一个MVP+RxJava+Retrofit的干货集中营

欢迎掘金的小伙伴们访问个人博客网站,原文连接:wensibo.top/2017/05/15/… ,未经容许不得转载!java

今天想要与你们一块儿分享的五月份的时候用一个星期开发的一个app——干货集中营客户端,由于已经得到了掘金的专栏因此就把以前的文章发不上来与你们一块儿分享。
其实网上已经有许多相似的项目,代码家也在他的干货集中营中推荐了几款优秀的做品,我也借鉴了其中的一些,本身开发出一款干货集中营客户端,目前项目已经发布到github,若是你想了解整个工程的具体内容,那么你能够fork或者clone,若是你以为我作得还能够,那么请你赐给我一个star呗!你的支持会是我努力的动力。android

前言

慢慢的已经养成了每篇文章都会来一个前言,也慢慢地将写文章潜移默化的转变成写故事,因此每一个故事都会有前言,也都会有结果,此次也不例外。
距离上篇引发热烈反响的文章发布已通过去一个月了,承蒙广大网友对个人支持以及建议,固然做为一个90后,我也很虚心的接受来自各方的吐槽,毕竟我并不优秀,只是一直在优秀的路上努力的奔跑着。下面我想跟你们一块儿分享一下这一个月里我作了些什么事,以及接下来一段时间的计划和打算。git

Have Done List

  • 持续22天在github上出现,看看下面这棵贡献树
    contributions
    contributions
  • 博客浏览量突破35000
    blog
    blog
  • 看了1本好书——《网络是怎样链接的》
  • 研究Retrofit与RxJava的源码(待我葡萄成熟时再把文章放出来吧,如今太嫩了,很差意思让你们看到)
  • 2次担任演讲的主讲人(以后会写一篇文章讲述个人演讲技巧)
  • 看了锤子科技新品发布会(我是罗粉但也是加油,心疼老罗一秒)
  • 努力寻找实习(投了许多简历,可是无一幸免:sob: ,有同窗能够推荐一波吗?没有的话我待会再问问)
  • 1个全新的干货集中营客户端app(也是写这篇文章的原因)

Todo List

  • xposed插件开发(这个闪念是有一天夜里惊醒过来的想法)
  • 继续写好的文章与你们一块儿分享,不只仅是技术方面的,还有许多我以为有用的文章,都会为你们奉上,感谢老铁们的支持
  • 继续看书
  • 继续找实习(呜呜呜~~(>_<)~~,体会到工做难找了,尤为是互联网寒冬)

老铁别废话了
老铁别废话了

好啦,上面讲了一大堆废话终于能够进入正题了,我也很基动,开车咯!

项目介绍

logo
logo

GankClient(又称干货集中营客户端)是一个全新的干货集中营客户端,它获取的是来自 干货集中营API的数据,利用全新的Material Design的设计语言展现数据内容。整个项目采用MVP的设计架构,而且大量使用RxJava2,网络框架使用的是Retrofit。我用下面几个装逼的句子来形容一下这个APP:

  • 更快速的加载速度
  • 更流畅的页面体验
  • 更有趣的刷新效果
  • 更精美的网页浏览
  • 更美观的视觉享受

这个只是个人我的感觉,大神请轻喷:joy: ,不过仍是但愿你们可以喜欢这个项目,而且积极的向我pull request以及反馈bug,但愿你们多多支持。若是能够的话给个star咯。 github

预览

谁说不给图的
谁说不给图的

所有效果图来一发

screenshot
screenshot
screenshot
screenshot
screenshot
screenshot

screenshot
screenshot
screenshot
screenshot
screenshot
screenshot

没有gif图都很差意思说话了

gif
gif

下载

酷安基佬群

若是你使用酷安的话,那就使劲点这里,或者在酷安搜索干货集中营,认准个人图标哦
web

干货集中营
干货集中营

fir.im

若是你没有安装酷安,那么你能够扫描下方的二维码进行下载
chrome

QRCode
QRCode

测试

若是你想测试这个项目,那么请手动clone数据库

功能&特点

√表示已经实现的功能,X表示的的是还没实现或者须要完善的功能。(吐槽一下,掘金的MarkDown编辑器仍是没有实现一些基本的语法,例如打勾勾) 编程

√实时获取服务器的最新数据,采用CardView的布局以更好的展示数据。
√刷新效果很好玩,真的很精致,感谢Phoenix
√若是你装有Chrome浏览器,并将其设置为默认浏览器,那么你的网页浏览效果就会十分酷炫。感谢Custom-Tabs-Client ! 墙裂推荐Chrome,若是你没有安装Chrome,那也不要紧,那就用传统的WebView吧!
√更加统一的过渡动画,相信你会爱上它。
√保存、分享图片与连接,也能够直接使用浏览器打开连接。
√更好看的Material Design设计风格。
√妹子很漂亮哟! api


X优化webview的视频播放。
X增长使用系统浏览器的选项。
X修复在主界面中加载数据到2016/4/20左右时数据显示错乱的问题。
X加强分享功能。 浏览器

分解

