Android程式碼架構之MVP
阿新 • • 發佈:2019-01-22
1、引言
9月到了,不知道同學們的暑假作業有沒有抄完,想到學校已經離我遠去,還真的有點傷感呢,不過沒關係,即使離開了學校咱還是可以繼續學習是不是,好吧,讓我們來開始今天的學習MVP架構2、為什麼要學習MVP架構?
相信很多同學之前都跟我這個菜雞一樣,寫程式碼的時候都是想到哪兒寫到哪兒,從左到右,從上到下,寫完之後執行一下,沒有Bug繼續往下寫,這樣做似乎一直也沒出什麼問題 但是,我們發現這樣做的結果就是我們的某個類中往往寫了大量的程式碼和邏輯,一個專案中行數過千的類估計也不在少數,在寫了一段時間後別人很難看懂我們的思路,有時甚至是我們自己也會被這上千行的程式碼搞得頭皮發麻,其實,將所有邏輯都寫在一個類中這首先就不符合我們的軟體設計原則中的單一職責原則,那麼怎麼樣才能使我們的程式碼變得更優雅,每一個類都各司其職呢?答案就是本片文章的主角——MVP架構3、MVP架構的概念
4、程式碼演示
首先可以先給大家看一下沒有采用MVP架構時註冊的寫法package com.example.machenike.netdemo10; import android.app.ProgressDialog; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; importandroid.view.View; import android.widget.EditText; import android.widget.Toast; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; public class RegisterActivity extends AppCompatActivity { private EditText mUsername; private EditText mPassword; private String mUsername1; private String mPassword1; private ProgressDialog mProgressDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_register); mUsername = (EditText) findViewById(R.id.username); mPassword = (EditText) findViewById(R.id.password); } public void register(View view) { mUsername1 = mUsername.getText().toString().trim(); mPassword1 = mPassword.getText().toString().trim(); User user = new User(); user.setUserName(mUsername1); user.setPassword(mPassword1); mProgressDialog = ProgressDialog.show(this, "註冊", "玩命兒註冊中....."); RetrofitClient.getInstance().getAPI().postRequest(user).enqueue(new Callback<UserResult>() { @Override public void onResponse(Call<UserResult> call, Response<UserResult> response) { mProgressDialog.dismiss(); if (response.isSuccessful()){ UserResult userResult = response.body(); if (userResult!=null){ if (userResult.getErrcode()==1){ Toast.makeText(RegisterActivity.this,"註冊成功!!",Toast.LENGTH_SHORT).show(); return; } Toast.makeText(RegisterActivity.this,userResult.getErrmsg(),Toast.LENGTH_SHORT).show(); return; } Toast.makeText(RegisterActivity.this,"未知錯誤!",Toast.LENGTH_SHORT).show(); } } @Override public void onFailure(Call<UserResult> call, Throwable t) { mProgressDialog.dismiss(); Toast.makeText(RegisterActivity.this,"註冊失敗",Toast.LENGTH_SHORT).show(); } }); } }
從上面的程式碼中我們可以看出彈吐司,進度條,網路請求等一系列程式碼全部擠在了RegisterActivity這個類中,有些同學可能會說了,這不是看著挺好的麼。是,是挺好的,可這只是一個Demo如果在真實的開發環境下,你的Activity中都只會是這點程式碼麼?所以我們需要將裡面的程式碼進行拆分,我們可以將裡面的邏輯分為兩大類,一個是與檢視相關的,一個是與檢視無關的,由於Activity本身就屬於檢視層,所以很顯然,與檢視相關的程式碼我們可以保留,與檢視無關的拆分到Model中,在這裡哪些與檢視相關呢,哪些與檢視無關呢?很顯然,彈吐司,進度條這些與檢視有關,網路請求與檢視無關,所以我們要拆分出去的程式碼主要就是這一段
下面我將會貼出採用MVP的註冊的寫法,讓大家理解拆分的過程
首先給大家看一下我的專案結構
在這個工程中我建了m,v,p,net四個包,在m中還有個entity放置實體類的二級包,net包中是我封裝的網路請求客戶端,這裡不做重點討論,m,v,p這個三個包中分別放置MVP對應的檔案,我們會發現,基本上每個類都一個介面與之對應,這裡也是借鑑了一些面向介面程式設計的思想,看完了專案結構,給大家看一下Model中我們是怎麼寫的
首先看介面
接著看他的實現類
package com.example.machenike.mvpdemo.m; import android.util.Log; import com.example.machenike.mvpdemo.m.entity.User; import com.example.machenike.mvpdemo.m.entity.UserResult; import com.example.machenike.mvpdemo.net.RetrofitClient; import com.example.machenike.mvpdemo.p.RegisterPresenter; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; /** * Created by MACHENIKE on 2017/9/1. */ public class RegisterModeImpl implements RegisterModel{ private RegisterPresenter mRegisterPresenter; public RegisterModeImpl(RegisterPresenter registerPresenter) { mRegisterPresenter = registerPresenter; } @Override public void register(User user) { Log.e("============","RegisterModeImpl"); //顯示進度條 mRegisterPresenter.showProgress(); RetrofitClient.getInstance().getAPI().register(user).enqueue(new Callback<UserResult>() { @Override public void onResponse(Call<UserResult> call, Response<UserResult> response) { //隱藏進度條 mRegisterPresenter.hideProgress(); if (response.isSuccessful()){ UserResult userResult = response.body(); if (userResult==null){ //展示錯誤資訊 mRegisterPresenter.showMessage("未知錯誤"); return; } if (userResult.getErrcode()!=1){ //展示錯誤資訊 mRegisterPresenter.showMessage(userResult.getErrmsg()); return; } //註冊成功 mRegisterPresenter.showMessage("註冊成功!"); } } @Override public void onFailure(Call<UserResult> call, Throwable t) { //隱藏進度條 mRegisterPresenter.hideProgress(); //展示錯誤資訊 mRegisterPresenter.showMessage("註冊失敗"); } }); } }
我們發現Model的實現類完成了我們剛才寫在Activity中的網路請求,我們還發現Model的構造方法中傳入了一個Presenter的物件,是的,Presenter作為橋樑,如果我們的Model中不持有其物件我們該怎樣將資料傳輸給View呢
接著,我們來看一下Presenter的程式碼,首先是介面
然後是實現類
我們發現Presenter的構造方法中傳入了一個Activity也就是View的物件,除此之外,在Presenter的構造中還建立了一個Model的物件,並將自己的物件穿給了Model,除了構造方法外,Presenter中還有四個方法,其中三個與View相關一個與Model相關,是的,作為中間人要不偏不倚,雨露均沾,我們在getDataFromModel中呼叫register方法,在其他三個方法中呼叫View相關的另外三個方法最後只剩下Activity也就是View的程式碼了,同樣先看介面
接著實現類
在這裡我們發現,Activity中只有與檢視相關的程式碼,當我們想要獲取資料的時候只要呼叫一聲中間人
new RegisterPresenterImpl(this).getDataFromModel(new User(userName,passWord));
中間人就會去Model中拿到資料並返回