亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Google 開發(fā)Android MVP架構(gòu)Demo深入解析

 更新時間:2022年11月25日 09:10:47   作者:itbird01  
這篇文章主要為大家介紹了Google 開發(fā)Android MVP架構(gòu)Demo深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

1.什么是MVP?

Google在2016年推出了官方的Android MVP架構(gòu)Demo,本文主要分析一下官方的MVP Demo,并且借由自己的一些經(jīng)驗,提出一些學習過程中,遇到的問題和自己的改進、封裝措施。

MVP架構(gòu)已經(jīng)推出很多年了,現(xiàn)在已經(jīng)非常普及了,我在這里就不過多介紹,簡單的說,它分為以下三個層次:

  • Model:數(shù)據(jù)模型層,主要用來數(shù)據(jù)處理,獲取數(shù)據(jù);
  • View:顯示界面元素,和用戶進行界面交互;
  • Presenter: 是Model和View溝通的橋梁,不關(guān)心具體的View顯示和Model的數(shù)據(jù)處理。View層中所有的邏輯操作都通過Presenter去通知Model層去完成,Model中獲取的數(shù)據(jù)通過Presenter層去通知View層顯示。 MVP架構(gòu)最大的好處,就是把傳統(tǒng)MVC架構(gòu)中View層和Control層的復雜關(guān)系完全解耦,View層只關(guān)心界面顯示相關(guān)的工作即可,Model層僅獲取數(shù)據(jù),處理邏輯運算即可,各司其職,而不用關(guān)心其他工作。而且大家發(fā)現(xiàn)沒有,這樣設計的話,很好寫單元測試代碼,針對于View、Presenter、Model層我們可以分別選用適合的單元測試框架,不用再像MVC/MVVM一樣,由于代碼混在或者分離在多處,到處無法“單一職責”的去完成每個類的單元測試代碼編寫。

在剛剛接觸android的時候,或者說,現(xiàn)在依然有很大一部分的APP開發(fā)者,在開發(fā)過程中,總是習慣在一個Activity、Fragment中幾乎完成了所有的功能。例如網(wǎng)絡請求、數(shù)據(jù)加載、業(yè)務邏輯處理、界面加載、界面動畫。 后來漸漸的我們接觸到了MVC、MVP各種官方的框架,懂得了模塊的分離、解耦(MVC),懂得了通過依賴于抽象去分離各個模塊徹底解耦(MVP)。 但是官方的MVP框架的確已經(jīng)幫我們做了很多,但是依然不夠,接下來,我們基于官方給的MVP框架,結(jié)合六大基本原則,去封裝更加適宜于項目的MVP框架。 整體設計模式Demo代碼

2.Google官方的MVP

官方Demo怎么去做的?

我們?yōu)榱朔奖闳シ治?,我這里簡化代碼,我們逐步分析,BaseView 和 BasePresenter,BaseView谷歌是這么寫的(其實就是view的接口,展示view),以下樣例為了理解,我簡化處理了部分代碼 BaseView.java

package com.itbird.design.principle.mvp.google;
/**
 * Google Demo
 * Created by itbird on 2022/2/25
 */
public interface BaseView<T> {
    //View中,設置presenter對象,使View可以持有Presenter對象引用
    void setPresenter(T presenter);
}

BasePresenter

package com.itbird.design.principle.mvp.google;
/**
 * Google Demo
 * Created by itbird on 2022/2/25
 */
public interface BasePresenter {
}

TaskDetailContract

package com.itbird.design.principle.mvp.google;
/**
 * Google Demo
 * Created by itbird on 2022/2/25
 */
public interface TaskDetailContract {
    interface View extends BaseView<Presenter> {
        //界面UI刷新方法
        void updateTextView(String s);
    }
    interface Presenter extends BasePresenter {
        void loadDataFromModel();
    }
}

TaskGoogleActivity

package com.itbird.design.principle.mvp.google;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.itbird.design.R;
public class TaskGoogleActivity extends AppCompatActivity implements TaskDetailContract.View {
    private static final String TAG = TaskGoogleActivity.class.getSimpleName();
    private TaskDetailContract.Presenter mPresenter;
    private TextView mTextView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.textview);
        Log.e(TAG, TAG + " onCreate");
        new TaskGooglePresenter(this);
    }
    @Override
    public void setPresenter(TaskDetailContract.Presenter presenter) {
        mPresenter = presenter;
    }
    @Override
    public void updateTextView(String s) {
        mTextView.setText(s);
    }
}

