純粹是個人學習總結,如有不對的地方請吐槽。
目錄結構
app模塊下的目錄結構
app目錄下放全局配置文件,包括Application
base目錄一眼就看清是什么
di目錄存放dagger有關的文件
ui這個目錄也很清楚
mvplibrary模塊下的目錄
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目錄下的文件
再來看看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<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完整的方式寫一套注入來完成,這樣也是可以的。