终于到了这个纯干货步骤了,别说话先看东西!

如何使用MVP的设计架构

我先展现如下这个项目的结构图,让你们内心有个底

  • http
    • GankRetrofit.java
    • GankRetrofitClient.java
  • mvp
    • model
      • BaseModel.java
    • presenter
      • BasePresenter.java
    • view
      • IBaseView.java
  • ui
    • activity
    • adapter
    • base
    • chromeviews
    • fragment
    • widget

能够看到,整个项目的结构还算比较清晰,总体的架构都是在mvp目录中定下来的,mvp架构分三层,model模型层,用于定义一些数据的类型;presenter呈现者层,用于处理view层的逻辑;view显示层,这里定义的都是接口,真正实现他们的是activity,这些activity只要实现相应的接口,就可以本身复写其中的方法。
固然我这么说你确定仍是一脸懵逼,并且我还必须跟你说,我这个不算最纯粹的MVP模式,最纯粹的写法应该都是面向接口编程的,就是在model,presenter,以及view下都是定义接口,而到了具体的运用场景,就定义出具体的类去实现这些接口。固然了,为了让你们可以更清楚MVP是怎么实现的,下面我会用代码的形式为你们展现,例如我要编写MainActivity的代码,首先已经知道在这个Activity中须要作以下这些事:

  • 初始化组件
  • 加载Fragment
  • FloatingActionButton的点击事件——去到DailyActivity
  • drawer menu的点击事件——去到AboutActivity

为了让Activity专一于界面的工做,而不用去考虑逻辑处理的操做,这个就是所谓的解耦,那么咱们能够将逻辑的操做放到presenter中去,而与界面有关的操做就放在view下,因而咱们就能够这样写(为了便于你们理解,我将项目中的代码作了适当的修改,若是你想了解更加具体的逻辑,能够仔细看看代码):

  • IBaseView
public interface IBaseView {
        //界面初始化操做
        void init();
}复制代码
  • BasePresenter&MainPresenter
/** * 将presenter的公共操做集成为BasePresenter */
public abstract class BasePresenter <T extends IBaseView>{
        protected Disposable disposable;
        protected Context context;
        protected T iView;      //获取到view的对象

        public BasePresenter(Context context, T iView) {
                this.context = context;
                this.iView = iView;
        }

        public void init() {
                iView.init();
        }

        public abstract void release();
        public abstract void initPresenter();
}

/** * 每个界面均可以编写本身的Presenter,并指定View的泛型 */
public class MainPresenter extends BasePresenter<IBaseView> {

        public MainPresenter(Context context, IBaseView iView) {
                super(context, iView);
        }

        @Override
        public void release() {

        }

        public void toDailyActivity() {
                Intent intent = new Intent(context, DailyActivity.class);
                context.startActivity(intent);
        }

        public void toAboutActivity() {
                Intent intent = new Intent(context, AboutActivity.class);
                context.startActivity(intent);
        }

        public void toSettingActivity() {
                Intent intent = new Intent(context, SettingActivity.class);
                context.startActivity(intent);
        }复制代码
  • MainActivity
public class MainActivity <MainPresenter> extends AppCompatActivity implements IBaseView{

        @OnClick(R.id.fab_main)
        void fabClick() {
                presenter.toDailyActivity();
        }

        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        }


        @Override
        protected void initPresenter() {
                presenter = new MainPresenter(this, this);
                presenter.init();
        }

        @Override
        public void init() {
                //全部的初始化操做
        }

        @Override
        protected void onDestroy() {
                super.onDestroy();
                presenter.release();
        }

}复制代码

大概就是这样一个套路,讲真我这样讲你确定迷糊,我当初在学这个的时候也是十分凌乱,后来才发现只有本身动手亲自敲代码才能了解整个思路,另外你们在学习MVP的过程当中应该擅于画图,无论是在纸上画仍是使用思惟导图都行,这样可让你更加宏观的了解整个调用的顺序以及各个类之间的关系,这毫不是你看了一篇文章就能懂的。

你真的用好RxJava了吗

当我问这个问题的时候,其实我想说的是RxJava的用处很广,咱们想固然的认为只要RxJava与Retrofit相配合就算是完成任务了,但实际上只要涉及到耗时操做、线程切换:网络请求、图片解析、数据库读取等等须要用多个线程一块儿完成的工做时,你均可以用到RxJava,而且若是你还一直用RxJava1的话,那么你也OUT啦,当你认识RxJava2.x的时候你会发现他更强大了。关于RxJava,我后续会写相关的文章与你们一块儿分享,这里我举项目中遇到的一个例子,看看RxJava的用武之地是多么的广:

