Skip to content

Latest commit

 

History

History
108 lines (89 loc) · 7.89 KB

File metadata and controls

108 lines (89 loc) · 7.89 KB

特殊功能说明

目录

DataBinding

  考虑到现在很多人项目中并没有大量使用这个东西,所以dataBinding功能默认是关闭的,开启dataBinding只需要在presenter或view的实现子类复写enableDataBinding方法,并返回true即可(不要忘记配置build.gradle)。
  基本使用参考demo中PersonDataBindingActivity界面,首先需要自己在view的实现类中声明一个当前界面对应类型的dataBinding,然后调用getDataBinding方法为这个变量赋值,后面就可以直接使用dataBinding了。

private ActivityPersonBinding mBinding;
    @Override
    public void initView (IBasePresenter presenter) {
        super.initView(presenter);
        mBinding = getDataBinding();
        mBinding.activityPersonCommitBtn.setOnClickListener(presenter);
    }

实现原理:
  MVPH对于dataBinding集成非常简单,就是采用配置参数判断使用传统方法加载布局还是使用dataBinding进行加载

使用建议:
  1.没用过dataBinding的同学,建议先去看下dataBinding的基本使用方法,然后再使用这个功能。
  2.使用dataBinding时,建议仅仅使用它的数据双向绑定以及直接通过id调用控件的功能。不要在xml布局中写逻辑,虽然它支持在xml布局中设置监听器,但是建议不要这么做,因为这样可能会引起后面逻辑的混乱与维护的复杂性。简单来说就是,不要过度依赖dataBinding。
  3.虽然dataBinding现在来说,相比之前已经成熟很多了,不过依然有个问题就是报错定位不准确的问题,这个问题在开发时绝对是令人抓狂的,所以,在使用dataBinding的时候,尽量一个界面一个界面的进行开发,以保证出错时方便查找。
  4.布局的要求(重点),dataBinding布局除了官方的要求外,在MVPH中使用还有几点强制的要求。这里只说明布局要求,具体为什么有这些限制,请看下一章节的布局结构说明。布局示例参考demo中的activity_person.xml

  • 首先,根布局必须为线性垂直布局
  • 其次,根布局id必须为dataBindingRootLayout
  • 最后,根布局中必须只能包含一个直接子布局
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
>
    <data>
        <variable name="person" type="com.xujl.mvpllirary.json.PersonPayload"/>
    </data>
    <LinearLayout android:id="@+id/dataBindingRootLayout"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:background="@color/layoutBgWhite"
                  android:orientation="vertical">
        <ScrollView android:layout_width="match_parent"
                    android:layout_height="match_parent">
                    <!--省略中间布局细节 -->
        </ScrollView>
    </LinearLayout>
</layout>

布局结构说明

  本库的自动添加toolBar功能和全局空布局功能都是基于为布局文件动态添加一个父布局(垂直线性布局),然后动态结合toolBar和真实布局实现的。从示意图可以明显看出,contentLayout才是项目中的布局文件,rootView是通过代码生成的布局,toolBar则是用rootView去添加到自己内部第一个位置的,需要特别指出的是,布局配置类中有个属性是,是否自动为布局文件创建父布局,这个属性在使用自动创建toolBar时是无效的,因为自动创建toolBar必须依赖于自动创建的父布局,这个方法主要是用于某些界面需要沉浸式状态栏。
  通过上面的说明,有的同学应该已经知道为什么在dataBinding布局中需要有那些强制要求了。这些强制要求就是为了dataBinding布局和普通布局保持结构的统一性。

反射创建说明

Presenter中持有view和model的强引用,view和model的声明类型采用的是类泛型传递到基类的,实际类型则是通过子类传递,然后进行反射创建,目前支持两种方式进行反射创建。(具体逻辑参考Presenter类中的createView或createModel方法)

  • 子类Presenter复写对应方法,直接返回对应view和model的类类型,通过类类型反射创建 demo中只有MainActivity采用了方法1进行反射创建,其他所有界面均采用方法2实现
  @Override
  protected Class<? extends IMainActivityView> getViewClassType () {
      return MainActivity.class;
  }

  @Override
  protected Class<? extends IMainActivityModel> getModelClassType () {
      return MainActivityModel.class;
  }
  • 由项目基类统一返回view和model的包路径,然后拼接出view和model的全限定名进行反射创建
    @Override
    protected String getViewClassPackageName () {
        return AppApplication.getInstance().getViewPackageName();
    }

    @Override
    protected String getModelClassPackageName () {
        return AppApplication.getInstance().getModelPackageName();
    }
注意点:
  • 基类反射逻辑为先判断子类是否返回了类类型,如果没有才会去尝试创建全限定名,也就是说方法1的优先级高于方法2
  • 两种方法优缺点对比:1方法优点在于非常自由,可以随意命名view和model类,然后进行传递,缺点在于比较繁琐,每个Presenter实现子类都必须要传递(mvp模式下)。2方法的优点在于非常简单,只需要自己在项目Presenter基类中复写一次对应方法,返回view和model的包路径,然后所有的子类无需再次复写,缺点在于:首先,对view和model的命名要求必须遵循一定规范(可以和demo中的命名规范不同,因为可以通过Presenter复写全限定名拼接方法来改变规则),其次,要求view和model的分包必须放在一起(至少activity对应的view和model,fragment对应的view和model,的分包必须各自在一起),因为如果包路径太多就会造成经常需要复写返回包路径的方法,这样的话,还不如直接使用方法1,最后,因为方法2采用的是拼接全限定名的方式,所以Presenter没有直接引用view和model的类名,这样有一个风险就是造成,以为某个view和model类未使用,而被误删。

总的来说,推荐使用方法2进行反射,虽然方法2缺点很多,但是只要习惯了这种创建方法,使用起来就会非常方便,需要特别指出的是使用方法2进行反射时就必须保证不混淆model和view的所有类,否则会找不到类,具体参见demo混淆文档示例。

加载方法说明

整体加载流程需要自行阅读源码,这里只介绍主要的几点。

  首先,不管是activity的onCreate方法还是fragment的onCreatView方法,目前都只加载了视图也就是mView的初始化代码,然后在界面可见后在子线程初始化Model,并调用model的初始化方法,延迟固定时间后最后才调用presenter的初始化方法,这么做主要是为了缓解界面初始化时的卡顿情况,当然,如果你在mView的初始化方法中做耗时操作依然后引起卡顿。

初始化方法说明:

方法名 所属类 说明
initView BaseView view的初始化方法,会被UI线程最优先调用,此方法请勿做任何耗时操作
initModel BaseModel model的初始化方法,0.1.5版本后,此方法中不再允许做耗时操作
initPresenter BasePresenter presenter的初始化方法,会被UI线程最后调用,不要做耗时操作