MVP模式做的尝试

纯粹是个人学习总结,如有不对的地方请吐槽。
目录结构

app模块下的目录结构

MVP模式做的尝试_第1张图片
image.png

app目录下放全局配置文件,包括Application
base目录一眼就看清是什么
di目录存放dagger有关的文件
ui这个目录也很清楚

mvplibrary模块下的目录

MVP模式做的尝试_第2张图片
image.png

config是配置有关的文件
delegate是监听Activity和Fragment生命周期的文件,这里就是不需要继承的关键代码
di同样是dagger相关的文件,我这用的是dagger2
mvp就是我们的mvp各个模块的基类以及接口
screen是存放dp和sp设配文件的工具类,后面会将怎么使用
sharedpre不是很形象,仔细看还是能看出是SharedPreferences相关类
后面的目录就不介绍了

下面就从如何使用说起

先来看看library下的Activity基类

public abstract class LibBaseActivity extends AppCompatActivity implements IActivity, IView {

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    initInject();//执行注入
    initData();//初始化
}

/************************{@link IActivity 接口实现}************************/

@Override
public View getLayoutView() {
    return null;
}

@Override
public boolean eventBus() {
    return false;
}

@Override
public boolean fragment() {
    return false;
}

/************************{@link IView 接口实现}************************/

@Override
public void showLoading() {

}

@Override
public void hideLoading() {

}

@Override
public void showMessage(String message) {
    Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}

/************************其他方法************************/
/**
 * 获取AppComponent
 *
 * @return AppComponent
 */
protected AppComponent getAppComponent() {
    return AppDelegate.sAppDelegate.getAppComponent();
  }
}

关于IActivity接口我们先来看看delegate目录下的文件


MVP模式做的尝试_第3张图片
image.png

再来看看IActivity里面的方法

public interface IActivity {

/**
 * 获取当前布局Id
 *
 * @return
 */
int getLayoutId();

/**
 * 执行注入方法
 */
void initInject();

/**
 * 获取当前显示的布局
 *
 * @return
 */
View getLayoutView();

/**
 * 子类做初始化操作
 */
void initData();

/**
 * 是否有事件绑定
 *
 * @return
 */
boolean eventBus();

/**
 * 是否使用fragment
 *
 * @return
 */
boolean fragment();
}

eventBus这个方法用于判断是否需要事件监听,返回true就完成了事件注册和事件注销
fragment这个方法用于判断是否需要监听fragment生命周期。

是不是觉得,看到这里还是不清楚到底是怎么回事,不用担心,这很正常,下面就来介绍如何不需要继承也能监听activity和Fragment的生命周期。

神奇之处就在于Application.ActivityLifecycleCallbacks和FragmentManager.FragmentLifecycleCallbacks对就是它们让我们脱离继承也能监听activity和Fragment的生命的周期,也许有很多小伙伴都不知道这个(我以前我也是其中之一),只是写着写着,就发现继承也存在不便(当你你已经继承了一个类,如果使用到其他第三方库,它也需要继承他的类,这时就JJ了)。

下面来看看监听的具体实现AppDelegate类,监听的关键代码

/**
 * 在application的onCreate方法中调用
 */
public void onCreate() {
    mActivityLifecycle = new ActivityLifecycle();
    mApplication.registerActivityLifecycleCallbacks(mActivityLifecycle);
    sAppDelegate = this;
}

第一行创建activity监听器,第二行设置监听器,fragment监听器后面介绍

然后在Application中创建并调用onCreate方法这样就完成了监听

 mAppDelegate = new AppDelegate(sApp);
    //这个方法执行之后会监听每个activity和fragment的生命周期
    //建议在Application的onCreate方法里面调用
    mAppDelegate.onCreate();

ActivityLifecycleCallbacks具体有那些回调方法可以自行百度,这里就不介绍了。

上面的没有看懂也没关系,只需要看懂下面的如何调用就可以了
总结一下如何调用:

public class App extends Application {
        private AppDelegate mAppDelegate;
        //当前app实例对象
        public static App sApp;
        //全局上下文对象
        public static Context sContext;
    
        @Override
        public void onCreate() {
            super.onCreate();
            sApp = this;
            sContext = this;
            mAppDelegate = new AppDelegate(sApp);
            //这个方法执行之后会监听每个activity和fragment的生命周期
            //建议在Application的onCreate方法里面调用
            mAppDelegate.onCreate();
            initInject();//初始化全局注入
        }
    
        /**
         * 初始化全局注入
         */
        public void initInject() {
            /**初始化注入,这个方法调用了之后就会调用{@link com.junwu.mvplibrary.config.IConfigModule#applyOptions(ConfigModule.Builder)}方法配置参数,
             * 接着就会调用{@link com.junwu.mvplibrary.config.IRegisterApiModule#registerComponents(IRepositoryManager)}方法,设置api接口
             * 可以在测试接口确定了之后在调用该方法,比如:测试阶段需要选择测试服务器地址,选择之后再调用这个方法
             **/
            mAppDelegate.injectRegApiService(new AppConfigModule(), new RegisterApiModule());
        }
 }
关键代码就三句话:
mAppDelegate = new AppDelegate(sApp);
mAppDelegate.onCreate();
mAppDelegate.injectRegApiService(new AppConfigModule(), new RegisterApiModule());
前面两句很好理解,最后一句就是设置OkHttp、Retrofit、RxCache的配置类和关于Retrofit、RxCache的api接口service类的配置

到这里,Activity和Fragment的生命周期监听部分和控件的初始化和事件注册,已经介绍完了,下面继续看关于MVP部分。