/** * 将图片保存在本地 */
public void openWebView(final Gank gank) {
    disposable=Observable.create(new ObservableOnSubscribe() {
            @Override
            public void subscribe(@NonNull ObservableEmitter e) throws Exception {
                    e.onNext(android.R.drawable.ic_menu_share);
            }
    }).subscribeOn(Schedulers.newThread())//开启一个新线程来进行耗时操做
            .map(new Function<Integer, Bitmap>() {
                    @Override
                    public Bitmap apply(@NonNull Integer integer) throws Exception {
                            //将资源id解析为bitmap是一个耗时操做
                            return BitmapFactory.decodeResource(activity.getResources(), integer);
                    }
            }).observeOn(AndroidSchedulers.mainThread())//回到主线程操做bitmap
            .subscribe(new Consumer<Bitmap>() {
                    @Override
                    public void accept(@NonNull Bitmap bitmap) throws Exception {
                            //拿到bitmap以后作的界面更新
                    }
            });
}

//释放资源
public void release() {
                if (disposable != null&&!disposable.isDisposed()) {
                        disposable.dispose();
                }
        }复制代码

爽快的Retrofit

还记得以前我写过Volley的一系列文章,虽然以为这个开源框架已经不错了,但毕竟长江后浪推前浪,在Retrofit的面前,Volley简直就是小巫见大巫,看看咱们应该如何在项目中使用:

  • 一、新建一个接口,用注解的形式在里面定义网络请求的方法:
public interface GankRetrofit {
        //获取MainActivity界面的数据,具体的请求路径应该详细看官方的API说明,
        // Retrofit与RxJava配合以后才能显示出更强的威力
        @GET("data/{type}/40/{page}")
        Observable<MainData> getMainData(@Path("type") String type, @Path("page") int page);
}复制代码
  • 二、得到实例:
Gson date_gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").create();
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://gank.io/api/")         //指定服务器地址
        .addConverterFactory(GsonConverterFactory.create(date_gson))    //添加一个gson的解析器
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())          // 若是想使用RxJava那就须要添加这个适配器 
        .build();
GankRetrofit gankRetrofit;
gankRetrofit = retrofit.create(GankRetrofit.class);            //获取GankRetrofit的对象复制代码
  • 三、获取数据:
//返回的Observable<MainData>对象就可使用RxJava进行解析了
gankRetrofit.getMainData("Android",40);复制代码

更好的网页浏览体验——Custom-Tabs-Client

若是你使用过Chrome浏览器,那么你应该会喜欢上它,当咱们在使用webview开发的时候,会发现webview存在许多的限制,而且开发者对webview不能彻底控制,因而Chrome团队为了解决开发者的这些问题,就设计出这个开源库,只要用户手机上安装Chrome而且设置为默认浏览器,那么打开网页连接的时候就会看到以下的画面:

custom-tabs-client
custom-tabs-client

是的!如此酷炫的画面是用到了Chrome浏览器的内核,而且读取Chrome的cookie,例如若是你在Chrome已经登陆过github了,那么经过这个库打开的github连接一样也显示你已经登陆了github。固然除了页面效果十分好以外,咱们还能够自定义许多东西,例如 过渡动画ToolBar上方的ActionButton等等,个人项目中也已经实现了这两个功能。接下来我带你们一块儿看看最简单的实例应该怎么编写:

CustomTabsIntent.Builder customTabsIntent;
 customTabsIntent = new CustomTabsIntent.Builder();     //获取到CustomTabsIntent实例
 //一系列的设置
customTabsIntent.setToolbarColor(activity.getResources().getColor(R.color.colorPrimaryDark));   //设置ToolBar的颜色
customTabsIntent.setShowTitle(true);    //设置是否显示网页的标题
customTabsIntent.setStartAnimations(activity, R.anim.slide_in_right, R.anim.slide_out_left);    //设置进入的动画
customTabsIntent.setExitAnimations(activity, R.anim.slide_in_left,R.anim.slide_out_right);      //设置退出的动画
//开启网页
CustomTabActivityHelper.openCustomTab(
    activity,       //当前的activity
    customTabsIntent.build(),
    view,
    gank,   //gank带有要打开的网页的url
    new CustomFallback() { //若是用户没有安装Chrome并将其设置为默认浏览器的话,应该作这样的处理
            @Override
            public void openUri(Activity activity, View view,Gank gank) {
                    Log.d("Gank", gank.toString());
                    super.openUri(activity, view,gank);
            }
    });复制代码

以上就是想要跟你们一块儿分享的关于这个项目中一些重要的点,可能有些地方讲得并不那么清楚,但我以为只有实践才能出真知,因此老哥仍是乖乖打开AS撸撸代码啦!

版本控制

目前app的版本为V1.0.0,我会用下面的时间表记录版本的迭代,若是有更新的版本,我会及时更新这个表格。

Version Date
V1.0.0 2017/5/14

致谢

做为一名Android开发者,咱们都应该具备像罗老师同样感激开源世界的情怀,而咱们如今能作的就是一样为开源世界作贡献,不管是写文章亦或是写程序,记得都要时刻保持一颗感恩的心。很是感谢代码家以及他的干活集中营,也很是感谢许多前辈们作过的干活集中营app。

后记

最近一个月,感受本身身体被掏空,吐槽学校对咱们专业的课程安排如此不合理,天天上那些本身不感兴趣的课程确实很无趣,可是生活再难也要感激它,只有经过本身的双手去努力,未来的你才会为如今的本身喝彩骄傲。下篇文章再见!

相关文章
相关标签/搜索