MVP模式做的尝试

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

app模块下的目录结构
image.png
image.png

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

mvplibrary模块下的目录
image.png
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目录下的文件


image.png
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接口就行,也可以直接继承LibBaseActivityLibBaseFragment,这里面实现也比较简单,就是实现了IActivityIFragment两个接口。

再来看看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<M extends IModel, V extends IView> 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完整的方式写一套注入来完成,这样也是可以的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值