結合實例分析Android MVP的實現


  最近閱讀項目的源碼,發現項目中有MVP的痕跡,但是自己卻不能很好地理解相關的代碼實現邏輯。主要原因是自己對於MVP的理解過於概念話,還沒有真正操作過。本文打算分析一個MVP的簡單實例,幫助自己更好的理解MVP的內在思想。

  對於什么是MVP,MVP和MVC的區別,MVP的有點,大家可以參考這篇文章:MVP 模式簡單易懂的介紹方式。文章里面還有demo,可以幫助大家更好的理解。

  今天分析的是一個別人寫的 demo,其實作者也有寫文章來介紹(Android MVP with Fragment and RecyclerView),那我為何還要自己來分析一遍呢?其實我已經仿照這個 demo 將 MVP 的思想用到了自己寫的一個 demo 上。但是,時間長了,又忘記了,所以打算梳理下。當然,文章肯定不會跟作者的文章一樣,得提出自己的思想。並且還對 demo 進行改造優化,使其更加符合MVP的思想。

  推薦先看前面兩篇文章,再來看本文,這樣能更好的理解文章的內容。

代碼結構簡析

  首先我們來看代碼的結構圖。 從中可以看到有6個文件夾,與 MVP 模式相關的是后面三個文件夾。model 中存放的是與數據相關的類。Picture 是數據 model,其他幾個類是負責下載Picture獲取數據的。Presenter 中會引入 model 和 view 的引用,以此來控制 model 和 view。View中只有一個 PictureView 類,但是嚴格說來,應該把 PictureFragment 和 PictureAdapter 也放在文件夾 view 中,但是這樣放也是可以的。

實現邏輯

  總體概要

  這個項目要做的事情很簡單,就是從網絡下載圖片,顯示在手機上,點擊圖片,彈出一個 Toast。

  思路分析

  MVP ?在這里 M 不就是圖片,所以肯定會有一個 Picture 實體類。圖片需要下載,因此,還要建立一個類用來控制,但是最終的調用下載是在 P 中。

  那 V ?就是 Fragment 啦,由 recyclerView 和 ProgressBar 構成的。PictureView 是一個接口,用於控制圖片的展示等。但是也是在 P 中調用。

  最后就是 P 啦,封裝了對 M, V 的操作,即 PicturePresenterImpl 這個類。

  代碼實現

  M的實現(只貼重要的代碼):

public class PictureInteractorImpl implements PictureInteractor {

    private final static String[] pictureNames = {
            "Rocket in the universe",
            "A scene in London",
            "Moon over mountains",
            "A simple moon",
            "Sun and volcano",
            "A collection of mountains",
            "River between mountains",
            "Some pine trees",
            "On Small Town",
            "Volcanos reflection"
    };


    private final static int  pictureImages[] = {
            R.drawable.cohete_flat,
            R.drawable.london_flat,
            R.drawable.material_flat,
            R.drawable.moon_flat,
            R.drawable.mountain_flat,
            R.drawable.mountain_mo_flat,
            R.drawable.moutain_go_flat,
            R.drawable.pine_flat,
            R.drawable.towers_flat,
            R.drawable.vulcan_flat
    };

    @Override
    public void loadPictures(final LoaderListener listener) {
        new Handler(Looper.getMainLooper())
                .postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        listener.onFinish(createPictures());
                    }
                }, 2000);
    }

    private List<Picture> createPictures() {
        ArrayList<Picture> pictures = new ArrayList<>();
        for (int i = 0; i < pictureNames.length; i++) {
            pictures.add(new Picture(pictureNames[i], pictureImages[i]));
        }
        return pictures;
    }
}

 

大家看上面的代碼,只有 loadPictures 是來自於接口的,為啥 createPictures 方法不寫在接口里呢?主要是因為寫在接口的方法是要在 P 中調用的。如果不需要外部調用,就沒必要接口里面了。

 

  V 的實現(只貼重要的代碼):

public interface PictureView {
    void showProgressBar();

    void hideProgressBar();

    void showMsg(String msg);

    void showPictures(List<Picture> pictures);
}

  雖然 View  中只有 PictureView 一個類,但是從這個類可以對 view 要做的事一清二楚。

  P 的實現(只貼重要的代碼):