TaskGooglePresenter

package com.itbird.design.principle.mvp.google;
public class TaskGooglePresenter implements TaskDetailContract.Presenter {
    private static final String TAG = TaskGooglePresenter.class.getSimpleName();
    TaskDetailContract.View mView;
    public TaskGooglePresenter(TaskDetailContract.View view) {
        mView = view;
        mView.setPresenter(this);
    }
    @Override
    public void loadDataFromModel() {
        //TODO :loaddata,此處可以用model、或者進行業(yè)務操作
        //調(diào)用界面方法,進行數(shù)據(jù)刷新
        mView.updateTextView("loaddata success!!!");
    }
}

小結(jié) 我們單從設計來說, Google MVP Demo的確向我們展示了MVP的優(yōu)點:

  • 1)業(yè)務、數(shù)據(jù)、視圖分離、解耦,從六大基本原則上來說,開閉、單一職責、里氏代換、依賴倒置、接口隔離、最少知道,基本都做到了。
  • 2)由于完全分離,所以我們很方便針對于每層去選取對應的單元測試模式,例如針對于數(shù)據(jù)層可以使用(Junit+Mockito)、視圖層可以使用(AndroidJunitRunner+Espresso)、業(yè)務層可以使用(Junit+Mockito)
  • 3)通過Contract 契約類,完全將視圖、業(yè)務相關(guān)的接口,封裝放在了一個地方,簡單明了,針對于開發(fā)者來說,不容易忘記和輔助養(yǎng)成習慣

但是,但是對于我們實際開發(fā)使用來說,依然有以下幾點問題:

  • 1)setPresenter接口完全沒有必要存在,因為Presenter對象一定是在View類中new出來的,我既然都有它自己的對象了,干嘛還要在Presenter內(nèi)部,去調(diào)用mView.setPresenter(this);,再返回View中,再去保存一個引用,代碼看著很怪
  • 2)我們知道MVP的精髓在與,P、V肯定要相互交互,他們互相要持有對方的引用,通過上面一點,我們知道Presenter對象一定是在View類中new出來的,所以View肯定有Presenter對象的引用,這個沒問題了。但是Presenter要想擁有View的引用,只能通過Presenter構(gòu)造方法、或者Presenter內(nèi)部有一個setView方法,讓開發(fā)者自己去調(diào)用setView或者實現(xiàn)帶參構(gòu)造方法,從設計角度來說,這明顯是一個坑,因為一個框架的設計,是為了更加方便開發(fā),而不是讓開發(fā)人員設置這個、設置那個、必須調(diào)用某個方法。既然是必須調(diào)用的方法,我們應該通過框架去內(nèi)部消化掉,而不是給開發(fā)者制造麻煩。
  • 3)Presenter中擁有View的引用,如果activity、fragment銷毀,但是presenter依然在執(zhí)行某些任務,這樣會導致activity、fragment無法GC回收,導致內(nèi)存泄露,甚至與崩潰,所以這也是一個框架必須解決的問題。

3.V1.1 My MVP V1

基于上面提出的三點,我們?nèi)?yōu)化Google的MVP框架。 我們首先將第一點和第二點通過抽象來解決一下。 IPresenter

package com.itbird.design.principle.mvp.v1;
/**
 * 自定義MVP框架,BasePresenter
 * Created by itbird on 2022/2/25
 */
public interface IPresenter {
    /**
     * 與view班定
     *
     * @param view
     */
    void onAttach(IView view);
    /**
     * 與view解綁
     */
    void onDetach();
    /**
     * 是否與view已經(jīng)班定成功
     *
     * @return
     */
    boolean isViewAttached();
    /**
     * 獲取view
     * @return
     */
    IView getView();
}

IView

package com.itbird.design.principle.mvp.v1;
/**
 * 自定義MVP框架,BaseView
 * Created by itbird on 2022/2/25
 */
public interface IView {
}

接下來是借助activity生命周期,對presenter的初始化進行封裝 BaseActivity

