Android MVP 模式 理解与浅析

吾日三省吾身,为人谋而不忠乎?与朋友交而不信乎?传不习乎?

问题

上一个桌面项目MVC模式,在主activity中的代码超过了2000行,完成后感觉自己的项目很烂。虽然逻辑还算清晰,但是整个View层和Controller层感觉太臃肿了。

是时候该从MVC转到MVP模式了。下面就有我来简单的总结一点心得,介绍一下MVP模式,希望能给想用MVP的人一点帮助。

MVP总结和介绍

在MVP模式里通常包含4个要素:

  • (1)View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity);

  • (2)View interface:需要View实现的接口,View通过View interface与Presenter进行交互,降低耦合,方便进行单元测试;

  • (3)Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合);

  • (4)Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑。

MVC与MVP模式比较

MVC模式

  • M : 业务层和模型层,相当与javabean和我们的业务请求代码
  • V : 视图层,对应Android的layout.xml布局文件
  • C : 控制层,对应于Activity中对于UI 的各种操作

    MVP模式

  • M :还是业务层和模型层

  • V : 视图层的责任由Activity来担当
  • P : 新成员Prensenter 用来代理 C(control) 控制层
MVPDemo讲解

下面我将用一个比较简单的Demo来向大家展示一下MVP,感受一下朵密的力量吧!

这里先来看一下biz,也就是业务层,业务层独立出去,该在哪儿调用就在哪儿调用。

RequestForDataBiz代码如下:

/**
 * Created by Administrator on 2017/2/25 0025.
 * 一个请求数据的biz
 * biz就是业务层的意思
 */

public interface RequestForDataBiz {

    //请求数据业务
    void requestForData(OnRequestListener listener);
}

数据请求的回掉接口,声明了成功和失败的方法 。OnRequestListener代码如下:

    /**
         * Created by Administrator on 2017/2/25 0025.
    */

    /*请求成功或者失败的回调接口,就和网络请求一样,一个网络请求的回调大致
    有四个success,finish error cancel.这里就简单用两个,请求返回的数据为一个String集合*/

public interface OnRequestListener {

    void onSuccess(List<String> data);

    void onFailed();


}

RequestForDataBizIml代码如下:

请求的实现类为了模拟网络请求,开启了一个会sleep1秒的线程,然后装填请求的数据,通过OnRequestListener 接口回调出去,与我们平时开发的方式一致。

/**
 * Created by Administrator on 2017/2/25 0025.
 * 底下这是一个完整的网络请求,就是模拟网络数据太麻烦了,弄个假的简单说明
 */

public class RequestForDataBizIml implements RequestForDataBiz {

    @Override
    public void requestForData(final OnRequestListener listener) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    ArrayList<String> data = new ArrayList<String>();
                    for (int i = 1; i < 12; i++) {
                        data.add("item" + i);
                    }
                    if (null != listener) {
                        listener.onSuccess(data);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }


//    public static String doGet(Context context, String url, String params) //
//            throws IOException {
//        InputStream in = null;
//        URL realUrl = new URL(url.replace(" ", "%20"));
//        Log.e("infodoGet", "HttpUtil:doGet realUrl=" + realUrl.toString());
//        URLConnection conn = realUrl.openConnection();
//        conn.setConnectTimeout(5000);
//        conn.setReadTimeout(5000);
//        conn.setRequestProperty("accept", "*/*");
//        conn.setRequestProperty("connection", "Keep-Alive");
//        conn.setRequestProperty("user-agent",
//                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)") ;
//        //    conn.setRequestProperty("X-Bsl-Client" , Configure.PACKAGE_NAME + "^" + Configure.has_secure) ;
//
//        try {
//            conn.connect();
//            in = conn.getInputStream();
//            BufferedReader br = new BufferedReader(new InputStreamReader(in));
//            String line = "";
//            result = new StringBuffer();
//            while (null != (line = br.readLine())) {
//                result.append(line);
//            }
//        } catch (SocketException e) {
//            return new String("SocketException");
//        } catch (SocketTimeoutException e) {
//            return new String("SocketException");
//        }
//
//        try {
//            if (in != null) {
//                in.close();
//            }
//        } catch (IOException ex) {
//            ex.printStackTrace();
//        }
//        Log.e("infodoGet", "Httpresult.toString()"+ result.toString());
//        return result.toString();
//    }
//
}

业务层的业务在此处完成。

MVP的凝视与思考

由于Activity变成了view层不再去控制界面,但是具体的界面的改变api其实还是由Activity来提供的,所以在写MVP之前需要思考,View层需要哪些方法,要做哪些事情。

  • 1,显示loading
  • 2,隐藏loading
  • 3,listview的初始化,展现页面
  • 4,弹出Toast消息

MVPView接口代码如下


/**
 * Created by Administrator on 2017/2/25 0025.
 * view层需要哪些方法,涉及到的UI展示。
 */

public interface MVPView {

    //显示loading progressBar
    void showLoading();

    //隐藏loading progressBar
    void hideLoading();