我们在写Activity和Fragment的时候一般都有base类,这里有两种选择,一就是自己写base类但是必须要实现IActivity和IFragment接口就行,也可以直接继承LibBaseActivity和LibBaseFragment,这里面实现也比较简单,就是实现了IActivity和IFragment两个接口。

再来看看dagger的配置,如果对dagger不熟悉的就自行查阅相关文档
这篇关于MVP模式对dagger的要求不高,只需要知道基本概念即可,如果实在不想看dagger的直接照搬也是可以的。
dagger相关的文件Component、Module、Scope以及注解Inject
AppComponent这个就是让Inject和Module产生关系的类
Module类有:AppModule配置Model的,关于更多Module

举个例子来看看,可能会更清楚

@ViewScope
@Component(modules = {ViewModule.class, ModelModule.class, UtilsModule.class}, dependencies = AppComponent.class)
public interface IViewComponent {
    /*****************************activity注入***************************/
//    void inject(StartActivity activity);
    /*****************************Fragment注入***************************/
    void inject(StartFragment fragment);
    void inject(HomeFragment fragment);
    /*****************************其他注入***************************/
}

从这里不难看出这个Component依赖AppComponent、ViewModule、ModelModule、UtilsModule

AppComponent在mvpLibary模块下:

@Singleton
@Component(modules = {AppModule.class, ClientHttpModule.class, ConfigModule.class})
public interface AppComponent {

    /**
     * 注入
     *
     * @param delegate AppDelegate
     */
    void inject(AppDelegate delegate);

    /**
     * 获取当前application对象
     *
     * @return Application
     */
    Application getApplication();

    /**
     * 获取OkHttpClient
     */
    OkHttpClient getOkHttp();

    /**
     * 获取Retrofit
     */
    Retrofit getRetrofit();

    /**
     * 获取RxCache
     */
    RxCache getRxCache();

    /**
     * 获取RxCacheBuild对应的实体
     */
    RxCacheBuilderEntity getRxCacheBuilderEntity();

    /**
     * 获取IRepositoryManager
     */
    IRepositoryManager getIRepositoryManager();
}

这个就像是基础模块的获取类

ViewModule,这个必须同你写的代码是一个Module下

@Module
public class ViewModule {

    private IView mIView;
    private Activity mActivity;

    public ViewModule(IView view) {
        this(null, view);
    }

    public ViewModule(Activity activity, IView view) {
        mActivity = activity;
        this.mIView = view;
    }

    @ViewScope
    @Provides
    public Activity provideActivity() {
        return mActivity;
    }

    @ViewScope
    @Provides
    public IView provideIView() {
        return mIView;
    }
}

这里的IView和Presenter里面的IView以及Activity实现的IView有密切关系

ModelModule类的代码

@Module
public class ModelModule {

    @ViewScope
    @Provides
    StartContract.Model provideStartContractModel(StartModel startModel) {
        return startModel;
    }
}

UtilsModule就不介绍了,它是用于配置一些工具类的注入,为了思路清晰就单独分出来了

然后在看看LibBasePresenter

public class LibBasePresenter implements IPresenter {
    protected M mModel;
    protected V mView;
    //是否注册了eventBus事件
    private boolean isEventBus = false;

    /**
     * 处理IView的所有业务逻辑
     *
     * @param m model 数据来源,网络、文件、数据库等数据
     */
    public LibBasePresenter(IModel m) {
        this.mModel = (M) m;
        onStart();
    }

    /**
     * 处理IView的所有业务逻辑
     *
     * @param v IView的子类接口实现类
     */
    public LibBasePresenter(IView v) {
        this(null, v);
    }

    /**
     * 处理IView的所有业务逻辑
     *
     * @param m model 提供网络、文件、数据库等数据来源
     * @param v IView的子类接口实现类
     */
    public LibBasePresenter(IModel m, IView v) {
        if (m != null)
            this.mModel = (M) m;
        if (v != null)
            this.mView = (V) v;
        onStart();
    }

    @Override
    public void onStart() {
        if (useEventBus()) {
            registerEventBus();
        }
    }

    @Override
    public void onDestroy() {
        //解除订阅
        if (mCompositeDisposable != null) {
            mCompositeDisposable.clear();
        }
        if (isEventBus) {
            EventBus.getDefault().unregister(this);
            isEventBus = false;
        }
        if (mModel != null) {
            mModel.onDestroy();
        }
        mModel = null;
        mView = null;
    }

    /**
     * 注册EventBus事件
     */
    protected void registerEventBus() {
        EventBus.getDefault().register(this);
        isEventBus = true;
    }
    /**
     * 是否注册事件
     *
     * @return
     */
    protected boolean useEventBus() {
        return false;
    }
}

请看构造函数Model和View都是可以为空的,这就可以根据业务来判断虚部需要Model模块,有的MVP是吧Model模块和Presenter是融合在一起的,对于一些业务不是很复杂的可以这么做,如果业务比较多还是建议将Model和Presenter区分开。

看在这里基本上应该已经看懂了,下面就来总结一下:
1:IViewComponent将所有需要注入的类都用它来注入
2:ModelModule所有的Model都有它来提供
3:ViewModule里面将所有的Activity和Fragment都视为IView,在LibBasePresenter里面会自动转换为对应的子类,减少了IView的注册
4:还是要将代码自己梳理一遍,具体可以参照MVPAttempt
这里打个小广告:关于MVPAttempt框架的应用这里有个app已经上线,有兴趣的可以下载下来看看
所有的注入都由IViewComponent来完成,可能会太死板,如果有特殊注入就可以按照dagger完整的方式写一套注入来完成,这样也是可以的。

你可能感兴趣的:(MVP模式做的尝试)