package com.itbird.design.principle.mvp.v1;
import android.app.Activity;
import android.os.Bundle;
import androidx.annotation.Nullable;
/**
 * Created by itbird on 2022/3/29
 */
public abstract class BaseActivity extends Activity implements IView {
    IPresenter mPresenter;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPresenter = createPresenter();
        if (mPresenter != null) {
            mPresenter.onAttach(this);
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mPresenter != null) {
            mPresenter.onDetach();
            mPresenter = null;
        }
    }
    abstract IPresenter createPresenter();
}

BasePresenter

package com.itbird.design.principle.mvp.v1;
import java.lang.ref.WeakReference;
/**
 * Created by itbird on 2022/3/29
 */
public class BasePresenter<V extends IView> implements IPresenter {
    WeakReference<V> mIView;
    @Override
    public void onAttach(IView iView) {
        mIView = new WeakReference<>((V) iView);
    }
    @Override
    public void onDetach() {
        mIView = null;
    }
    @Override
    public V getView() {
        if (mIView != null) {
            mIView.get();
        }
        return null;
    }
    @Override
    public boolean isViewAttached() {
        return mIView != null && mIView.get() != null;
    }
}

4.V1.2 My MVP V2

看上圖類圖,我們依然發(fā)現(xiàn)有一些不滿足的點:

1)activity中,依然需要初始化mPresenter

 @Override
    IPresenter createPresenter() {
        mTaskPresenter = new TaskMyPresenter();
        return mTaskPresenter;
    }

是否可以做到在activity中,自己像presenter中調(diào)用view一樣,自己一句話getView就可以搞定

2)觀察類圖,其實IView、IPresenter沒有必要存在,因為畢竟只是baseActivity、basePresenter的行為

所以改造如下: BasePresenter

package com.itbird.design.principle.mvp.v2;
import java.lang.ref.WeakReference;
/**
 * Created by itbird on 2022/3/29
 */
public abstract class BasePresenter<V> {
    WeakReference<V> mIView;
    public void onAttach(V iView) {
        mIView = new WeakReference<>(iView);
    }
    public void onDetach() {
        mIView = null;
    }
    public V getView() {
        if (mIView != null) {
            mIView.get();
        }
        return null;
    }
    public boolean isViewAttached() {
        return mIView != null && mIView.get() != null;
    }
}

BaseActivity

package com.itbird.design.principle.mvp.v2;
import android.app.Activity;
import android.os.Bundle;
import androidx.annotation.Nullable;
/**
 * Created by itbird on 2022/3/29
 */
public abstract class BaseActivity<V, T extends BasePresenter<V>> extends Activity {
    T mPresenter;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPresenter = initPresenter();
        if (mPresenter != null) {
            mPresenter.onAttach((V) this);
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mPresenter != null) {
            mPresenter.onDetach();
            mPresenter = null;
        }
    }
    public T getPresenter() {
        return mPresenter;
    }
    abstract T initPresenter();
}

此時,契約類,不再需要依賴BasePresenter/BaseView相關(guān)接口,而且View中也可以自己獲取到presenter的引用了。

package com.itbird.design.principle.mvp.v2;
/**
 * my Demo
 * Created by itbird on 2022/2/25
 */
public interface TaskMyContract {
    interface View {
        //界面UI刷新方法
        void updateTextView(String s);
    }
    interface Presenter {
        void loadDataFromModel();
    }
}
package com.itbird.design.principle.mvp.v2;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import com.itbird.design.R;
public class TaskMyActivity extends BaseActivity<TaskMyContract.View, TaskMyPresenter> implements TaskMyContract.View {
    private static final String TAG = TaskMyActivity.class.getSimpleName();
    TextView mTextView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = findViewById(R.id.textview);
        Log.e(TAG, TAG + " onCreate");
        mPresenter.loadDataFromModel();
    }
    @Override
    TaskMyPresenter initPresenter() {
        return new TaskMyPresenter();
    }
    @Override
    public void updateTextView(String s) {
        mTextView.setText(s);
    }
}

此時的類圖,是否更加明確,而且上面各個問題都已經(jīng)得到了解決。

整體設計模式Demo代碼

以上就是Google 開發(fā)Android MVP架構(gòu)Demo深入解析的詳細內(nèi)容,更多關(guān)于Google Android MVP 架構(gòu)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論