美文网首页Android进阶之路
Android组件化+MVP+Dragger2+RxJava+E

Android组件化+MVP+Dragger2+RxJava+E

作者: lebronzhen | 来源:发表于2019-11-03 18:12 被阅读0次

    Android开发规范


    参考文章

    学习Android开发的规范,主要学习到的点:
    1、包名划分采用PBF进行分包的好处,因为同一功能代码在同一包中,所以容易删除功能,并且降低了package耦合;拥有私有作用域,一个功能不能访问另一功能的任何东西;包大小体现出功能的问题,包太大说明此功能需要进行重构。
    2、命名规范主要需要记住的是静态字段命名以s开头,非静态字段以m开头,其他的规范都比较熟悉。
    3、代码样式规范主要学习到Activities 和 Fragments 的传参,直接使用AndroidStudio写好的Live Templates,输入starter或者newInstance来生成启动器。
    4、版本统一规范,可以在build.gradle文件中使用ext来定义全局变量

    MVP


    Google官方出品的架构项目,属于MVC的演化版本,MVC中Activity的作用既像View又像Controller,演化之后,出现了Presenter,将Activity完全视为View层,Presenter则负责View和Model层之间的交互。MVC中Controller没有完全让Model和View断开联系,Model和View可以进行交互,MVP则让两者完全解耦。
    MVP简化了Activity的代码,将业务逻辑的相关代码提取到Presenter层中进行处理。同时MVP中虽然增加了很多的类,但是使代码变得很清晰。

    组件化开发


    参考文章
    组件化架构包括三层,基础层主要是封装一些常用的操作,不同的组件都可以进行引用;组件层包含各种功能组件,每个组件都是一个module;应用层来引用不同的组件实现最终的业务功能。
    组件化开发需要解决的问题:
    1.每个组件都是一个整体,开发过程中需要满足组件单独运行和调试的要求。解决方法是:
    在组件module中添加gradle.properties配置文件,在文件中添加一个boolean类型的变量,在build.gradle中通过这个布尔值来判断需要单独调试运行还是集成调试,然后修改apply plugin的值、是否需要配置applicationId,以及使用的Manifest文件的调整。
    2、组件之间的相互调用和数据传递,界面跳转
    创建ComponentBase模块,供基础层依赖,在其中定义组件中需要对外提供访问的Service接口和空实现的类,然后在组件中进行具体实现,并将实现这些方法的类的对象添加到ComponentBase提供的ServiceFactory中,其他组件就可以通过调用ServiceFactory获取想要调用的方法和数据。
    组件间的界面跳转使用第三方的ARouter来实现组件间的路由功能,在Application将它初始化,就可以通过配置的路由来实现界面跳转。
    3、主项目访问组件中的Fragment
    一种方式可以直接通过反射来进行Fragment的初始化,并传递给Activity。
    另一种方式和上述ServiceFactory方式相同,在Service接口中添加获取Fragment的方法,并在组件的实现类中返回Fragment对象,这样就可以通过ServiceFactory来获取Fragment。
    4、集成调试时,如果依赖多个组件,如何实现依赖其中一部分就编译通过
    这个问题通过上边问题的解决已经得到了解决,组件间没有直接的关联,都是通过ComponentBase的Service接口来实现,由于其中默认提供了空实现,所以即使被调用的组件没有初始化,调用也不会出现异常,只是调用了一个空的实现。

    Dagger2


    参考文章
    Dagger2是一个依赖注入框架,注入方式是通过apt插件在编译阶段生成对应的注入代码。依赖注入的目的是为了降低程序的耦合,耦合产生的原因就是因为类之间的依赖,通过依赖注入来解决类之间的依赖问题。
    如何引入Dagger2就不详细说明了,首先引入一段简单的在MVP中实现了依赖注入代码,虽然看起来比直接实例化更加复杂,但是这种方式通过添加一些辅助类解决了程序的耦合问题,去除了类之间的直接依赖。

    public class MainActivity extends AppCompatActivity implements MainContract.View {
        @Inject
        MainPresenter mainPresenter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
             //初始化
             DaggerMainComponent.builder()
                    .mainModule(new MainModule(this))
                    .build()
                    .inject(this);
            //调用Presenter方法加载数据
             mainPresenter.loadData();
        }
    
    }
    
    public class MainPresenter {
        private MainContract.View mView;
        
        @Inject
        MainPresenter(MainContract.View view) {
            mView = view;
        }    
        public void loadData() {
            //调用model层方法,加载数据
        }
    
    @Module
    public class MainModule {
        private final MainContract.View mView;
    
        public MainModule(MainContract.View view) {
            mView = view;
        }
    
        @Provides
        MainView provideMainView() {
            return mView;
        }
    }
    
    @Component(modules = MainModule.class)
    public interface MainComponent {
        void inject(MainActivity activity);
    }
    
    public interface MainContract {
        interface View extends IView {
        }
    
        interface Presenter extends IPresenter {
            void loadData();
        }
    
        interface Model extends IModel {
        }
    }
    

    然后我们rebuild一下项目,通过生成的DaggerMainComponent来实现注入,在MainActivity添加如下代码:

    DaggerMainComponent.builder()
                   .mainModule(new MainModule(this))
                   .build()
                   .inject(this);
    

    看完可能一脸懵,为什么MainActivity用@Inject注解就完成了mainPresenter的实例化,他们究竟是怎么产生的关系。
    首先有几个注解需要了解一下:

    • @Inject 带有此注解的属性或构造方法将参与到依赖注入中,Dagger2会实例化有此注解的类
    • @Module 带有此注解的类,用来提供依赖,里面定义一些用@Provides注解的以provide开头的方法,这些方法就是所提供的依赖,Dagger2会在该类中寻找实例化某个类所需要的依赖。
    • @Component 用来将@Inject和@Module联系起来的桥梁,从@Module中获取依赖并将依赖注入给@Inject

    理解了这几个含义就容易理解他们之间的关系,首先MainActivity想要依赖MainPresenter,然后发现MainPresenter构造函数有@Inject注解,可以实现实例化,但是里边有一个参数MainContract.View,因此需要通过MainModule中的provideMainView来提供依赖,作为MainModule的构造函数参数传入。
    想要更深的理解,可以看上方提供的参考文章的源码讲解,讲解的很清晰,通过生成的类之间的关系,实现了注入的过程。
    最核心的部分就是DaggerMainComponent.builder中的initialize方法

    @SuppressWarnings("unchecked")
      private void initialize(final Builder builder) {
    
        this.provideMainViewProvider = MainModule_ProvideMainViewFactory.create(builder.mainModule);
    
        this.mainPresenterProvider = MainPresenter_Factory.create(provideMainViewProvider);
    
        this.mainActivityMembersInjector = MainActivity_MembersInjector.create(mainPresenterProvider);
      }
    

    以及MainActivity_MembersInjector的injectMembers方法

    @Override
      public void injectMembers(MainActivity instance) {
        if (instance == null) {
          throw new NullPointerException("Cannot inject members into a null reference");
        }
        instance.mainPresenter = mainPresenterProvider.get();
      }
    

    MainPresenter_Factory通过MainModule_ProvideMainViewFactory的get方法获取到MainContract.View对象,MainModule_ProvideMainViewFactory的get方法则是通过传入的mainModule的provideMainView方法来获取。
    最后在DaggerMainComponent 的inject方法的实现中调用MainActivity_MembersInjector的injectMembers的方法中,injectMembers方法实现了将MainPresenter_Factory 的get方法实例化的mainPresenter赋值给MainActivity中的mainPresenter,从而实现了mainPresenter的实例化。

    查找带有@Inject注解的参数是否可以注入,有两种方式。
    第一种方式是直接查看构造函数,如果有@Inject注解则直接实例化;
    第二种是 通过@Module注解的类中的@Provides看是否有需要的依赖。
    注:如果有@Inject的构造函数中还需要其他参数,同样按照上述两种方式进行查找。

    不看源码解释的确实有点绕口,感兴趣的可以去参考文章中查看更为详细的说明。

    RxJava


    RxJava是一个基于事件流,实现异步操作的库,逻辑简洁,实现优雅,使用简单等都是RxJava的优点。
    Rxjava的原理是基于一种扩展的观察者模式,总共包括四个角色:

    角色 作用
    被观察者(Observable) 产生事件
    观察者(Observer) 接收事件,并给出响应动作
    订阅(Subscribe) 连接 被观察者 & 观察者
    事件(Event) 被观察者 & 观察者沟通的载体

    被观察者通过订阅将事件发送给观察者,观察者接收到事件并执行相应操作。
    Observable中常用到的操作符:

    • observeOn:主要功能是指定观察者(Observer)在哪个线程执行,多次执行的话都会进行切换。
    • subscribeOn:指定自身(Observable)在哪个线程执行。如果多次调用,只有第一次调用生效,之后的调用不再切换,与调用的位置没有关系。除了指定自身的执行位置还可以指定doOnSubcribe执行的位置。
    • doOnSubscribe:事件被订阅之前会调用的方法,如果调用此方法之后又调用了subscribeOn方法,那么它也会切换到新的线程中执行。
    • doOnNext:观察者被通知之前的回调方法,执行onNext()前调用。
    • compose:对当前被观察者进行操作,并返回一个新的被观察者。和map不同,map知识改变被观察者发布的事件和序列,compose则是直接对当前Observable进行操作。
    • map:将被观察者,转换成新的被观察者对象,并且发送给观察者,观察者会收到新的被观察者并处理。
    • subcribe:连接观察者和被观察者,观察者如果想要收到被观察者发送的数据,就必须要使用subcribe来订阅被观察者。里边可以实现观察者用来组合的一些方法,包括:onNext,onError,onCompleted,如果不传参数,将只发生订阅,观察者接收不到任何数据和通知。

    EventBus


    EventBus主要功能是简化组件之间的通信,同样是使用观察者模式,有效的将事件的发送和接收进行分离,实现解耦。
    主要包括事件的订阅者(接收方),事件的发布者(发送发),通过传递事件实现两者的通信。
    基本的用法就是:
    首先自定义一个事件类,用来传递事件;
    其次需要在订阅者和发布者中都进行注册,并且在页面销毁等不需要的时候取消注册;
    发送事件通过调用post方法,将发送的事件保存到事件队列;
    在接收方通过@Subscribe注解来接收事件类的对象,注解中需要指定线程模型,并进行相应的处理。
    线程模型总共分为四种:

    • POSTING (默认) 表示事件处理函数的线程跟发布事件的线程在同一个线程。
    • MAIN 表示事件处理函数的线程在主线程,因此在这里不能进行耗时操作。
    • BACKGROUND 表示事件处理函数的线程在后台线程,因此不能进行UI操作。如果发布事件的线程是主线程,那么事件处理函数将会开启一个后台线程,如果发布事件的线程是在后台线程,那么事件处理函数就使用该线程。
    • ASYNC 表示无论事件发布的线程是哪一个,事件处理函数始终会新建一个线程运行,同样不能进行UI操作。

    如果想要在事件发送之后订阅还可以接收到事件,那就需要用到粘性事件,粘性事件需要通过postSticky方法来发送,接收是需要在注解中添加sticky=true,粘性事件需要进行手动移除,也可以通过检查,看是否存在此事件。

    以上就是最新学习的一些知识,希望能给大家提供帮助。

    相关文章

      网友评论

        本文标题:Android组件化+MVP+Dragger2+RxJava+E

        本文链接:https://www.haomeiwen.com/subject/lzabvctx.html