博客主頁android
MVC:Model-View-Controller,經典模式,很容易理。數據庫
可是在Android實際開發中,這個View層對應於佈局文件,其實能作的事情特別少,實際上關於該佈局文件中的數據綁定操做,事件處理的代碼都在Activity中;咱們每每也會把具體的業務相關代碼放到了Activity中;再加上Activity自己又承擔着控制層的責任,這樣致使Contrlller層愈來愈臃腫。segmentfault
因此說,MVC真實存在的是MC(V),Controller與Model根本就分不開,View和Model嚴重耦合。服務器
從圖中能夠看出,Controller是做爲媒介,處於Model和View之間。Model和View之間有緊密的聯繫,耦合性偏強。網絡
MVC主要缺點有兩個:架構
優勢:異步
舉一個簡單的例子:獲取網絡圖片並展現在界面上ide
public interface ImageModel { // 從網絡加載圖片 void loadImage(String imagePath, OnImageListener listener); interface OnImageListener { void shopImage(Bitmap bitmap); } } public class ImageModelImpl implements ImageModel { @Override public void loadImage(String imagePath, OnImageListener listener) { if (listener != null && !TextUtils.isEmpty(imagePath)) { // 模擬網絡獲取圖片 if (!TextUtils.isEmpty(imagePath)) { listener.shopImage(BitmapFactory.decodeFile(imagePath)); } else { listener.shopImage(null); } } } }
public class MainActivity extends AppCompatActivity implements ImageModel.OnImageListener { private static final String TAG = "===>"; // View層 private ImageView mShowImageView; // Model層 private ImageModel mImageModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mShowImageView = findViewById(R.id.showImageView); findViewById(R.id.loadImageBtn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 加載圖片 mImageModel.loadImage("/mnt/sdcard/Pictures/2.png", MainActivity.this); } }); mImageModel = new ImageModelImpl(); } @Override public void shopImage(Bitmap bitmap) { if (bitmap != null) { // 展現圖片 mShowImageView.setImageBitmap(bitmap); } } }
MVP:Model-View-Presenter,MVC的一個演變模式,將Controller換成了Presenter,主要爲了解決上述第一個缺點,將View和Model解耦,不過第二個缺點依然沒有解決。函數
一、 MVP接口過多
二、 每個功能,相對於MVC要多寫好幾個文件
三、 若是某一個界面中須要請求多個服務器接口,這個界面文件中會實現不少的回調接口,致使代碼繁雜
四、 若是更改了數據源和請求中參數,會致使更多的代碼修改
五、 額外的代碼複雜度及學習成本佈局
一、 減小了Activity的職責,簡化了Activity中的代碼,將複雜的邏輯代碼提取到了Presenter中進行處理。與之對應的好處就是:耦合度更低
二、 Activity代碼變得更加簡潔:使用MVP以後,Activity就能瘦身許多了,基本上只有findView、setListener以及init的代碼。其餘的就是對Presenter的調用,還有對View接口的實現。這種情形下閱讀代碼就容易多了,並且你只要看Presenter的接口,就能明白這個模塊都有哪些業務,很快就能定位到具體代碼。Activity變得容易看懂,容易維護,之後要調整業務。刪減功能也就變得簡單許多。
三、 方便進行單元測試
四、 避免Activity的內存泄露
Java一個強大的功能就是其虛擬機的內存回收機制,這個功能使得Java用戶在設計代碼的時候,不用像C++用戶那樣考慮對象的回收問題。然而,Java用戶老是喜歡隨便寫一大堆對象,而後幻想着虛擬機能幫他們處理好內存的回收工做。但是虛擬機在回收內存的時候,只會回收那些沒有被引用的對象,被引用着的對象由於還可能會被調用,因此不能回收
Activity是有生命週期的,用戶隨時可能切換Activity,當APP的內存不夠用的時候,系統會回收處於後臺的Activity的資源以免OOM。
五、 模塊職責劃分明顯,層次清晰,接口功能清晰
六、 Model層和View層分離,解耦;修改View而不影響Model
七、 功能複用度高,方便;一個Presenter能夠複用於多個View,而不用更改Presenter的邏輯
八、 若是後臺接口還未寫好,但已知返回數據類型的狀況下,徹底能夠寫出此接口完整的功能
一、View:負責繪製UI元素,與用戶進行交互(在Android中體現爲Activity)
二、Activity interface:須要View實現的接口,View經過View interface與Presenter進行交互,下降耦合,方便進行單元測試
三、Model:負責存儲、檢索、操縱數據(有時也實現一個Model interface用來下降耦合)
四、Presenter:做爲View與Model交互的中間紐帶,處理與用戶交互的負責邏輯
從服務器端下拉最新的20篇文章,而後將每一篇文章的簡介顯示到列表上,當用戶點擊某項數據進入到另外一個頁面,該頁面加載這篇文章的詳細內容。
一、ArticleModel就是Model層接口
public interface ArticleModel { // 加載文章數據 void loadArticles(OnArticleListener listener); interface OnArticleListener { void onLoadComplete(List<Article> data); } }
二、ArticleModelImpl實現了ArticleModel接口,用於加載網絡數據,爲了代碼簡單,這裏睡眠2秒模擬從網絡獲取數據
public class ArticleModelImpl implements ArticleModel { @Override public void loadArticles(OnArticleListener listener) { new LoadArticleTask(listener).execute(); } private static class LoadArticleTask extends AsyncTask<Void, Void, List<Article>> { private final OnArticleListener listener; LoadArticleTask(OnArticleListener listener) { this.listener = listener; } @Override protected List<Article> doInBackground(Void... params) { // 模擬網絡請求 SystemClock.sleep(2000); final List<Article> data = new ArrayList<>(); for (int i = 0; i < 40; i++) { data.add(new Article("title-" + i, "message:" + i)); } return data; } @Override protected void onPostExecute(List<Article> data) { if (listener != null) { listener.onLoadComplete(data); } } } }
三、 ArticleViewInterface就是主界面的邏輯接口,表明View接口角色,用於Presenter回調View的操做
public interface ArticleViewInterface { void showProgressBar(); // 顯示進度條 void hideProgressBar(); // 隱藏進度條 void showArticles(List<Article> data); // 展現數據 }
四、Presenter層,做爲View和Model的中間人。
public interface ArticlePresenter { void loadArticles(); } public class ArticlePresenterImpl implements ArticlePresenter { // ArticleView的接口,表明了View角色 private ArticleViewInterface mView; // 文章數據的Model,也就是Model角色 private ArticleModel mArticleModel; public ArticlePresenterImpl(ArticleViewInterface view) { this.mView = view; mArticleModel = new ArticleModelImpl(); } // 獲取文章,也就是咱們的業務邏輯 @Override public void loadArticles() { mView.showProgressBar(); mArticleModel.loadArticles(new ArticleModel.OnArticleListener() { @Override public void onLoadComplete(List<Article> data) { // 數據加載完後,通知View層更新UI mView.hideProgressBar(); mView.showArticles(data); } }); } }
五、ArticleActivity須要實現ArticleViewInterface接口,而且須要創建與Presenter的聯繫,ArticleActivity的業務邏輯都交給Presenter進行處理,處理結果經過ArticleViewInterface接口回調給ArticleActivity類
public class ArticleActivity extends AppCompatActivity implements ArticleViewInterface { private ProgressBar mProgressBar; private ArrayAdapter<Article> mAdapter; private ArticlePresenter mArticlePresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); // 構建ArticlePresenter,與ArticleActivity創建關聯 mArticlePresenter = new ArticlePresenterImpl(this); } private void initView() { mProgressBar = findViewById(R.id.load_progress_bar); ListView listView = findViewById(R.id.list_view); mAdapter = new ArrayAdapter<>(this, R.layout.item_list, R.id.item_title); listView.setAdapter(mAdapter); } @Override protected void onResume() { super.onResume(); // 請求文章數據 mArticlePresenter.loadArticles(); } @Override public void showArticles(List<Article> data) { mAdapter.setNotifyOnChange(true); mAdapter.addAll(data); // 更新UI } // .... }
因爲Presenter常常須要執行一些耗時操做,如請求網絡數據,而Presenter持有了ArticleActivity的強引用,若是在請求結束以前Activity被銷燬了,那麼因爲網絡請求尚未返回,致使Presenter一直持有ArticleActivity對象,使得ArticleActivity對象沒法被回收,此時就發生內存泄露。
如何解決這樣的問題呢?
咱們能夠經過弱引用和Activity、Fragment的生命週期來解決這個問題。
一、 首先創建一個Presenter抽象,BasePresenter,它是一個泛型類,泛型類型爲View角色要實現的接口類型
public abstract class BasePresenter<V> { private Reference<V> mViewRef; // View接口類型的弱引用 public void attachView(V view) { mViewRef = new WeakReference<>(view); // 創建關聯 } public void detachView() { if (mViewRef != null) { mViewRef.clear(); mViewRef = null; } } public boolean isViewAttached() { return mViewRef != null && mViewRef.get() != null; } protected V getView() { return mViewRef.get(); } }
二、 建立一個MVPBaseActivity基類,經過這個基類的生命週期函數來控制它與Presenter的關係。MVPBaseActivity有兩個泛型參數,第一個是View的接口類型,第二個是Presneter的具體類型
public abstract class MVPBaseActivity<V, T extends BasePresenter<V>> extends AppCompatActivity{ protected T mPresenter; // Presenter對象 @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mPresenter = createPresenter(); // 建立Presenter mPresenter.attachView((V) this); } @Override protected void onDestroy() { super.onDestroy(); mPresenter.detachView(); } protected abstract T createPresenter(); }
若是個人文章對您有幫助,不妨點個贊鼓勵一下(^_^)