MVP模式做的嘗試

純粹是個人學習總結,如有不對的地方請吐槽。
目錄結構

app模塊下的目錄結構

image.png

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

mvplibrary模塊下的目錄

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

再來看看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完整的方式寫一套注入來完成,這樣也是可以的。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容