public class PicturePresenterImpl implements PicturePresenter, LoaderListener {

    private PictureView mPictureView;
    private PictureInteractor mInteractor;

    public PicturePresenterImpl(PictureView pictureView) {
        this.mPictureView = pictureView;
        mInteractor = new PictureInteractorImpl();
    }

    @Override
    public void onResume() {
        mPictureView.showProgressBar();
        mInteractor.loadPictures(this);
    }

    @Override
    public void onDestroy() {
        mPictureView = null;
    }

    @Override
    public void onItemClick(int pos) {
        mPictureView.showMsg(String.valueOf(pos));
    }

    @Override
    public void onFinish(List<Picture> pictures) {
        mPictureView.hideProgressBar();
        mPictureView.showPictures(pictures);
    }
}

   可以看出來,P 中其實就是對 M,V 的邏輯進行了封裝,統一由其來掌控。

  最后來講講 fragment,內部引入了 P 。主要是由於 P 無法控制生命周期,所以需要借用 fragment 的生命周期來對整個過程進行控制。

疑問?

  大家看了上面的demo,不覺得在 fragment 中,即夾雜着 V, 又有 P,這樣其實不利於維護,尤其是后期當 view 越來越多的時候,那時候,還要把 view 的初始化等等都寫在 fragment 中嘛?所以接下去要對 fragment 內容進行瘦身。那怎么瘦身呢?具體請看下文。

改造

  改造后的結構,只在 view 中新建了一個 BasePageView 來處理 view 的初始化和控制邏輯。

其代碼具體如下:

public class BasePageView extends FrameLayout implements PictureView {

    private RecyclerView mRecyclerView;
    private ProgressBar mProgress;

    private PictureAdapter mAdapter;
    private PicturePresenter mPresenter;
    private Context mContext;

    /**
     * 構造函數。
     */
    public BasePageView(Context context){
        this(context, null);
    };

    public BasePageView(Context context, AttributeSet attributeSet) {
        this(context, attributeSet, 0);
    }

    public BasePageView(Context context, AttributeSet attributeSet, int defStyleAttr){
        super(context, attributeSet, defStyleAttr);
        init(context);
    }

    /**
     * 初始化
     */
    public void init(Context context) {
        mContext = context;
        inflate(mContext, R.layout.base_view_layout, this);
        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        mProgress = (ProgressBar) findViewById(R.id.progress_bar);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
    }

    @Override
    public void showProgressBar() {
        mProgress.setVisibility(View.VISIBLE);
        mRecyclerView.setVisibility(View.INVISIBLE);
    }

    @Override
    public void hideProgressBar() {
        mProgress.setVisibility(View.INVISIBLE);
        mRecyclerView.setVisibility(View.VISIBLE);
    }

    @Override
    public void showMsg(String msg) {
        Toast.makeText(mContext, msg, Toast.LENGTH_LONG).show();
    }

    @Override
    public void showPictures(List<Picture> pictures) {
        mAdapter = new PictureAdapter(pictures);
        mAdapter.setRecyclerItemClickListener(new OnRecyclerItemClickListener() {
            @Override
            public void onItemClick(int pos) {
                mPresenter.onItemClick(pos);
            }
        });
        mRecyclerView.setAdapter(mAdapter);
    }

}

 這樣當需要對視圖進行更改的時候,只需要更改這個類就可以了,不用在跑到 fragment 中去了。

於此同時,fragment 也瘦身成功了:

public class PictureFragment extends Fragment{

    private PicturePresenter mPresenter;

    public static PictureFragment newInstance() {
        return new PictureFragment();
    }

    public PictureFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_picture, container, false);
       BasePageView basePageView = (BasePageView) view.findViewById(R.id.baseView);
        mPresenter = new PicturePresenterImpl(basePageView);
        return view;
    }

    @Override
    public void onResume() {
        super.onResume();
        mPresenter.onResume();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mPresenter.onDestroy();
    }

}

  改造之后,是不是更好理解了啊。當我們需要對某一部分需要修改的時候,能夠輕松定位要修改的地方。

  好了,通過改造之后,相信大家對 MVP 的理解也就更加深刻了。

  希望這篇文章對大家有所幫助。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM