RXjava+Retrofit+dagger2打造自己的MVP框架

RXjava+Retrofit+dagger的入门

        前言:现在RXjava+Retrofit+dagger可谓是如日中天,当时头一次接触都有一种无从入手的感觉,那么我来分享一下我的学习方式。将RXjava Retrofit dagger分开来学 最后整合到一起


RXjava篇

相信各位看官对RxJava早有耳闻,那么关于什么是RxJava我就不再赘述了,不知道的可自行百度。如果你已经大致了解过什么是RxJava,想开始学习,那么本文不失为你良好的选择,为什么这么说呢,因为我也是刚学几天,正所谓“知己知彼,百战不殆”。网上流传,RxJava的入门门槛高,而经过我这几天的学习,我反而不那么认为,精通我不敢说,但入门确实也不难,不信?我先来个简单的例子预热一下。

先创建个数据发射源,很好理解,就是发射数据用的:

   Observable<String> sender = Observable.create(new Observable.OnSubscribe<String>() {

           @Override
            public void call(Subscriber<? super String> subscriber) {

                subscriber.onNext("Hi,Weavey!");  //发送数据"Hi,Weavey!"
            }
        });

再创建个数据接收源,同理,接收数据用的:

   Observer<String> receiver = new Observer<String>() {

            @Override
            public void onCompleted() {

                //数据接收完成时调用
            }

            @Override
            public void onError(Throwable e) {

                //发生错误调用
            }

            @Override
            public void onNext(String s) {

               //正常接收数据调用
                System.out.print(s);  //将接收到来自sender的问候"Hi,Weavey!"
            }
        };

好了,将发射源和接收源关联起来:

  sender.subscribe(receiver);

这样就形成RxJava一个简单的用法,sender发射"Hi,Weavey!",将会被receiver的onNext的接收,通过这个例子,也许你会想到“异步”、“观察者模式”,没错,这些都是RxJava所做的事情,并且让他们变得更简单和简洁,而RxJava所有的一切都将围绕这两个点展开,一个是发射数据,一个是接收数据,是不是很通俗易懂?如果你理解了这点或者你已经知道RxJava就是这么一回事,那么恭喜你,你已经一只脚跨进RxJava的大门了,如果不是!!!!那也无所谓,请继续往下看...


论概念的重要性

网上关于RxJava的博文也有很多,我也看过许多,其中不乏有优秀的文章,但绝大部分文章都有一个共同点,就是侧重于讲RxJava中各种强大的操作符,而忽略了最基本的东西——概念,所以一开始我也看的一脸懵逼,看到后面又忘了前面的,脑子里全是问号,这个是什么,那个又是什么,这两个长得怎么那么像。举个不太恰当的例子,概念之于初学者,就像食物之于人,当你饿了,你会想吃面包、牛奶,那你为什么不去吃土呢,因为你知道面包牛奶是用来干嘛的,土是用来干嘛的。同理,前面已经说过,RxJava无非是发送数据与接收数据,那么什么是发射源,什么是接收源,这就是你应该明确的事,也是RxJava的入门条件之一,下面就依我个人理解,对发射源和接收源做个归类,以及RxJava中频繁出现的几个“单词”解释一通,说的不好还请海涵,欢迎补充。


基本概念

Observable:发射源,英文释义“可观察的”,在观察者模式中称为“被观察者”或“可观察对象”;

Observer:接收源,英文释义“观察者”,没错!就是观察者模式中的“观察者”,可接收Observable、Subject发射的数据;

Subject:Subject是一个比较特殊的对象,既可充当发射源,也可充当接收源,为避免初学者被混淆,本章将不对Subject做过多的解释和使用,重点放在Observable和Observer上,先把最基本方法的使用学会,后面再学其他的都不是什么问题;

Subscriber:“订阅者”,也是接收源,那它跟Observer有什么区别呢?Subscriber实现了Observer接口,比Observer多了一个最重要的方法unsubscribe( ),用来取消订阅,当你不再想接收数据了,可以调用unsubscribe( )方法停止接收,Observer 在subscribe() 过程中,最终也会被转换成 Subscriber 对象,一般情况下,建议使用Subscriber作为接收源;

Subscription :Observable调用subscribe( )方法返回的对象,同样有unsubscribe( )方法,可以用来取消订阅事件;

Action0:RxJava中的一个接口,它只有一个无参call()方法,且无返回值,同样还有Action1,Action2...Action9等,Action1封装了含有 1个参的call()方法,即call(T t),Action2封装了含有 2 个参数的call方法,即call(T1 t1,T2 t2),以此类推;

Func0:与Action0非常相似,也有call()方法,但是它是有返回值的,同样也有Func0、Func1...Func9;


