MVP瘦身方案的可行性
自google发布mvp架构demo以来,越来越多的人开始在项目中尝试使用mvp架构来搭建自己的项目。mvp的发布初衷也是为了将逻辑代码与UI分离,通过接口的方式互通,达到解耦的目的。但用着用着,我们会发现一个蛋疼的事实,因为mvp是通过接口的形式来互相通信,那么就无法避免地要额外写多个接口。
通常,一个Activity就对应着一个View、一个Presenter和一个Model,这就意味着有多少个Activity,就要多写至少2个接口。如果一个项目中有几十个上百个Activity,那么这增加的代码量可不容小觑,并且开发人员写起来也相当蛋疼。
贴一张现在项目某个module下presenter包结构图:

可以看到,光这里的presenter就多达20几个,相应地,model包跟ui包下也差不多都有20几个接口了。
mvp在项目中的实际操作
通常,我们是怎样定义mvp各个模块的接口的呢,拿用户端的接单DriverLocationAdvanceActivity来说:
model层:

View层:

presenter层:

可以看到,View层有三个网络请求的动作,具体的动作实施放在model层,model层通过CallBack接口回调将数据回传给presenter层,presenter层因持有view层的引用,因此调用view层的各个接口将数据传给具体的View完成具体动作的实施。
改进方案
view层与presenter层不通过接口,而是通过Message进行通信,这样就可以减少view层跟presenter层的代码量,并且可以重用presenter.
还是拿上面的例子,修改后的类结构图:
view层:

presenter层:

model层基本不变。
可以看到,view层中,在IView中增加了一个handleMessage方法,它接收一个Message对象,而presenter层中在每个方法中也都传入了Message对象,那这个Message有是什么呢?
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Messenger;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
/**
* Defines a message containing a description and arbitrary data object that can be
* sent to a {@link Handler}. This object contains two extra int fields and an
* extra object field that allow you to not do allocations in many cases.
* <p>
* <p class="note">While the constructor of Message is public, the best way to get
* one of these is to call {@link #obtain Message.obtain()} or one of the
* {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
* them from a pool of recycled objects.</p>
*/
public final class Message implements Parcelable {
/**
* User-defined message code so that the recipient can identify
* what this message is about. Each {@link Handler} has its own name-space
* for message codes, so you do not need to worry about yours conflicting
* with other handlers.
*/
public int what;
/**
* arg1 and arg2 are lower-cost alternatives to using
* {@link #setData(Bundle) setData()} if you only need to store a
* few integer values.
*/
public int arg1;
/**
* arg1 and arg2 are lower-cost alternatives to using
* {@link #setData(Bundle) setData()} if you only need to store a
* few integer values.
*/
public int arg2;
public String str;
/**
* 记录presenter的类名,当一个页面需要持有多个Presenter时使用
*/
public String presenter;
/**
* An arbitrary object to send to the recipient. When using
* {@link Messenger} to send the message across processes this can only
* be non-null if it contains a Parcelable of a framework class (not one
* implemented by the application). For other data transfer use
* {@link #setData}.
* <p>
* <p>Note that Parcelable objects here are not supported prior to
* the {@link Build.VERSION_CODES#FROYO} release.
*/
public Object obj;
public Object[] objs;
/**
* Optional Messenger where replies to this message can be sent. The
* semantics of exactly how this is used are up to the sender and
* receiver.
*/
public Messenger replyTo;
/**
* Optional field indicating the uid that sent the message. This is
* only valid for messages posted by a {@link Messenger}; otherwise,
* it will be -1.
*/
public int sendingUid = -1;
/**
* If set message is in use.
* This flag is set when the message is enqueued and remains set while it
* is delivered and afterwards when it is recycled. The flag is only cleared
* when a new message is created or obtained since that is the only time that
* applications are allowed to modify the contents of the message.
* <p>
* It is an error to attempt to enqueue or recycle a message that is already in use.
*/
/*package*/ static final int FLAG_IN_USE = 1 << 0;
/**
* If set message is asynchronous
*/
/*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
/**
* Flags to clear in the copyFrom method
*/
/*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
/*packa