android开发 MVP模式介绍与实战

android MVP模式介绍与实战

描述


MVP模式是什么?MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。

MVC和MVP的区别?


为什么会出现MVP模式呢?这是因为原有的MVC模式有一些短板。比如在android开发中,activity充当着MVC中Controller的角色,但是在实际开发中处理view的逻辑和角色。当业务界面复杂时我的activity会显得很庞大。于是出现了MVP模式,它新增了一个Presenter角色用于处理数据和界面的模型以及逻辑,Activity仅仅用于展示界面和用户交互,这样就解决了MVC中角色不清的局面。
所以,MVP与MVC的重大区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会直接从Model中读取数据而不是通过 Controller。
在MVC里,View是可以直接访问Model的!从而,View里会包含Model信息,不可避免的还要包括一些业务逻辑。 在MVC模型里,更关注的Model的不变,而同时有多个对Model的不同显示,即View。所以,在MVC模型里,Model不依赖于View,但是View是依赖于Model的。不仅如此,因为有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少那些业务逻辑是无法重用的。

MVC模式结构

  • Model 业务逻辑和实体模型
  • Controller 对应Activity
  • View 视图以及布局文件

MVP模式结构

  • Model: 业务逻辑和实体模型
  • View:用户交互和视图显示,在android中对应activity
  • Presenter: 负责完成View于Model间的逻辑和交互

小节:MVP模式相当于在MVC模式中又加了一个Presenter用于处理模型和逻辑,将View和Model完全独立开,在android开发中的体现就是activity仅用于显示界面和交互,activity不参与模型结构和逻辑,

#### 实战
谷歌官网给了我们一个MVP模式实战的例子,它是一个类似记事本的app,源码地址在:https://github.com/googlesamples/android-architecture
 

看完源码后发现其不适合初学者理解,于是我自己写了一个demo方便大家理解。
demo源码地址:https://github.com/halibobo/AndroidMvpExample
 

下面来看源码
View层
对应的是MainActivity,它继承了抽离出View所有操作方法的接口OperationView

/**
 * *Created by su on 2016/6/22.
 */
    public interface OperationView {

    void showCreatingPhone();

    void showPhoneCountChange();

    void showNoPhone();

    void showFactoryBusy();

    void showCreatedPhone();
}

MainActivity具体对每个操作进行了具体的实现

    public class MainActivity extends AppCompatActivity implements OperationView {

    private ListView listView;

    private Button btnCreate;

    private PhonePresenter phonePresenter;

    private ProgressDialog mLoadingDialog;
    ArrayAdapter<Phone> arrayAdapter;
    private Toast toast;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        PhoneFactory phoneFactory = new PhoneFactory();
        phoneFactory.createPhone("nokia",555);
        phonePresenter = new PhonePresenter(phoneFactory, this);
        btnCreate = (Button) findViewById(R.id.btnCreate);
        listView = (ListView) findViewById(R.id.listView);
        arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, phoneFactory.getPhonesList());
        btnCreate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                phonePresenter.addPhone(new Phone("iphone", 4000+ new Random().nextInt(1000)));
            }
        });

        listView.setAdapter(arrayAdapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                phonePresenter.removePhone(position);
            }
        });

    }

    @Override
    public void showCreatingPhone() {
        mLoadingDialog = new ProgressDialog(this);
        mLoadingDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        mLoadingDialog.setMessage("工厂正在生产手机");
        mLoadingDialog.setCancelable(true);
        mLoadingDialog.show();
    }

    @Override
    public void showPhoneCountChange() {
        arrayAdapter.notifyDataSetChanged();
    }

    @Override
    public void showNoPhone() {
        findViewById(R.id.noPhone).setVisibility(View.VISIBLE);
    }

    @Override
    public void showFactoryBusy() {
        showToast("工厂繁忙,请稍后再试!");
    }

    @Override
    public void showCreatedPhone() {
        if (mLoadingDialog != null && mLoadingDialog.isShowing()) {
            mLoadingDialog.dismiss();
        }
        mLoadingDialog = null;
        showToast("新生产出一台手机!");
        findViewById(R.id.noPhone).setVisibility(View.GONE);
    }

    private void showToast(String string) {
        if (toast == null) {
            toast = Toast.makeText(this, string, Toast.LENGTH_SHORT);
        }else{
            toast.setText(string);
        }
        toast.show();
    }
}