基本用法

  • Observable的创建
    1.使用create( ),最基本的创建方式:

    normalObservable = Observable.create(new Observable.OnSubscribe<String>() {
      @Override
      public void call(Subscriber<? super String> subscriber) {
          subscriber.onNext("create1"); //发射一个"create1"的String
          subscriber.onNext("create2"); //发射一个"create2"的String
          subscriber.onCompleted();//发射完成,这种方法需要手动调用onCompleted,才会回调Observer的onCompleted方法
      }});

    2.使用just( ),将为你创建一个Observable并自动为你调用onNext( )发射数据:

    justObservable = Observable.just("just1","just2");//依次发送"just1""just2"

    3.使用from( ),遍历集合,发送每个item:

    List<String> list = new ArrayList<>();
    list.add("from1");
    list.add("from2");
    list.add("from3");
    fromObservable = Observable.from(list);  //遍历list 每次发送一个
    /** 注意,just()方法也可以传list,但是发送的是整个list对象,而from()发送的是list的一个item** /

    4.使用defer( ),有观察者订阅时才创建Observable,并且为每个观察者创建一个新的Observable:

    deferObservable = Observable.defer(new Func0<Observable<String>>() {
      @Override
      //注意此处的call方法没有Subscriber参数
      public Observable<String> call() {
          return Observable.just("deferObservable");
      }});

    5.使用interval( ),创建一个按固定时间间隔发射整数序列的Observable,可用作定时器:

    intervalObservable = Observable.interval(1, TimeUnit.SECONDS);//每隔一秒发送一次

    6.使用range( ),创建一个发射特定整数序列的Observable,第一个参数为起始值,第二个为发送的个数,如果为0则不发送,负数则抛异常:

    rangeObservable = Observable.range(10, 5);//将发送整数10,11,12,13,14

    7.使用timer( ),创建一个Observable,它在一个给定的延迟后发射一个特殊的值,等同于Android中Handler的postDelay( )方法:

    timeObservable = Observable.timer(3, TimeUnit.SECONDS);  //3秒后发射一个值

    8.使用repeat( ),创建一个重复发射特定数据的Observable:

    repeatObservable = Observable.just("repeatObservable").repeat(3);//重复发射3次
  • Observer的创建

    mObserver = new Observer<String>() {
      @Override
      public void onCompleted() {
          LogUtil.log("onCompleted");
      }
      @Override
      public void onError(Throwable e) {
      }
      @Override
      public void onNext(String s) {
          LogUtil.log(s);
      }};

    ok,有了Observable和Obsever,我们就可以随便玩了,任取一个已创建的Observable和Observer关联上,即形成一个RxJava的例子,如:

    justObservable.subscribe(mObserver);

    mObserver的onNext方法将会依次收到来自justObservable的数据"just1""just2",另外,如果你不在意数据是否接收完或者是否出现错误,即不需要Observer的onCompleted()onError()方法,可使用Action1subscribe()支持将Action1作为参数传入,RxJava将会调用它的call方法来接收数据,代码如下:

    justObservable.subscribe(new Action1<String>() {
        @Override
        public void call(String s) {
    
              LogUtil.log(s);
         }});

    以上就是RxJava最简单的用法。看到这里,我也不知道我写的是否简单明了,也许你会想,“哎呀,写个异步的东西,怎么这么麻烦,为什么不用Thread+Handler呢”,那你就错了,RxJava也以代码的简洁深受广大用户喜爱,简洁不能理解为代码量少,而是随着逻辑的复杂,需求的更改,代码可依然能保持极强的阅读性,举个简单的例子(前方高能预警~~~),领导要我从数据库的用户表查找出所有用户数据,我二话不说拿出心仪的RxJava就写:

         Observable.create(new Observable.OnSubscribe<List<User>>() {
              @Override
              public void call(Subscriber<? super List<User>> subscriber) {
                  List<User> userList = null;
                  ···
                  //从数据库获取用户表数据并赋给userList
                  ···
                  subscriber.onNext(userList);
              }
          }).subscribe(new Action1<List<User>>() {
              @Override
              public void call(List<User> users) {
    
                  //获取到用户信息列表
              }
          });

    但是,领导突然又不想要所有用户了,只要名字叫“小明”的用户,行吧,领导最大,我改(假设名字唯一):

        Observable.create(new Observable.OnSubscribe<List<User>>() {
              @Override
              public void call(Subscriber<? super List<User>> subscriber) {
                  List<User> userList = null;
                  ···
                  //从数据库获取用户表数据并赋给userList
                  ···
                  subscriber.onNext(userList);
              }
          }).flatMap(new Func1<List<User>, Observable<User>>() {
              @Override
              public Observable<User> call(List<User> users) {
                  return Observable.from(users);
              }
          }).filter(new Func1<User, Boolean>() {
              @Override
              public Boolean call(User user) {
                  return user.getName().equals("小明");
              }
          }).subscribe(new Action1<User>() {
              @Override
              public void call(User user) {
                  //拿到谜之小明的数据
              }
          });

    搞定,这时候领导又说,我不要小明了,我要小明的爸爸的数据,(坑爹啊~~),我继续改:

    Observable.create(new Observable.OnSubscribe<List<User>>() {
              @Override
              public void call(Subscriber<? super List<User>> subscriber) {
                  List<User> userList = null;
                  ···
                  //从数据库获取用户表数据并赋给userList
                  ···
                  subscriber.onNext(userList);
              } 
         }).flatMap(new Func1<List<User>, Observable<User>>() {
              @Override
              public Observable<User> call(List<User> users) {
                  return Observable.from(users);
              }
          }).filter(new Func1<User, Boolean>() {
              @Override
              public Boolean call(User user) {
                  return user.getName().equals("小明");
              }
          }).map(new Func1<User, User>() {
              @Override
              public User call(User user) { 
                  //根据小明的数据user从数据库查找出小明的父亲user2
                  return user2;
              }
          }).subscribe(new Action1<User>() {
              @Override
              public void call(User user2) {
                //拿到谜之小明的爸爸的数据
              }
          });

    搞定,“还想怎么改?领导请说···”。
    以上例子,涉及到几个操作符,初学者可能无法理解,但是无所谓,这不是重点,我的目的只是为了向你展示RxJava在需求不断变更、逻辑愈加复杂的情况下,依旧可以保持代码简洁、可阅读性强的一面,没有各种回调,也没有谜之缩进!



Retrofit篇

Retrofit与okhttp共同出自于Square公司,retrofit就是对okhttp做了一层封装。把网络请求都交给给了Okhttp,我们只需要通过简单的配置就能使用retrofit来进行网络请求了,其主要作者是Android大神JakeWharton


导包:

compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'//Retrofit2所需要的包
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'//ConverterFactory的Gson依赖包
compile 'com.squareup.retrofit2:converter-scalars:2.0.0-beta4'//ConverterFactory的String依赖包
* 这里需要值得注意的是导入的retrofit2包的 版本必须要一致 ,否则就会报错。


首先定义我们请求的Api,我们假设是这样的

http://106.3.227.33/pulamsi/mobileLogin/submit.html
与Okhttp不同的是,Retrofit需要定义一个接口,用来返回我们的Call对象,这里示范的是Post请求:

public interface RequestServes {
    @POST("mobileLogin/submit.html")
    Call<String> getString(@Query("loginname") String loginname,
                           @Query("nloginpwd") String nloginpwd);
}


Retrofit提供的请求方式注解有 @GET @POST ,参数注解有 @PATH @Query 等,我们只介绍常用的;前两个顾名思义就是定义你的请求方式 Get or Post ,后面的 @PATH 指的是通过参数填充完整的路径,一般用法:

@GET("{name}")
Call<User>
getUser(@Path("name") String name)
;

这里的参数username会被填充至{name}中,形成完整的Url请求地址,{name}相当于一个占位符;

@Query就是我们的请求的键值对的设置,我们构建Call对象的时候会传入此参数,

1
2
3
@POST("mobileLogin/submit.html")
   	Call<String> getString(@Query("loginname") String loginname,
                          @Query("nloginpwd") String nloginpwd);
这里 @Query("loginname") 就是键,后面的 loginname 就是具体的值了,值得注意的是Get和Post请求,都是这样填充参数的;


接口写完了之后我们需要来定义Retrofit对象来进行请求了;

创建一个Retrofit 对象

Retrofit retrofit = new Retrofit.Builder()
               .baseUrl("http://106.3.227.33/pulamsi/")
               //增加返回值为String的支持
               .addConverterFactory(ScalarsConverterFactory.create())
               //增加返回值为Gson的支持(以实体类返回)
               .addConverterFactory(GsonConverterFactory.create())
               //增加返回值为Oservable<T>的支持
               .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
               .build();

这里的baseUrl加上之前@POST("mobileLogin/submit.html")定义的参数形成完整的请求地址;

addConverterFactory(ScalarsConverterFactory.create())的意思是构建了一个返回支持,如果你的Call对象的泛型接收另外的格式需要添加另外的支持,上述代码已经列出;

接下来我们用这个Retrofit对象创建一个RequestSerives接口对象,也就是我们之前定义的那个接口,并且得到我们的Call对象;

 
RequestSerives requestSerives = retrofit.create(RequestSerives.class);//这里采用的是Java的动态代理模式
Call<String> call = requestSerives.getString("userName", "1234");//传入我们请求的键值对的值
利用得到的Call对象,然后我们就发出网络请求了:

 
 
call.enqueue(new Callback<String>() { @Override public void onResponse(Call<String> call, Response<String> response) { Log.e("===","return:"response.body().toString()); } @Override public void onFailure(Call<String> call, Throwable t) { Log.e("===","失败"); } });

导入Dagger2

使用Dagger2之前需要一些配置,该配置是在Android Studio中进行操作。

在工程的build.gradle文件中添加android-apt插件(该插件后面介绍)

buildscript {

    ....

    dependencies {

        classpath 'com.android.tools.build:gradle:2.1.0'
        // 添加android-apt 插件
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

在app的中的build.gradle文件中添加配置

apply plugin: 'com.android.application'
// 应用插件
apply plugin: 'com.neenbedankt.android-apt'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.mahao.alex.architecture"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}


dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.3.0'

    // dagger 2 的配置
    compile 'com.google.dagger:dagger:2.4'
    apt 'com.google.dagger:dagger-compiler:2.4'
    compile 'org.glassfish:javax.annotation:10.0-b28'// 添加java 注解库
}

以上两个配置就可以了。

android-aptGradle编译器的插件,根据其官方文档,主要两个目的:

  • 编译时使用该工具,最终打包时不会将该插件打入到apk中。

  • 能够根据设置的源路径,在编译时期生成相应代码。

在导入类库时,

    compile 'com.google.dagger:dagger:2.4'
    apt 'com.google.dagger:dagger-compiler:2.4'
   
   

    dagger是主要的工具类库。dagger-compiler为编译时期生成代码等相关的类库。

    android-apt的文档中,也推荐使用这种方式。因为,编译时期生成代码的类库在运行期并不需要,那么将其分为两个库,(运行类库dagger)和(编译器生成代码类库(dagger-compiler)),那么在打包时,就不需要将dagger-compiler打入其中(用不到),减小APK 的大小。

    Dagger2篇

    Dagger2的使用,需要大量的学习成本,不是很能够容易的上手并使用。该博客将从简单入手,尽可能的使用简单的例子演示Dagger2的功能。

    一个东西需要先会用,然后才更好的学习原理。该篇博客的目的主要是讲解如何使用。后面会有专门的分析源码的博客。

    在之前的分析中,通过Dagger2的目的是将程序分为三个部分。
    - 实例化部分:对象的实例化。类似于容器,将类的实例放在容器里。
    - 调用者:需要实例化对象的类。
    - 沟通桥梁:利用Dagger2中的一些API 将两者联系。

    先看实例化部分(容器),在此处是Module

    
    @Module   //提供依赖对象的实例
    public class MainModule {
    
        @Provides // 关键字,标明该方法提供依赖对象
        Person providerPerson(){
            //提供Person对象
            return new Person();
        }
    
    
    }
    

    沟通部分Component

    @Component(modules = MainModule.class)  // 作为桥梁,沟通调用者和依赖对象库
    public interface MainComponent {
    
        //定义注入的方法
        void inject(MainActivity activity);
    
    }
       
       

      使用者Actvity中调用。

      public class MainActivity extends AppCompatActivity{
      
          @Inject   //标明需要注入的对象
          Person person;
      
          @Override
          protected void onCreate(@Nullable Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
      
              // 构造桥梁对象
              MainComponent component = DaggerMainComponent.builder().mainModule(new MainModule()).build();
      
              //注入
              component.inject(this);
      
          }
      }
      

      看一下Person

      public class Person {
      
          public Person(){
              Log.i("dagger","person create!!!");
          }
      
      
      }
      
         
         

        最后结果不在演示。其过程如下:

        • 创建Component(桥梁),并调用注入方法。
                // 构造桥梁对象
                MainComponent component = DaggerMainComponent.builder().mainModule(new MainModule()).build();
        
                //注入
                component.inject(this);
           
           
          • 查找当前类中带有@Inject的成员变量。
              @Inject   //标明需要注入的对象
              Person person;
          
             
             
            • 根据成员变量的类型从Module中查找哪个有@Provides注解的方法返回值为当前类型。
                @Provides // 关键字,标明该方法提供依赖对象
                Person providerPerson(){
                    //提供Person对象
                    return new Person();
                }
            

            这里写图片描述

            在使用过程出现了很多注解:

            • @Module:作为实例对象的容器。
            • @Provides:标注能够提供实例化对象的方法。
            • @Component:作为桥梁,注入对象的通道。
            • @Inject:需要注入的方法

            如上使用有一种变通,修改MainModulePerson类。

            @Module   //提供依赖对象的实例
            public class MainModule {
            
            /*
                @Provides // 关键字,标明该方法提供依赖对象
                Person providerPerson(){
                    //提供Person对象
                    Log.i("dagger"," from Module");
                    return new Person();
                }
            
            */
            
            }
               
               
              public class Person {
              
                  @Inject  // 添加注解关键字
                  public Person(){
                      Log.i("dagger","person create!!!");
                  }
              
              }
              

              Module中的providePerson()方法注释,在Person中添加@Inject注解,依然能够实现。

              逻辑如下:
              - 先判断Module中是否有提供该对象实例化的方法。
              - 如果有则返回。结束。
              - 如果没有,则查找该类的构造方法,是否有带有@Inject的方法。如过存在,则返回。

              @Singleton 单例注解

              假如,对于同一个对象,我们需要注入两次,如下方式

               public class MainActivity extends AppCompatActivity{
              
                  @Inject
                  Person person;
              
                  @Inject
                  Person person2;
              
                  @Override
                  protected void onCreate(@Nullable Bundle savedInstanceState) {
                      super.onCreate(savedInstanceState);
              
                      // 构造桥梁对象
                      MainComponent component = DaggerMainComponent.builder().mainModule(new MainModule()).build();
              
                      //注入
                      component.inject(this);
              
                      // 打印两个对象的地址
                      Log.i("dagger","person = "+ person.toString()+"; person2 = "+ person2.toString());
                  }
              }
              

              看一下结果:

              person = com.mahao.alex.architecture.dagger2.Person@430d1620; person2 = com.mahao.alex.architecture.dagger2.Person@430d17c8
              
                 
                 

                可见两个对象不一致。也就是说创建了两个对象。

                可以在提供实例化对象的方法上添加@Singleton注解

                 @Provides // 关键字,标明该方法提供依赖对象
                    @Singleton
                    Person providerPerson(){
                
                        return new Person();
                    }
                
                   
                   

                  同时,对于MainComponent也需要添加注解,不添加会无法编译

                  @Singleton
                  @Component(modules = MainModule.class)  // 作为桥梁,沟通调用者和依赖对象库
                  public interface MainComponent {
                      //定义注入的方法
                      void inject(MainActivity activity);
                  
                  }

                  此时在Log,会发现两个对象的地址一样,可见是同一个对象。

                  person = com.mahao.alex.architecture.dagger2.Person@4310f898; person2 = com.mahao.alex.architecture.dagger2.Person@4310f898

                  那么不同的Activity之间,能否保持单例呢?

                  创建一个新的Activity,代码如下:

                  public class Main2Actvity extends AppCompatActivity {
                  
                      @Inject
                      Person person;
                  
                  
                      @Override
                      protected void onCreate(@Nullable Bundle savedInstanceState) {
                          super.onCreate(savedInstanceState);
                  
                          // 构造桥梁对象
                          MainComponent component = DaggerMainComponent.builder().mainModule(new MainModule()).build();
                  
                          //注入
                          component.inject(this);
                  
                          Log.i("dagger","person = "+ person.toString());
                      }
                  }
                  

                  结果如下:

                   person create!!!
                   person = com.mahao.alex.architecture.dagger2.Person@4310f898; person2 = com.mahao.alex.architecture.dagger2.Person@4310f898
                   person create!!!
                   person = com.mahao.alex.architecture.dagger2.Person@43130058
                     
                     

                    可见,@Singleton只对一个Component有效,即其单例所依赖Component对象。

                    需要参数的实例化对象

                    Person的构造方法发生了变化,需要传入一个Context,代码如下:

                    public class Person {
                    
                        private Context mContext;
                    
                        public Person(Context context){
                            mContext = context;
                            Log.i("dagger","create");
                        }
                    
                    }
                    
                       
                       

                      这样的话,我们需要修改MainModule

                      
                      @Module   //提供依赖对象的实例
                      public class MainModule {
                      
                          private Context mContext;
                      
                          public MainModule(Context context){
                              mContext = context;
                          }
                      
                      
                          @Provides
                          Context providesContext(){
                              // 提供上下文对象
                              return mContext;
                          }
                      
                          @Provides // 关键字,标明该方法提供依赖对象
                          @Singleton
                          Person providerPerson(Context context){
                      
                              return new Person(context);
                          }
                      
                      }
                      
                      • 修改providerPerson方法,传入Context对象。
                      • 添加providesContext(),用以提供Context对象。

                      看一下使用

                       // 构造桥梁对象
                              MainComponent component = DaggerMainComponent.builder().mainModule(new MainModule(this)).build();
                      
                              //注入
                              component.inject(this);
                      
                         
                         

                        逻辑:

                        • 根据@Inject注解,查找需要依赖注入的对象。
                        • MainModule中根据返回值,找到providerPerson(Context context)对象。
                        • 发现其需要传入参数Context,找到moudule中具有返回值为Context的方法providesContext()
                        • 最后就成功的构建了实例化对象。

                        可能会有疑问,我既然module中已经保存了Context对象,那么为什么不直接使用Context对象呢,因为解耦,如果使用了保存的对象,会导致下次Context获取发生变化时,需要修改providerPerson(Context context)中的代码。

                        在编写Module中,不能出现传入参数和返回参数一致的情况,会导致死循环。

                        很容易理解,需要的和获取的是同一个方法,循环调用。

                        依赖一个组件

                        在使用中,往往会有依赖另一个组件的情况。比如,在AppMoudle中能够提供Context对象,如下:

                        @Module
                        public class AppModule {
                        
                            private Context mContext;
                        
                            public AppModule(Context context){
                                mContext = context;
                            }
                        
                            @Provides
                            Context providesContext(){
                                // 提供Context对象 
                                return mContext;
                            }
                        
                        }
                        

                        而在另一个Module中需要依赖Context对象,那么怎么写呢?

                        首先编写当前AppModuleComponent

                        /**
                         *
                         * 全局的Component 组件
                         * Created by MH on 2016/7/18.
                         */
                        
                        @Component(modules = AppModule.class)
                        public interface AppComponent {
                        
                            // 向其下层提供Context 对象
                            Context proContext();
                        }
                        

                        在此种,因为Module中需要向下层提供Context对象,而其与下层的联系时通过Component
                        ,所以需要在这里声明一个其所提供对象的方法。以便下层Module获取。

                        /**
                         *
                         * 下层Module类
                         * Created by MH on 2016/7/18.
                         */
                        @Module
                        public class ActivityMoudule {
                        
                            @Provides
                            Person providePerson(Context context){
                                // 此方法需要Context 对象
                                return new Person(context);
                            }
                        }
                        
                        
                           
                           
                          /**
                           *  子的Component
                           * Created by MH on 2016/7/18.
                           */
                          @Component(dependencies = AppComponent.class,modules = ActivityMoudule.class)
                          public interface ActivityComponent {
                          
                              // 注入
                              void inject(MainActivity activity);
                          }
                          
                             
                             

                            在子Component中,有一句关键的注解dependencies = AppComponent.class,添加了上层依赖。

                            看一下使用

                                    // 依赖对象 Component
                                    AppComponent appCom = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
                            
                                    // 子类依赖对象 ,并注入
                                    DaggerActivityComponent.builder()
                                            .appComponent(appCom)
                                            .activityMoudule(new ActivityMoudule())
                                            .build()
                                            .inject(this);
                            

                            在其中使用过程中,有很重的两点。

                            • 父依赖的Component中需要添加提供对象的接口。
                            • 子依赖的Component中的注解中添加dependencies = AppComponent.class

                            @Qualifier 自定义标记

                            在使用中,会出现两个方法返回对象相同时的情况,那么如何区分呢。

                            Person对象具有两个构造方法,根据不同的参数值构造不同的方法。

                            public class Person {
                            
                                private Context mContext;
                            
                                public Person(Context context){
                                    mContext = context;
                                    Log.i("dagger","create");
                                }
                            
                                public Person(String name){
                                    Log.i("dagger",name);
                                }
                            }
                            

                            ActivityModule中添加@Named标记

                            @Module
                            public class ActivityMoudule {
                            
                                @Named("Context")  // 通过context创建Person 对象
                                @Provides
                                Person providePersonContext(Context context){
                                    // 此方法需要Context 对象
                                    return new Person(context);
                                }
                            
                            
                                @Named("name")  // 通过name创建Person 对象
                                @Provides
                                Person providePersonName(){
                                    // 此方法需要name
                                    return new Person("1234");
                                }
                            }
                            

                            使用时,也需要添加此标记

                                public class MainActivity extends AppCompatActivity{
                            
                                @Named("context") // 标记
                                @Inject
                                Person person;
                            
                                @Named("name")  // 标记
                                @Inject
                                Person person2;
                            
                            
                                @Override
                                protected void onCreate(@Nullable Bundle savedInstanceState) {
                                    super.onCreate(savedInstanceState);
                            
                                    setContentView(R.layout.activity_main);
                                    //注入
                                    component.inject(this);*/
                            
                                    // 依赖对象 Component
                                    AppComponent appCom = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
                            
                                    // 子类依赖对象 ,并注入
                                    DaggerActivityComponent.builder()
                                            .appComponent(appCom)
                                            .activityMoudule(new ActivityMoudule())
                                            .build()
                                            .inject(this);
                                }
                            
                                }
                            

                            使用时,使用者的@Inject上,必须要加入注解@Named("xxx"),不然编译期会报错。

                            这样使用过程中,虽然解决了问题,但是通过字符串标记一个对象,容易导致前后不匹配,可以通过自定义注解的方式解决。

                            添加两个注解,分别对应Contextname

                            @Qualifier  // 关键词
                            @Retention(RetentionPolicy.RUNTIME)  // 运行时仍可用
                            public @interface PersonForContext {
                                // Context 对象的注解
                            }
                               
                               
                              @Qualifier
                              @Retention(RetentionPolicy.RUNTIME)
                              public @interface PersonForName {
                                  // name 对象的注解
                              }
                                 
                                 

                                在使用@Named("")的地方替换为上面的注解

                                
                                   @PersonForContext  // 通过context创建Person 对象
                                    @Provides
                                    Person providePersonContext(Context context){
                                        // 此方法需要Context 对象
                                        return new Person(context);
                                    }
                                
                                
                                    @PersonForName  // 通过name创建Person 对象
                                    @Provides
                                    Person providePersonName(){
                                        // 此方法需要Context 对象
                                        return new Person("123");
                                    }
                                   
                                   

                                  注入时:

                                  
                                      @PersonForContext // 标记
                                      @Inject
                                      Person person;
                                  
                                  
                                      @PersonForName // 标记
                                      @Inject
                                      Person person2;
                                     
                                     

                                    Scope

                                    在前面中提到@Singleton注解,该注解能够使同一个Component中的对象保持唯一,即单例。

                                    回忆一下,如下方式:

                                        @Provides // 关键字,标明该方法提供依赖对象
                                        @Singleton
                                        Person providerPerson(Context context){
                                    
                                            return new Person(context);
                                        }
                                       
                                       

                                      Module中,对应方法中添加@Singleton注解,同时其所在的Component中,类生命上也需要添加注解

                                      
                                      @Singleton
                                      @Component(modules = MainModule.class)  // 作为桥梁,沟通调用者和依赖对象库
                                      public interface MainComponent {
                                      }
                                         
                                         

                                        如果我们看这个意思,感觉其内部应该做了很多的实现,用以达到单例。其实,没我们想的那么复杂。

                                        看一下@Singleton的实现

                                        @Scope //注明是Scope 
                                        @Documented  //标记在文档 
                                        @Retention(RUNTIME)  // 运行时级别
                                        public @interface Singleton {}
                                        
                                           
                                           

                                          通过@Scope定义的一个新的注解。

                                          在之前的,我们知道该单例是依托于他所在的Component组件。那么我们是否可以这样理解,因为方法上添加的@Scope标记的注解和Component上添加的@Scope标记的注解相同(确实相同,同为@Singleton),就表明了该方法提供的实例对象在Component保持唯一。保持唯一的条件是通过@Scope标记的注解相同。

                                          通过在上面的依赖层级上,Android中通常定义两个生命周期。

                                          全局的生命周期PerApp

                                          /**
                                           * 全局的生命周期单例
                                           */
                                          @Scope
                                          @Documented
                                          @Retention(RetentionPolicy.RUNTIME)
                                          public @interface PerApp {
                                          
                                          }
                                             
                                             

                                            在使用中完全和@Singleton相同。

                                            @Module
                                            public class AppModule {
                                            
                                                private Context mContext;
                                            
                                                public AppModule(Context context){
                                                    mContext = context;
                                                }
                                            
                                                @Provides
                                                @PerApp  // 添加该标记表明该方法只产生一个实例
                                                Context providesContext(){
                                                    // 提供上下文对象
                                                    return mContext;
                                                }
                                            
                                            }
                                            
                                            @PerApp // 因为Module 中使用了该标记,所以需要在此添加
                                            @Component(modules = AppModule.class)
                                            public interface AppComponent {
                                            
                                                // 向其下层提供Context 对象
                                                Context proContext();
                                            }

                                            因为单例的依托于他所在的Component中,所以需要在Application中进行实例化。

                                            public class App extends Application {
                                            
                                                // 为什么可以使用静态
                                                public static AppComponent appComponent;
                                            
                                            
                                                @Override
                                                public void onCreate() {
                                                    super.onCreate();
                                            
                                                    // 实例化
                                                    appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
                                            
                                                }
                                            }
                                            
                                               
                                               

                                              为什么可以使用静态的,因为该AppComponent对象的生命周期是整个App。那么在使用中,其所在Module中的实例化对象,可以保持全局单例。

                                              一个Activity的生命周期PerActivity

                                              有全局的单例,而对于一个Activity,他也有些对象需要保持单例。我们需要定义该注解。

                                              /**
                                               * Activity 单例生命周期
                                               */
                                              @Scope
                                              @Documented
                                              @Retention(RetentionPolicy.RUNTIME)
                                              public @interface PerActivity {
                                              }
                                              
                                                 
                                                 

                                                会发现,除了定义名不一样,其余都和PerApp一样。在前面,说过这样一句话:保持唯一的条件是通过@Scope标记的注解相同。

                                                @Module
                                                public class ActivityMoudule {
                                                
                                                    @PersonForContext
                                                    @Provides
                                                    @PerActivity  // 添加标记,生命其所构造的对象单例
                                                    Person providePersonContext(Context context){
                                                        // 此方法需要Context 对象
                                                        return new Person(context);
                                                    }
                                                
                                                    .....
                                                }
                                                
                                                   
                                                   
                                                  
                                                  @PerActivity  // ActivityMoudule 中使用了该标记
                                                  @Component(dependencies = AppComponent.class,modules = ActivityMoudule.class)
                                                  public interface ActivityComponent {
                                                  
                                                      // 注入
                                                      void inject(MainActivity activity);
                                                  }
                                                  
                                                     
                                                     

                                                    使用方式,因为其所保持的单例是在Activity中,具体使用如下。

                                                    public class MainActivity extends AppCompatActivity{
                                                    
                                                        @PersonForContext // 标记
                                                        @Inject
                                                        Person person;
                                                    
                                                    
                                                        @PersonForName // 标记
                                                        @Inject
                                                        Person person2;
                                                    
                                                    
                                                        /**
                                                         * 不使用静态的,因为该Component只是针对于该Activity,而不是全局的
                                                         */
                                                        ActivityComponent  activityComponent;
                                                    
                                                    
                                                        @Override
                                                        protected void onCreate(@Nullable Bundle savedInstanceState) {
                                                            super.onCreate(savedInstanceState);
                                                    
                                                            setContentView(R.layout.activity_main);
                                                    
                                                    
                                                            activityComponent = DaggerActivityComponent.builder()
                                                                    .appComponent(App.appComponent)  // 添加了全局的AppComponent组件,可以使用全局的实例化对象
                                                                    .activityMoudule(new ActivityMoudule())
                                                                    .build();
                                                    
                                                    
                                                            activityComponent.inject(this);
                                                    

                                                    对于具有依赖关系的Component,不能使用相同的Scope,如果使用相同的会带来语意不明

                                                    懒加载Lazy和强制重新加载Provider

                                                    public class MainActivity extends AppCompatActivity{
                                                    
                                                        @PersonForContext // 标记
                                                        @Inject
                                                        Lazy<Person> lazyPerson; // 注入Lazy元素
                                                    
                                                    
                                                        @PersonForName // 标记
                                                        @Inject
                                                        Provider<Person> providerPerson; // 注入Provider
                                                    
                                                    
                                                        /**
                                                         * 不使用静态的,因为该Component只是针对于该Activity,而不是全局的
                                                         */
                                                        ActivityComponent  activityComponent;
                                                    
                                                    
                                                        @Override
                                                        protected void onCreate(@Nullable Bundle savedInstanceState) {
                                                            super.onCreate(savedInstanceState);
                                                    
                                                            setContentView(R.layout.activity_main);
                                                    
                                                    
                                                            activityComponent = DaggerActivityComponent.builder()
                                                                    .appComponent(App.appComponent)  // 添加了全局的AppComponent组件
                                                                    .activityMoudule(new ActivityMoudule())
                                                                    .build();
                                                    
                                                    
                                                            activityComponent.inject(this);
                                                    
                                                    
                                                            Person person = lazyPerson.get();// 调用该方法时才会去创建Person,以后每次调用获取的是同一个对象
                                                    
                                                    
                                                            // 调用该方法时才回去创建Person1,以后每次调用都会重新加载Module中的具体方法,根据Module中的实现,可能相同,可能不相同。
                                                            Person person1 = providerPerson.get();
                                                        }
                                                    }
                                                    说这么多都没用,不如实践一下。下面提供一个链接github上的一个开源项目,RXjava+Retrofit+dagger2的框架。希望这篇文章对想要学习RXjava+Retrofit+dagger2有一些帮助
                                                    点击打开链接
                                                    
                                                       
                                                       
                                                      • 2
                                                        点赞
                                                      • 3
                                                        收藏
                                                        觉得还不错? 一键收藏
                                                      • 0
                                                        评论
                                                      对于Android项目中的网络请求,RxJavaRetrofitMVP是常用的框架组合。下面是一个简单的网络框架封装示例: 首先,在项目中引入RxJavaRetrofit的依赖。 ``` implementation 'io.reactivex.rxjava2:rxjava:2.2.19' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0' ``` 然后,创建一个Retrofit的单例类,用于进行网络请求的初始化和配置。 ```java public class RetrofitClient { private static Retrofit retrofit; private static final String BASE_URL = "https://api.example.com/"; public static Retrofit getClient() { if (retrofit == null) { retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); } return retrofit; } } ``` 接下来,创建一个ApiService接口,定义网络请求的方法。 ```java public interface ApiService { @GET("users") Observable<List<User>> getUsers(); } ``` 然后,创建一个DataManager类,用于管理网络请求。 ```java public class DataManager { private ApiService apiService; public DataManager() { apiService = RetrofitClient.getClient().create(ApiService.class); } public Observable<List<User>> getUsers() { return apiService.getUsers(); } } ``` 最后,在MVP的Presenter中调用DataManager类进行网络请求。 ```java public class UserPresenter { private UserView userView; private DataManager dataManager; public UserPresenter(UserView userView) { this.userView = userView; dataManager = new DataManager(); } public void getUsers() { dataManager.getUsers() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<List<User>>() { @Override public void onSubscribe(Disposable d) { // 在请求开始时的操作 } @Override public void onNext(List<User> users) { // 请求成功返回数据时的操作 userView.showUsers(users); } @Override public void onError(Throwable e) { // 请求失败时的操作 userView.showError(e.getMessage()); } @Override public void onComplete() { // 请求完成时的操作 } }); } } ``` 这样,就完成了一个简单的Android RxJava + Retrofit + MVP网络框架封装。你可以根据自己的需要,进行进一步的封装和扩展。

                                                      “相关推荐”对你有帮助么?

                                                      • 非常没帮助
                                                      • 没帮助
                                                      • 一般
                                                      • 有帮助
                                                      • 非常有帮助
                                                      提交
                                                      评论
                                                      添加红包

                                                      请填写红包祝福语或标题

                                                      红包个数最小为10个

                                                      红包金额最低5元

                                                      当前余额3.43前往充值 >
                                                      需支付:10.00
                                                      成就一亿技术人!
                                                      领取后你会自动成为博主和红包主的粉丝 规则
                                                      hope_wisdom
                                                      发出的红包
                                                      实付
                                                      使用余额支付
                                                      点击重新获取
                                                      扫码支付
                                                      钱包余额 0

                                                      抵扣说明:

                                                      1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
                                                      2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

                                                      余额充值