1、深入浅出RxJava(一:基础篇) - 大头鬼Bruce - 博客频道 - CSDN.NET
2、RxJava教程
3、RxJava的Demo
4、Rxjava-Android资料汇总(里面有一些推荐的相关跳转网址,很有用的)
5、给 Android 开发者的 RxJava 详解(这个呢,是很多人推荐的,我是第一次看,没懂,看了别的后,回看,懂了一部分,再次回看,基本明白)
6、老罗的Android视频第二季里的其中一个,RxJava(百度搜一下,有地方下的,我那个网址链接找不到了,抱歉)
7、Retrofit官网(纯英文,当时我完全看不懂,也没足够的时间猜词,哈哈哈哈)
8、快速Android开发系列网络篇之Retrofit
9、Retrofit的使用教程(一)
10、android retrofit视频(Retrofit的视频蛮多的,比较好找,建议网上看视频学习学习基本的)
11、Android MVP 详解(上)
12、Android App的设计架构:MVC,MVP,MVVM与架构经验谈
13、ANDROID MVP 模式 简单易懂的介绍方式
14、详解Dagger2(注解框架)
15、聊聊 Android 中的依赖注入 - 安卓 - 伯乐在线
16、Dagger——Android上的依赖注入框架
17、Dagger2图文完全教程
18、最简单的Dagger2入门教程
19、Dagger2
20、Dagger2相关网址
21、Dagger2 这次入门就不用放弃了 - _王剑锋 - 博客频道 - CSDN.NET
22、Google官方架构MVP解析与实战 - OPEN 开发经验库
23、Google 官方架构 MVP+Dagger2 架构详解 - 掘金
24、Google官方MVP下载(包括+RxJava和+Dagger2de1)
25、Google官方MVP+Dagger2架构详解【从零开始搭建android框架系列(6)】(这位作者另一篇文章对MVP的理解写的也很棒,你可以找一下,系列里的其他几个)
好了,归于正题,我现在要开始讲了。我做的就是一个上拉加载,下拉刷新的recyclerview的加载数据和点击跳转详情页面的例子。
首先看一下文件目录。
xyrecyclerview包是直接import Module进来的,不用手写。
adapter包,就放了xyrecyclerview的adapter,加载器
api包是服务访问,里面是Retrofit2写的。
bean包是新闻信息的实例类,你在模仿时,直接copy就好了
shownewdetail包新闻细节显示页面(包括了Dagger2、MVP、RxJava的使用)
shownewslist包新闻列表显示页面(包括了Dagger2、MVP、RxJava的使用)
utils包一个功能包,就是webView的一些数据处理的,不用管,直接copy。
其他几个class文件后面一一讲解。
如下讲解,全是个人理解,错了别打我。
首先,要新建一个class,用来继承Application,我的是MyApplication。里面有ApplicationComponent applicationComponent。我讲解一下,代码的写的顺序。
- package zjl.com.dagger_mvp_rxjava_demo2;
-
- import android.app.Application;
- import android.content.Context;
-
-
-
-
- public class MyApplication extends Application {
-
- private ApplicationComponent applicationComponent;
-
- public static MyApplication get(Context context){
- return (MyApplication) context.getApplicationContext();
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- setGraph();
- }
-
- private void setGraph() {
- applicationComponent = DaggerApplicationComponent.builder().applicationModule(new ApplicationModule(this)).build();
- applicationComponent.inject(this);
- }
-
- public ApplicationComponent component(){return applicationComponent;}
- }
写的顺序是什么呢,先是继承Application,然后,我要重写onCreate()方法,自定义个方法,setGraph()。用来添加注入器。为什么我要写这个MyApplication呢。因为啊,我是需要某些变量啊、获取几个服务啊,等等的。这些我是在想通过Dagger2来实现简化的想法上,所准备添加的。(我试过,不写,也没关系)。
为了说明效果,我写了给注入器Component用的,注入类ApplicationModule,用来提供Context。
- package zjl.com.dagger_mvp_rxjava_demo2;
-
- import android.content.Context;
-
- import dagger.Module;
- import dagger.Provides;
-
-
-
-
- @Module
- public class ApplicationModule {
- private Context context;
- public ApplicationModule(Context context){
- this.context = context;
- }
-
- @Provides
- public Context provideContext(){
- return context;
- }
- }
@Module符号是给Component识别用的,让他找得到。我想提供一个Context对象用(最终目的是为了new 一个Context对象出来嘛),所以就是@Provides下面这段代码,return一个Context对象,这个对象值怎么来,ApplicationModule的构造方法里获取。@Provides是一个识别的符号,告诉别人,用下面的这个方法提供某类对象。
再写一个ApplicationComponent,即注入器。是一个工具。
- package zjl.com.dagger_mvp_rxjava_demo2;
-
- import dagger.Component;
-
-
-
-
- @Component(modules = {ApplicationModule.class})
- public interface ApplicationComponent {
-
- void inject(MyApplication myApplication);
- }
@Component(modules = {ApplicationModule.class})表示如在MyApplicationzhon中我需要一个Context对象时,可以通过ApplicationComponent的@Component里的某个class中,找到某个@Provides提供相应需要的对象。
- void inject(MyApplication myApplication);
是表示我要提供给谁。比如说:我买本书,Modules是书,Component是卖书的人,@Inject的对象是我。书通过卖书的人的手,到我的手上。回过去看MyApplication,通过DaggerApplicationComponent.builder().applicationModule(new ApplicationModule(this)).build()获取Component对象,并用inject(this)注入。如果以后需要用到某个类对象,就可以通过Application获得。component()方法,就是调用该ApplicationComponent对象。以后会说到,哪里被用到。
然后,是以MVP的框架来写的。那么写个BaseView、BasePresenter、BaseActivity作为基类,用于写具体的类里必定会调用的方法。
BaseView
- <span style="font-size:10px;">package zjl.com.dagger_mvp_rxjava_demo2;
-
-
-
-
- public interface BaseView {
-
-
- }</span><span style="font-size:12px;font-weight: bold;">
- </span>
因为我的Demo没有需要的必定会用的方法,所以不用写。
BasePresenter
- <span style="font-size:12px;">package zjl.com.dagger_mvp_rxjava_demo2;
-
- import android.support.annotation.NonNull;
-
-
-
-
- public interface BasePresenter<T extends BaseView> {
-
- void attachView(@NonNull T view);
-
- void detachView();
- }<strong>
- </strong></span>
用于绑定的,防止内存泄漏哦。
BaseActivity
- <span style="font-size:12px;">package zjl.com.dagger_mvp_rxjava_demo2;
-
-
- import android.os.Bundle;
- import android.support.annotation.Nullable;
- import android.support.v7.app.AppCompatActivity;
-
-
-
-
- public abstract class BaseActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(initContentView());
- setupComponent((ApplicationComponent) MyApplication.get(this).component());
- initUi();
- initDatas();
- initListener();
- onclick();
- }
-
- protected abstract void initUi();
-
- protected abstract void initDatas();
-
- protected abstract void initListener();
-
- protected abstract void onclick();
-
- protected abstract void setupComponent(ApplicationComponent component);
-
- public abstract int initContentView();
-
- }</span><strong style="font-size:12px;">
- </strong>
写了一些抽象方法,系统一点。
下面开始重点区域部分。
api包,里就两个文件,ApiManagerService里用于写接口,ApiManager实现接口的调用。
来看代码:
先看ApiManagerService
- package zjl.com.dagger_mvp_rxjava_demo2.api;
-
-
-
- /**
- * Created by dell on 2016/8/10.
- */
-
- import retrofit2.http.GET;
- import retrofit2.http.Path;
- import rx.Observable;
- import zjl.com.dagger_mvp_rxjava_demo2.bean.NewsDetail;
- import zjl.com.dagger_mvp_rxjava_demo2.bean.NewsList;
-
- /**
- * @className:ApiManagerService
- * Created by lidong on 2016/3/2.
- */
- public interface ApiManagerService {
- @GET("stories/latest")
- Observable<NewsList> getLatestNews();
-
- @GET("stories/before/{date}")
- Observable<NewsList> getBeforeNews(@Path("date") String date);
-
- @GET("story/{id}")
- Observable<NewsDetail> getNewsDetail(@Path("id") int id);
-
- }
根据接口,获取服务,@GET注释,里面写接口的。注意,开头没有“/”的,看getNewsDetail,里,id的@GET为什么有{}呢?因为,他是会变,由参数@Path("id") int id的id值来决定的哦。
再看ApiManager
- package zjl.com.dagger_mvp_rxjava_demo2.api;
-
- import retrofit2.Retrofit;
- import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
- import retrofit2.converter.gson.GsonConverterFactory;
- import rx.Observable;
- import zjl.com.dagger_mvp_rxjava_demo2.bean.NewsDetail;
- import zjl.com.dagger_mvp_rxjava_demo2.bean.NewsList;
-
-
-
-
- public class ApiManager {
-
-
-
- private static final Retrofit sRetrofit = new Retrofit.Builder()
- .baseUrl("http://news-at.zhihu.com/api/4/")
- .addConverterFactory(GsonConverterFactory.create())
- .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
- .build();
-
- private static final ApiManagerService apiManager = sRetrofit.create(ApiManagerService.class);
-
- public static Observable<NewsList> getLatestNews(){
- return apiManager.getLatestNews();
- }
-
- public static Observable<NewsList> getBeforeNews(String date){
- return apiManager.getBeforeNews(date);
- }
-
- public static Observable<NewsDetail> getNewsDetail(int id) {
- return apiManager.getNewsDetail(id);
- }
-
-
-
- }
创建sRetrofit对象,以Gson对json数据解析,使用RxJava进行回调,baseUrl里写主要的不变的总接口地址(注意,结尾必须是"/"作为结尾的哦!!!)
通过Retrofit.create(ApiManagerService.class)获取服务(这都是套路啦)
自己写的静态方法,用户获取相应接口给的数据getLatestNews()、 getBeforeNews(String date)、 getNewsDetail(int id)。
这个比较基础的,如果要用的更复杂,可以加什么@header这些,那个要更深层的学习了。
然后是shownewslist包和shownewdetail包这两个包写法相同。我先按代码编写顺序讲,先是shownewslist包。
ShowNewsListActivity里调用ShowNewsListPresenter,与其关联。ShowNewsListActivity继承了ShowNewsListContract的View接口,ShowNewsListPresenter继承了ShowNewsListContract的Presenter接口。showNewsListModel从ApiManager中获取数据。并提供给ShowNewsListPresenter进行数据处理,再将对应的结果在用ShowNewsListActivity的方法进行显示。ShowNewsListPresenterComponent是ShowNewsListPresenter的注入器,ShowNewsListModule是注入类。
来看代码:
ShowNewsListActivity
按顺序来吧。
initContentView()绑定xml,R.layout.activity_main。
我要创建ShowNewsListPresenter对象,并与其关联。通过Dagger2简化、实现解耦。setupComponent(ApplicationComponent component)方法。
当然,注入对象,就要写Component,要不要写Module呢?这个要看情况的,当提供的对象是第三方库的,要,不是的话,你可以选择用@Inject哦。我这里都有在代码里涉及。
从已写好的代码结果来返回去看,比较好理解。
先看四块代码,了解。
这里,我讲解的顺序有些不同,希望能看懂。一开始,我是一MVP的写法写,那必须要写Presenter,即ShowNewsListPresenter。我们先不看注入,
先看MVP。ShowNewsListPresenter是对数据进行处理,ShowNewsListModel是或取需要的数据,我这里写的是或取接口返回的数据的方法。为了不使系统发生可能的异常,采用异步的方式即RxJava,ShowNewsListModel里的方法,传的值的类型是Observable<T>。
ShowNewsListPresenter
ShowNewsListPresenter里哪里用到了RxJava呢?对RxJava有所了解的,很清楚的看出是在getBeforeNewsListData(String date) ,getNewsListData() ,getRefreshNewsListData()里。以getBeforeNewsListData(String date) 方法,为例。一句句说明干什么用。
mSubscription是什么?
- private Subscription mSubscription;
RxJava中有个叫做Subscription的接口,可以用来取消订阅.只需要调用unsubscribe就可以取消订阅,那么如何得到一个Subscription对象呢?
其实很简单:
Observable.subscribe()方法可以返回一个Subscription的对象,即我们每次订阅都会返回.
感觉Subscription就像一个订单,你下单了就会生成一个订单,而你也可以用这个订单取消订单。
- showNewsListModel.getLatestNews()
调用showNewsListModel的getLatestNews()方法向接口获取数据。
- .subscribeOn(Schedulers.io())
获取数据这一步是开启新线程,在新线程里执行。
- .observeOn(AndroidSchedulers.mainThread())
对接口返回的数据的处理,是在主线程执行。
- .subscribe(new Action1<NewsList>() {
- @Override
- public void call(NewsList newsList) {
- for (int z = 0; z < newsList.getStories().size(); z++) {
- listdata.add(newsList.getStories().get(z));
- }
- view.load(listdata);
- }
- }, new Action1<Throwable>() {
- @Override
- public void call(Throwable throwable) {
- System.out.println("-------onFailure" + throwable.getMessage());
- }
- });
- }
对接口返回的数据的处理,在subscribe()方法中写,Action1<NewsList>方法里重写call(),这个是简化了写法,替代了,onNext()、onError()、onComplete()方法。
重写call()方法,代码里用for循环遍历list,是为了处理数据,再通过
方法,调用ShowNewsListActivity里的load(ArrayList<News> list)方法,对V进行UI对应更改。
然后是attachView(@NonNull ShowNewsListContract.View view)、detachView()方法,这两个方法是什么用的呢?是为了防止内存泄漏的哦。当Activity结束时,要同时结束Presenter,防止,重新使用Activity时,上个Presenter还未结束。所以要将Presenter绑定到Activity,随着Activity销毁,OnDestory()而结束。
ShowNewsListModel
- package zjl.com.dagger_mvp_rxjava_demo2.shownewslist;
-
-
- import javax.inject.Inject;
-
- import rx.Observable;
- import zjl.com.dagger_mvp_rxjava_demo2.api.ApiManager;
- import zjl.com.dagger_mvp_rxjava_demo2.bean.NewsList;
-
-
-
-
-
- public class ShowNewsListModel {
-
- @Inject
- public ShowNewsListModel(){}
-
- Observable<NewsList> getLatestNews(){
- return ApiManager.getLatestNews();
- }
-
- Observable<NewsList> getBeforeNews(String date){
- return ApiManager.getBeforeNews(date);
- }
- }
对MVP有了解的,知道。V接收用户的指令,调用P,P有必要时,就向M获取数据,M将获取的数据再给P,P处理后,反馈给V中去显示。(这是我理解的MVP)。我们回看ShowNewsListActivity,看看哪里调用了P。
在initDatas()方法中,初始化数据。
- @Override
- protected void initDatas() {
- newsListAdapter = new NewsListAdapter(this, listData);
- mxRecyclerView.setAdapter(newsListAdapter);
-
- showNewsListPresenter.attachView(this);
- showNewsListPresenter.getNewsListData();
- }
在这里就执行了
- showNewsListPresenter.attachView(this);
将Presenter绑定Activity,
- showNewsListPresenter.getNewsListData();
这句话,就调用了P,让ShowNewsListPresenter调用相应的方法去获取新闻数据。
这样MVP的使用应该能理解吗?(我第一次写,不是很会讲,没看懂,真是对不起了。)
接下来我讲Dagger2的使用。
ShowNewsListActivity要让ShowNewsListPresenter调用方法,就需要对ShowNewsListPresenter实例化。为了解耦,避免ShowNewsListPresenter有改动,导致ShowNewsListActivity也要随之改动,所以,用Dagger2实现注入。
既然要实现注入,Component必不可少。所以就有了ShowNewsListPresenterComponent。
看代码:
ShowNewsListPresenterComponent
- package zjl.com.dagger_mvp_rxjava_demo2.shownewslist;
-
-
- import dagger.Component;
- import zjl.com.dagger_mvp_rxjava_demo2.ApplicationComponent;
-
-
-
-
- @Component(dependencies = ApplicationComponent.class,modules = ShowNewsListModule.class)
- public interface ShowNewsListPresenterComponent {
- void inject(ShowNewsListActivity showNewsListActivity);
- }
我这里void inject(ShowNewsListActivity showNewsListActivity);是表明要注入到ShowNewsListActivity中。看代码里有一句
- @Component(dependencies = ApplicationComponent.class,modules = ShowNewsListModule.class)
依赖上层的Component,实例化ShowNewsPresenter时需要Module,ShowNewsListModule中提供的某些对象。而其实,我这里并未用到ShowNewsListModule.class,只是演示一下Module怎么写。在NewDetailPresenterComponent中我特意写成需要用到的,到时候看一下。
ShowNewsListModule
- package zjl.com.dagger_mvp_rxjava_demo2.shownewslist;
-
- import dagger.Module;
- import dagger.Provides;
-
-
-
-
- @Module
- public class ShowNewsListModule {
-
- private final ShowNewsListContract.View view;
- public ShowNewsListModule(ShowNewsListContract.View view){
- this.view = view;
- }
- }
看ShowNewsListPresenter中有
- @Inject
- public ShowNewsListPresenter() {
-
- }
@Inject是识别的,ShowNewsListActivity中需要一个ShowNewsListPresenter对象,通过Component去找哪里有对应的对象生成,发现,ShowNewsListPresenter的构造方法上有一个 @Inject符号,就找到这个对象,自动实例化,其中还需要一个ShowNewsListModel对象,同样用@Inject注入,ShowNewsListPresenterComponent会自动去查找哪里有提供对象,会在ShowNewsListModel的构造方法中,找到,最终生成了ShowNewsListPresenter对象。
回来再看,ShowNewsListActivity,需要实例化Component,进一步注入对象,这个时候,就要重写setupComponent(ApplicationComponent component)方法。
- @Override
- protected void setupComponent(ApplicationComponent component) {
- DaggerShowNewsListPresenterComponent.builder().applicationComponent(component).showNewsListModule(new ShowNewsListModule(this)).build().inject(this);
- }
首先在ShowNewsListPresenterComponent和ShowNewsListModule写好后,需要rebuild一下项目,自动生成DaggerShowNewsListPresenterComponent文件,在进一步实例化,依赖的Component和Module,最后注入进Activity。
OK,ShowNewsListPresenter注入成功。
那Module怎么使用呢,我的ShowNewsListModule没有被使用,所以我特地写了个会被使用的。请看shownewdetail包,MVP的写法相同,我就不写了,我讲一下Dagger2注入。
NewDetailPresenterComponent写法相同。
- package zjl.com.dagger_mvp_rxjava_demo2.shownewdetial;
-
-
- import dagger.Component;
- import zjl.com.dagger_mvp_rxjava_demo2.ApplicationComponent;
-
-
-
-
- @Component(dependencies = ApplicationComponent.class,
- modules = NewDetailModule.class)
- public interface NewDetailPresenterComponent {
- void inject(NewDetailActivity newDetailActivity);
- }
NewDetailPresenter的构造方法和ShowNewsListPresenter的有些不同,有参数。
NewDetailPresenterComponent会自动去找提供对象的方法,找到了NewDetailModule。
- package zjl.com.dagger_mvp_rxjava_demo2.shownewdetial;
-
- import dagger.Module;
- import dagger.Provides;
- import zjl.com.dagger_mvp_rxjava_demo2.shownewslist.ShowNewsListContract;
-
-
-
-
- @Module
- public class NewDetailModule {
- private final NewDetailContract.View view;
- private int id;
- public NewDetailModule(NewDetailContract.View view,int id){
- this.view = view;
- this.id = id;
- }
-
- @Provides
- public int provideid(){
- return id;
- }
- }
provideid()方法,提供了参数int id。
在NewDetailActivity里setupComponent(ApplicationComponent component)方法中,对NewDetailModule的实例化时,需要传递进一个int型参数,就是用于实例化NewDetailPresenter的。
- @Override
- protected void setupComponent(ApplicationComponent component) {
- DaggerNewDetailPresenterComponent.builder().applicationComponent(component).newDetailModule(new NewDetailModule(this, getIntent().getIntExtra("new", 0))).build().inject(this);
- }
综上,例子就写完了。希望对大家能有一丢丢的帮助。首次写博客,写的不好请见谅。
项目地址