MVP在Android中2种实现(1)

对此题目有兴趣的同学都是知道至少了解这个东西,在此我不准备讲太多的理论,因为互联网上对MVP的介绍铺天盖地了.例如这位同学的文章就很精彩 Android MVP 详解(上),本人只是介绍两种MVP在Android的实现方法。

第一种:MVP在Android中2种实现(1)
第二种: MVP在Android中2种实现(2)

第一种

众所周知,MVP全称 Model-View-Presenter
Model:负责提供数据,转化为目标格式供上层接口调用
View:负责内容显示及操作指令下发
Presenter:负责协调View和Model

首先,由于大部分Android APP只是一个客户端,具体的业务逻辑几乎都在后台服务器,所以此处降低了Model的职责,将从后台获取数据写在了Presenter里面,特此说明。

本例以开发一个登陆功能来说明
具体实现思路如下:
我们知道要针对抽象编程,所以先设计接口:此处我们需要两个接口,第一个是业务逻辑接口表示登录这个操作,让presenter实现。第二个是View要实现的接口,表示View要针对登录这个操作返回的结果做出响应。

presenter实现的接口Login1Presenter

package com.ss007.androidmvpsample.mvp;

/**
 * Copyright (C) 2017
 *
 *
 * @author ben
 * @version 1.0
 * @createDate 2017/7/5 10:30
 * @description
 */

public interface Login1Presenter
{
    void login(String userName,String passWord);
}

View实现的接口Login1ActView

package com.ss007.androidmvpsample.mvp;

/**
 * Copyright (C) 2017
 *
 *
 * @author ben
 * @version 1.0
 * @createDate 2017/7/5 10:29
 * @description
 */

public interface Login1ActView
{
    void loginSuccess(String responseStr);
    void loginFailed(String code,String errBody);
}

Model

省略

View

View 自然就让我们的Activity来充当了,命名为Login1Act,样子如下图
这里写图片描述

负责参数输入,指令触发(登录),对处理结果及时作出响应

package com.ss007.androidmvpsample.mvp;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.ss007.androidmvpsample.BaseActivity;
import com.ss007.androidmvpsample.R;

public class Login1Act extends BaseActivity implements Login1ActView
{
    private final static String TAG = Login1Act.class.getSimpleName();
    private EditText userName, passWord;
    private Button btnLogin;
    private Login1Presenter mPresenter;
    private Activity mAct;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login1);
        mAct = this;
        userName = (EditText) findViewById(R.id.et_user_name);
        passWord = (EditText) findViewById(R.id.et_password);
        btnLogin = (Button) findViewById(R.id.btn_login);
        btnLogin.setOnClickListener(clickListener);
        mPresenter = new Login1PresenterImp(this);
    }

    @Override
    public void loginSuccess(String responseStr)
    {
        btnLogin.setText("Login");
        Log.d(TAG, String.format("result: %s", responseStr));
        Toast.makeText(mAct, "login success", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void loginFailed(String code, String errBody)
    {
        Log.d(TAG, String.format("error code:%s | error body: %s", code, errBody));
        Toast.makeText(mAct, "login failed", Toast.LENGTH_SHORT).show();

    }

    private View.OnClickListener clickListener = new View.OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            switch (v.getId())
            {
                case R.id.btn_login:
                    if (mPresenter != null)
                    {
                        btnLogin.setText("Loginning ...");
                        mPresenter.login(userName.getText().toString(),   passWord.getText().toString());
                    }
                    break;
                default:
                    break;
            }
        }
    };
}

Presenter

负责向后台发起网络请求

package com.ss007.androidmvpsample.mvp;

import android.os.Handler;

/**
 * Copyright (C) 2017
 *
 *
 * @author ben
 * @version 1.0
 * @createDate 2017/7/5 10:30
 * @description
 */

public class Login1PresenterImp implements Login1Presenter
{
    private Login1ActView login1ActView;
    public Login1PresenterImp(Login1ActView login1ActView)
    {
        this.login1ActView=login1ActView;
    }
    @Override
    public void login(String userName, String passWord)
    {
        //模拟登录(Mock login)
        new Handler().postDelayed(new Runnable()
        {
            @Override
            public void run()
            {
                boolean isSuccess=true;//根据实际情况判断
                if (login1ActView==null)
                    return;
                if (isSuccess)
                {
                    login1ActView.loginSuccess("the result get from your server");
                }
                else
                {
                    login1ActView.loginFailed("error code","error body");
                }
            }
        }, 2000);
    }
}

代码已经非常简单明了了,在此我做一点讲解:
第一步:根据业务需要定义两个接口,一个给Presenter实现,一个给View实现。
第二步:如果决定使用轻ModelPresenter的模式,那么Model基本就是一些JavaBean类,让View持有Presenter的引用(最好是以接口声明),那么在View中就可以调用Presenter里面的方法了,例如点击登录按钮,调用presenter里面的login()方法。
第三步:Presenter里面的方法执行后会有结果回来,那么View是要对这些结果做出响应的,例如登录后是成功了还是失败了呢?这就需要从Presenter里面调用View里面的方法将结果传过去。所以需要Presenter持有一个View的引用(最好是以接口声明)。

小结

这种方法的优点就是简单,但是有一个比较严重的问题就是在一定的情况下会造成内存泄漏。
例如这个登录页面没有一个不可取消的loading弹窗,那么用户就可以随时关闭登录页面,那么由于Presenter持有View的引用,而又当Presenter有未完成的操作不能被GC回收时,Activity也不能够释放,就会造成内存泄漏。

第二种方法将会讲解如何改进第一种方法,避免内存泄漏。

源码下载

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShuSheng007

亲爱的猿猿,难道你又要白嫖?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值