    //ListView的初始化,展示界面
    void initListView(List<String> data);

    //Toast message
    void showMessage(String message);


}

我们总结出View层需要的接口。我们的Activty就是View层,所以直接用Activity来实现上面的方法。将View视图层就完成。


public class MainActivity extends AppCompatActivity implements MVPView {

    private ProgressBar mMvpLoadingbarProgressBar;
    private ListView mMvpListviewListView;
    private RelativeLayout mActivityMainRelativeLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mMvpLoadingbarProgressBar = (ProgressBar) findViewById(R.id.mvp_loadingbar);
        mMvpListviewListView = (ListView) findViewById(R.id.mvp_listview);
        mActivityMainRelativeLayout = (RelativeLayout) findViewById(R.id.activity_main);


    }

    @Override
    public void showLoading() {
        mMvpLoadingbarProgressBar.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoading() {
        mMvpLoadingbarProgressBar.setVisibility(View.GONE);
    }

    @Override
    public void initListView(List<String> data) {
        ArrayAdapter adapter = new ArrayAdapter(MainActivity.this,android.R.layout.simple_list_item_1,data);
        mMvpListviewListView.setAdapter(adapter);
    }

    @Override
    public void showMessage(String message) {
        Toast.makeText(this,message,Toast.LENGTH_SHORT).show();
    }
}

View视图层完成了。接下来开始写presenter层, 同样在写presenter之前想想控制层需要哪些方法?

  • (1)网络请求数据
  • (2)点击事件的响应

MVPresenter代码如下

/**
 * Created by Administrator on 2017/2/25 0025.
 * - (1)网络请求数据
 - (2)点击事件的响应

 */

public class MVPresenter {


    private MVPView mvpView;
    RequestForDataBiz requestBiz;
    private Handler mHandler;

    public MVPresenter(MVPView mvpView) {
        this.mvpView = mvpView;
        requestBiz = new RequestForDataBizIml();
        mHandler = new Handler(Looper.getMainLooper());
    }

    public void onResume(){
        mvpView.showLoading();
        requestBiz.requestForData(new OnRequestListener() {
            @Override
            public void onSuccess(final List<String> data) {
                //由于请求开启了新线程,所以用handler去更新界面
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mvpView.hideLoading();
                        mvpView.initListView(data);
                    }
                });

            }

            @Override
            public void onFailed() {
                mvpView.showMessage("请求失败");
            }
        });
    }

    public void onItemClick(int position){
        mvpView.showMessage("点击了item"+position);
    }


    public void onDestroy(){
        mvpView = null;
    }
}

Presenter完成(Presenter里面像不像接管了MVC模式中的C层?理解才是硬道理啊!),现在就剩下一件事,Activity中使用Presenter。

下面放大招:完整版的MainActivity:

/*
* MVP实现了,是不是很简洁?
* 就是这么清爽,没有乱七八糟的业务。
* 没有各种点击处理逻辑,Activity只需要提供View层的方法就可以了。
* 你看现在activity的生命周期都托管给了MVPresenter。
* 你要做的就是加深理解,把你的业务逻辑也带入到prenter层去处理。
* */
public class MainActivity extends AppCompatActivity implements MVPView ,AdapterView.OnItemClickListener{

    private ProgressBar mMvpLoadingbarProgressBar;
    private ListView mMvpListviewListView;
    private RelativeLayout mActivityMainRelativeLayout;
    MVPresenter mMVPresenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mMvpLoadingbarProgressBar = (ProgressBar) findViewById(R.id.mvp_loadingbar);
        mMvpListviewListView = (ListView) findViewById(R.id.mvp_listview);
        mActivityMainRelativeLayout = (RelativeLayout) findViewById(R.id.activity_main);
        mMVPresenter=new MVPresenter(this);

    }

    @Override
    public void showLoading() {
        mMvpLoadingbarProgressBar.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoading() {
        mMvpLoadingbarProgressBar.setVisibility(View.GONE);
    }

    @Override
    public void initListView(List<String> data) {
        ArrayAdapter adapter = new ArrayAdapter(MainActivity.this,android.R.layout.simple_list_item_1,data);
        mMvpListviewListView.setAdapter(adapter);
    }

    @Override
    public void showMessage(String message) {
        Toast.makeText(this,message,Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        mMVPresenter.onItemClick(position);
    }


    //将生命周期托付给MVPresenter,你的逻辑,业务,在这里面做的事都可以转移到MVPresenter
    @Override
    protected void onResume() {
        super.onResume();
        mMVPresenter.onResume();

    }

    @Override
    protected void onDestroy() {
        mMVPresenter.onDestroy();
        super.onDestroy();
    }
}

一点体会和小小的心得

可以看到,View只负责处理与用户进行交互,并把数据相关的逻辑操作都扔给了Presenter去做。视图层与控制层完全分离,可以让我们在界面还是很粗糙的情况下,先进行控制层的开发,甚至可以先让View层先提供方法出来,这样可以节省很多时间。

Github源码下载地址

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值