前言:如果童鞋對于接口回調,多態,泛型(這個很重要)不是特別熟練,或者不是特別了解,建議還是不要使用這種模式。先謝謝常規MVP練練手,等真正對這些知識能熟練掌握了再來學習MVP模式。這個架構用到了大量的接口,泛型。(基礎很重要啊)
使用MVP模式架構項目也有2個了。最新的項目原本想結合Dagger2去做(聽說會讓結構更加清晰)。不過在看了一上午Dagger2以后,我決定下個項目再集成,先把現有的MVP模式自己封裝好。 先說下項目使用技術 Rxjava+Retrofit+Gson+butterknife SDK:25 開發環境Studio 如果沒有聽說過以上技術,自行百度,這些在16年就比較流行了。
首先Gradle配置下
dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') androidTestCompile('com.android.support.test.es如果想添加控制臺輸出依賴 ,在Progect的gradle下添加如下代碼(主要為了解決 原生Log輸出字符數限制)allprojects { repositories { jcenter() //控制臺無限制輸出 遠程倉庫 maven { url "https://jitpack.io" } }}基本配置完成,說說MVP模式: 傳統的MVC模式,Activity同時擔任了View的職責和Controller的職責。整個類過于臃腫,一個8000行的類,讓你去維護,有沒有砸電腦的心情。 而MVP模式,高度解耦,使得Activity和Fragment只負責View層。 P對應的是Presenter
去年,我所遇到的關于MVP的Demo,接口過于臃腫,并且BaseActivity和BaseFragment封裝的不是太好,用到具體Presenter的時候總是伴隨著強轉,并且需要定義的接口類太多(我相信有過那段體驗的童鞋會跟我有同感,我們是外包哎,公司可不管理代碼質量怎么樣,只要功能有了,程序不閃退就行,也不會因為你代碼質量提升了就給我多的項目時間,吐槽下。)
首先,一個好的項目,應當有一個清晰可見的命名規范,否則維護起來,難度大大增加。說說我自己的項目規范吧(萬一成為行業規范那?嘿嘿) 在項目 視圖包下(個人習慣取名ui )下新建mvp包,mvp包分別有三個子包:iml,interfaces,presenter。
先說說分別是干啥的吧。 iml用于存放各種交互,通常為網絡請求。 interfaces用于存放IBaseView以及其子類 這個IBaseView是干嘛的? 就是一個接口,所有的Activity都要實現它或者它的子類。里面封裝了各種回調,比如獲取到網絡數據了,你要有一個對象回調到Activity中去做顯示,此時,就需要IBaseView了,本質就是接口。是鏈接module和view的一個橋梁 presenter:里面存放所有presenter。這個Presenter是干嘛的?就是Activity大部分邏輯處理,為什么說不是全部?因為有的是處理不了的,就比如onActivityResult 里面處理的,就放在Activity中比較合理,放到Presenter就顯得不是很合理。
首先定義基類 基類有三個,分別是BasePresenter IBaseView IViewBase 先簡單介紹一下: BasePresenter:所有的Presenter的基類,里面封裝了一些通用的東西,如Presenter與Activity綁定,解綁,IBaseView對象的獲取等等。可拓展。 IBaseView:是一個接口,主要用于每個Activity的回調處理,其子類也是改接口,需要手動實現。 IViewBase:是一個接口,掛載Presenter 等方法
下面分別貼出代碼
BasePresenter
public abstract class BasePresenter<T extends IBaseView> { public T mView;//這個是要回調的接口的對象 public Context mContext; protected String token="token"; public void attach(T mView) { this.mView = mView; } public void detachView() { if (mView != null) { mView = null; } }}IBaseView:空接口,用于封裝使用
public interface IBaseView {}IViewBase: 抽取一些方法,用于在BaseActivity和BaseFragment里去實現
public interface IViewBase<K extends IBaseView,T extends BasePresenter<K>> { T getPresenter();//Presenter對象 int getLayoutId();//布局id View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);//創建View void bindView(Bundle savedInstanceState);//onCreate()執行 View getView();//獲取根View}下面貼出BaseActivity:
public abstract class BaseActivity<K extends IBaseView,T extends BasePresenter<K>> extends AppCompatActivity implements IViewBase<K,T> ,IBaseView{ /** * 根文件 */ protected View rootView; public T mPresenter; protected MyTitleBarView mTitleBarView; protected Context context; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); context=this; init(savedInstanceState); } private void init(Bundle savedInstanceState) { //狀態欄設置 true:是否開啟 小米和魅族 狀態欄字體顏色變色 true:開啟 false:不開啟 這個是作者的一個jar的代碼,用于實現沉浸式狀態欄,集成的時候刪掉此代碼就行,我也會把這個jar上傳上去。 StatusUtils.builder(this,R.color.main_color,true); //初始化RootView rootView=createView(null,null,savedInstanceState); //設置布局 setContentView(rootView); mTitleBarView= (MyTitleBarView) findViewById(R.id.title_bar); mPresenter=getPresenter(); if (mPresenter != null) { mPresenter.attach((K) this); mPresenter.mContext=this; } bindView(savedInstanceState); AppManager.getAppManager().addActivity(this); getIntentDate(getIntent()); } @Override public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view=LayoutInflater.from(this).inflate(getLayoutId(),null); //項目集成 ButterKnife 如果沒用到這個注解插件,注釋此行代碼,用findViewById就行 ButterKnife.bind(this, view); return view; } protected void back() { finish(); } //獲取頁面傳遞數據 protected void getIntentDate(Intent intent) { } @Override protected void onDestroy() { super.onDestroy(); //作者自己的Activity管理類,注釋就行,如有興趣,會上傳項目代碼,里面都有 AppManager.getAppManager().removeActivity(this); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { back(); } return false; } @Override public View getView() { return rootView; }上傳一個示例Activity:MainActivityCallView 是一個接口,所有的頁面回調工作由他完成 集成自IBaseView 接口 MainActivityPresenter 具體的Presenter
public class MainActivity extends BaseActivity<MainActivityCallView,MainActivityPresenter> implements MainActivityCallView{ @Override public MainActivityPresenter getPresenter() { return new MainActivityPresenter(); } @Override public int getLayoutId() { return R.layout.activity_main; } @Override public void bindView(Bundle savedInstanceState) { mPresenter.login(); } //控制臺輸出下結果 @Override public void loginSuccess() { LogUtils.i("回調成功"); }}MainActivityCallView:是一個接口 里面有所有Presenter需要回調到Activity層展示的方法
public interface MainActivityCallView extends IBaseView { void loginSuccess();}MainActivityPresenter:IML_MainAService 是網絡交互的接口,用于網絡交互,此處隨便寫了一個。
public class MainActivityPresenter extends BasePresenter<MainActivityCallView>{ private IML_MainAService mService=new IML_MainAService() { @Override public void api_login() { mView.loginSuccess(); } }; public void login() { mService.api_login(); }}IML_MainAService:代碼如下,就是隨便寫了幾個方法,是那么個意思。
public interface IML_MainAService { void api_login();}最后,很重要的一點:命名規范,一個規范的命名對于項目是很重要的,不管這個項目是不是你去維護。有人習慣用縮寫,我個人認為能不用縮寫就不用,每人會猜你這是干嘛的,盡量用全拼(英語)。
說說這個項目的mvp命名規范:
功能 命名規范 Presenter 帶Activity的名稱 比如是MainActivity的Presenter 就要寫MainActivityPresenter 網絡交互 在Presenter中與遠程服務器交互的接口 都以IML_開頭后跟具體哪個類的全拼,此處作者有自己的標準 Activity和Fragment都取首字母 比如 IML_MainAService 則是 MainActivity的Presenter中網絡交互接口 IBaseView 所有的IBaseView子類都應當以主類功能命名,并且后綴固定 作者使用的是CallView結尾,當然也可以使用CallBack結尾,清晰易懂,回調處理比如 :MainActivityCallView 就是主界面的回調接口類
好了MVP模式就說到這里,稍后會上傳各種資源。
新聞熱點
疑難解答