Model层对应的是PhoneFactory,它处理和数据相关的一些简单操作

 /**
 * Created by su on 2016/6/22.
 */

/**
 * 手机工厂类
 */

public class PhoneFactory {
    private ArrayList<Phone> phonesList = new ArrayList<>();


    public void addPhone(Phone phone) {
        phonesList.add(phone);
    }

    public void removePhone(Phone phone) {
        phonesList.remove(phone);
    }

    public void removePhone(int index) {
        if (index >= 0 && index < phonesList.size()) {
            phonesList.remove(index);
        }
    }

    public void createPhone(String name, double price) {
        Phone phone = new Phone(name, price);
        phonesList.add(phone);
    }

    public ArrayList<Phone> getPhonesList() {
        return phonesList;
    }

    public int getPhoneCounts() {
        return phonesList.size();
    }
}

下面是最为重要的Presenter层 对应代码中的PhonePresenter,它处理界面逻辑和数据模型等,源码如下:

public class PhonePresenter implements TaskPresenter{

    private final PhoneFactory phoneFactory;
    private final OperationView operationView;

    private static final long createPhoneTime = 2000;
    private static final int msgWhat = 0x102;


    public PhonePresenter(@NonNull PhoneFactory phoneFactory, @NonNull OperationView operationView) {
        this.phoneFactory = phoneFactory;
        this.operationView = operationView;
    }

    @Override
    public void addPhone(Phone phone) {
        operationView.showPhoneCountChange();
        if (mHandler.hasMessages(msgWhat)) {
            operationView.showFactoryBusy();
            return;
        }
        Message message = new Message();
        message.what = msgWhat;
        message.obj = phone;
        mHandler.sendMessageDelayed(message, createPhoneTime);
        operationView.showCreatingPhone();
    }

    @Override
    public void removePhone(int index) {
        phoneFactory.removePhone(index);
        if (phoneFactory.getPhoneCounts() <= 0) {
            operationView.showNoPhone();
        }
        operationView.showPhoneCountChange();
    }

    @Override
    public void removePhone(Phone phone) {

    }

    public ArrayList<Phone> getPhones() {
        ArrayList<Phone> phones = phoneFactory.getPhonesList();
        if (phones.isEmpty()) {
            operationView.showNoPhone();
        }
        return phones;
    }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            phoneFactory.addPhone((Phone)msg.obj);
            operationView.showCreatedPhone();
            operationView.showPhoneCountChange();
        }
    };
}

总结

使用MVP模式会使得代码多出一些接口但是使得代码逻辑更加清晰,尤其是在处理复杂界面和逻辑时,我们可以对同一个activity将每一个业务都抽离成一个Presenter,这样代码既清晰逻辑明确又方便我们扩展。当然如果我们的业务逻辑本身就比较简单的话使用MVP模式就显得,没那么必要。所以我们不需要为了用它而用它,具体的还是要要业务需要

谢谢大家

原文地址:
http://dahei.me/2016/06/22/mvp/android%20MVP%E6%A8%A1%E5%BC%8F%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%AE%9E%E6%88%98/

 【关于我们】

才淇(微信公众号:caiqicehua),专注于国内各大互联网公司社会招聘内推。每天更新最新互联网名企(包括但不限于今日头条、网易游戏、BAT、网易互联网、小米、京东、乐视、携程等名企)内推信息,有技术岗、有产品岗、有运营岗、有设计岗、有交互岗、有销售岗,更有其他N多相关岗位!更多内推信息请扫描以下二维码关注查阅。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值