Android中的MVP架构

Android应用的MVC架构,Activity往往充当了View和Control双重角色,造成代码耦合性较强。怎样将View和Control解耦呢,可以使用MVP架构(Model、Control、Prestener)将Activity的View和Control彻底分离,不说废话了直接上代码吧!

github: https://github.com/Allin1579/MVP-android

 

以Activity为例,Fragment的原理相同:

View:我们将Activity看作一个单纯的View

package com.allin.android.activity;

import com.allin.android.presenter.BasePrestener;

import android.app.Activity;
import android.os.Bundle;

/**
 * MVP架构中Activity的基类,主要用于与Prestener建立关联并管理生命周期
 * @author Allin
 * 2015.11.24
 * @param <V> BaseActivity子类需继承的View接口,该接口声明了Activity的各种视图操作逻辑, MVP中的V
 * @param <P> BasePrestener子类, MVP中的P
 */
public abstract class BaseActivity<V, P extends BasePrestener<V>> extends Activity {
    protected P mPrestener; //持有一个Prestener对象的引用,用来调用Prestener中的数据逻辑

    @SuppressWarnings("unchecked")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPrestener = createPrestener();
        mPrestener.attachView((V)this);
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mPrestener.detachView();
    }
    
    protected abstract P createPrestener(); //mPrestener对象延迟到子类生产
    
}

Prestener:中介者用来处理数据逻辑和View中视图逻辑的流程控制

package com.allin.android.presenter;

import java.lang.ref.Reference;
import java.lang.ref.WeakReference;

/**
 * MVP架构中Prestener的基类,主要用于与View建立关联并管理生命周期
 * @author Allin
 * 2015.11.24
 * @param <V> View接口
 */
public abstract class BasePrestener<V> {
    protected Reference<V> mViewRef; //持有一个V的引用,用来调用Activity或Fragment中的视图逻辑
    
    public void attachView(V view){
        mViewRef = new WeakReference<V>(view); //此处使用弱引用,防止因Activity或Fragment异常关闭造成内存泄露
    }
    
    protected V getView(){
        return mViewRef.get();
    }
    
    public boolean isViewAttached(){
        return mViewRef != null && mViewRef.get() != null;
    }
    
    public void detachView(){
        if(mViewRef != null){
            mViewRef.clear();
            mViewRef = null;
        }
    }
    
}

至此,V和C已经完全解耦。

为了避免Prestener臃肿,我们可以将具体逻辑进一步分离,以联网Api为例:

package com.allin.android.api;

import java.util.Map;

/**Api基类
 * @author Allin
 * 2015.11.24
 */
class BaseApi {

    /**
     * http get请求
     * @param url
     * @param params
     * @param callback 将网络获取的数据回调给调用者
     */
    public void httpGet(final String url, final Map<?, ?> params, final ApiCallback callback){
        // TODO Auto-generated method stub
    }
    
    /**
     * http post请求
     * @param url
     * @param params
     * @param callback 将网络获取的数据回调给调用者
     */
    public void httpPost(final String url, final Map<?, ?> params, final ApiCallback callback){
        // TODO Auto-generated method stub
    }
}

Api回调接口:

package com.allin.android.api;

/**
 * ApiCallback
 * @author Allin
 * 2015.11.24
 */
public interface ApiCallback {

    /**
     * 网络请求成功的回调
     * @param result
     */
    <T> void onSucceed(T result);
    
    /**
     * 网络请求失败的回调
     * @param msg
     */
    void onFailed(String msg);
}

用法举栗,写一个Activity包含三个功能:创建长度为length的无序数组用ListView展示出来、排序并刷新ListView、统计有多少项的值为value

首先写一个ViewListener声明Activity里面的方法:

package com.allin.android.listener;
/**
 * MVPViewListener
 * @author Allin
 * 2015.11.24
 */
public interface MVPViewListener extends BaseViewListener{
    
    /**
     * 创建无序数组并在列表显示
     * @param array
     */
    void showList(int[] array);
    
    /**
     * 排序然后刷新列表
     */
    void sort();
    
    /**
     * 统计有多少项的值为value
     * @param value
     */
    void count(int value);

}

然后是Activity和Prestener的交互,先看Activity

package com.allin.android.activity;

import com.allin.android.adapter.MVPAdapter;
import com.allin.android.allin.R;
import com.allin.android.listener.MVPViewListener;
import com.allin.android.presenter.MVPPrestener;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

/**
 * MVPActivity
 * @author Allin
 * 2015.11.24
 */
public class MVPActivity extends BaseActivity<MVPViewListener, MVPPrestener> 
    implements MVPViewListener, OnClickListener{ private ListView mListView; private EditText mEditText; private TextView mCountText; private TextView mSortText; private MVPAdapter mAdapter; /** * 父类BasePrestener的抽象函数,必须在子类中实现,用来创建具体的Prestener对象 * Prestener对象及其生命周期全部交给父类管理,子类只需要创建实例就可以了 */ @Override protected MVPPrestener createPrestener() { return new MVPPrestener(); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.mvp); initView(savedInstanceState); initData(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.count: String edit = mEditText.getText().toString(); int value = Integer.parseInt(edit); count(value); break; case R.id.sort: sort(); break; default: break; } } @Override public void initView(Bundle savedInstanceState) { mListView = (ListView) findViewById(R.id.list); mEditText = (EditText) findViewById(R.id.edit); mCountText = (TextView) findViewById(R.id.count); mSortText = (TextView) findViewById(R.id.sort); mCountText.setOnClickListener(this); mSortText.setOnClickListener(this); } @Override public void initData() { mPrestener.init(); //数据逻辑交给Prestener去处理 } @Override public void showList(int[] array) { mAdapter = new MVPAdapter(array); mListView.setAdapter(mAdapter); } @Override public void sort() { mPrestener.sort(); //数据逻辑交给Prestener去处理 } @Override public void count(int value) { int count = mPrestener.count(value); //数据逻辑交给Prestener去处理 Toast.makeText(this, String.valueOf(count), Toast.LENGTH_SHORT).show(); } }

Prestener

package com.allin.android.presenter;

import com.allin.android.algorithms.Sort;
import com.allin.android.listener.MVPViewListener;
import com.allin.android.util.Factory;

/**
 * MVPPrestener
 * @author Allin
 * 2015.11.24
 */
public class MVPPrestener extends BasePrestener<MVPViewListener> {
    private int[] array;
    
    public void init(){
        array = Factory.createArray(1000);
        getView().showList(array);
    }

    public void sort(){
        Sort.sort(array);
        getView().showList(array);
    }
    
    public int count(int value){
        int count = 0;
        for (int i = 0; i < array.length; i++) {
            if(value == array[i]){
                count++;
            }
        }
        
        return count;
    }

}

 视图与数据逻辑分离之后,两边的代码都十分干净清爽,而且方便维护。缺点在于对开发人员的接口设计能力要求比较高

posted @ 2015-11-27 15:27  Allin1579  阅读(302)  评论(0编辑  收藏  举报