Android工程架构设计:Base Library(基层MVP框架)基于EventBus

Base Library部分把App中Application,UI(activity,fragment)公用方法重新封装成模板方法,并开放对子类的扩展。同时融入mvp设计思想,封装成基于mvp的基层架构体系。

Android工程架构设计:Base Library(基层MVP框架)基于EventBus_第1张图片

目录

1,IApplication(接口):

2,BaseApplication(抽象基类)

2.1 规定Application中行为的执行规则(模板方法模式)

2.2 实现IApplication中的部分行为(通用部分)

2.3 Application关键方法

2.4 定义与公共行为相关的抽象方法(具体行为),供子类扩展

2.5 缓存管理Activity

3,mvp(基层mvp架构)

3.1. mvp策略微调

3.1.1.PV之间通讯采用EventBus消息机制替换之前的接口回调机制。

3.1.2.增加对P的缓存管理

3.2. 契约类 Contract

3.3. V层

1. Activity

3.3.2. Fragment

3.4. P层

3.4.1. Presenter

3.4.2. Event

3.5. M层

4,GlobalField

总结


 

1,IApplication(接口):

1,把框架内应用(Application)的通用行为抽象定义(框架内app都会用到的初始化或者公参配置的行为方法)。

2,继承ActivityLifecycleCallbacks接口,整合Activity生命周期回调方法。

之后框架内所有app的自定义Application应该都实现此接口,具体行为放在各个app的Application中实现。

public interface IApplication extends Application.ActivityLifecycleCallbacks {
    /**
     * 初始化组件(生命周期)(组件化)
     */
    void initModules();
    /**
     * 初始化Router(组件化)
     */
    void initRouter();
    /**
     * init net config
     */
    void initNetworkConfig();
    /**
     * create SharedPreference by name
     *
     * @param sharedName SharedPreference name
     */
    void initSharedPreference(String sharedName);
    /**
     * other config
     */
    void initOtherConfig();
}

也就是说,每个app的Application做了两部分事情,一部分是实现了公共行为(IApplication)(共性),另外一部分实现了私有行为(异性)。

2,BaseApplication(抽象基类)

public abstract class BaseApplication extends MultiDexApplication implements IApplication

BaseApplication需要做四件事情:

2.1 规定Application中行为的执行规则(模板方法模式)

@Override
public void onCreate() {
    super.onCreate();
    INSTANCE = this;
    registerActivityLifecycleCallbacks(this);
    /*
     * 组件化框架使用,非组件化无用
     */
    initModules();
    /*
     * 组件化框架使用,非组件化无用
     */
    initRouter();
    initNetworkConfig();
    initSharedPreference(defineSharedPreferenceName());
    initOtherConfig();
    /*
     * 组件化框架调用组件生命周期,非组件化无用
     */
    ModuleRouter.getInstance().onModulesCreate(defineModulesNeedManagedByModuleName());
}

2.2 实现IApplication中的部分行为(通用部分)

@Override
public void initModules() {
    ModuleRouter.getInstance().loadModules(this);
}
@Override
public void initSharedPreference(String sharedName) {
    SharedUtils.initInstance(getApplicationContext(), sharedName);
}

2.3 Application关键方法

@Override
public void onTerminate() {
    super.onTerminate();
    /*
     * 组件化框架调用组件生命周期,非组件化无用
     */
    ModuleRouter.getInstance().
		onModulesTerminate(defineModulesNeedManagedByModuleName());
    unregisterActivityLifecycleCallbacks(this);
}
@Override
public void onLowMemory() {
    super.onLowMemory();
    /*
     * 组件化框架调用组件生命周期,非组件化无用
     */
   ModuleRouter.getInstance().
		onModulesLowMemory(defineModulesNeedManagedByModuleName());
}
@Override
public void onTrimMemory(int level) {
    super.onTrimMemory(level);
    /*
     * 组件化框架调用组件生命周期,非组件化无用
     */
    ModuleRouter.getInstance().
		onModulesTrimMemory(defineModulesNeedManagedByModuleName(), level);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    /*
     * 组件化框架调用组件生命周期,非组件化无用
     */
    ModuleRouter.getInstance().
	onModulesConfigurationChanged(defineModulesNeedManagedByModuleName(), newConfig);
}
@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    MultiDex.install(this);
}

本类库中,利用Activity生命周期回调方法,由BaseApplication对Activity对应P层的注册,解注行为进行统一管理。支持Activity,AppCompatActivity,FragmentActivity。

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    if (activity instanceof BaseActivity) {
        ((BaseActivity) activity).registerPresenter();
    } else if (activity instanceof BaseAppCompatActivity) {
        ((BaseAppCompatActivity) activity).registerPresenter();
    } else if (activity instanceof BaseFragmentActivity) {
        ((BaseFragmentActivity) activity).registerPresenter();
    }
}
@Override
public void onActivityDestroyed(Activity activity) {
    if (activity instanceof BaseActivity) {
        ((BaseActivity) activity).unregisterPresenter();
    } else if (activity instanceof BaseAppCompatActivity) {
        ((BaseAppCompatActivity) activity).unregisterPresenter();
    } else if (activity instanceof BaseFragmentActivity) {
        ((BaseFragmentActivity) activity).unregisterPresenter();
    }
}

2.4 定义与公共行为相关的抽象方法(具体行为),供子类扩展

protected abstract String defineSharedPreferenceName();
/**
 * define modules which need managed in Application lifecycle(组件化使用)
 */
protected abstract String[] defineModulesNeedManagedByModuleName();

// other methods ...

2.5 缓存管理Activity

/**
 * app有效activity缓存
 */
private List> activityList = new ArrayList();
/**
 * app当前activity缓存
 */
private List> currentActivityList = new ArrayList();
…… ……
/**
 * get current activity
 * @return Activity
 */
public Activity getCurrentActivity() {
    return currentActivityList.size() == 0 ? null : currentActivityList.get(0).get();
}
/**
 * kill all activity
 */
public void killAllActivity() {
    for (WeakReference activity : activityList) {
        if (null != activity && null != activity.get()) {
            activity.get().finish();
        }
    }
}
/**
 * kill all activities Except!!!
 * @param activityClass Except activity class
 */
@SuppressWarnings("unchecked")
public void killAllActivityExcept(Class activityClass) {
    for (WeakReference weakReference : activityList) {
        if (null != weakReference && null != weakReference.get() && !weakReference.get().getClass().equals(activityClass)) {
            weakReference.get().finish();
        }
    }
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    activityList.add(new WeakReference<>(activity));
    // ……
}
@Override
public void onActivityStarted(Activity activity) {
    if (currentActivityList.size() == 0) {
        ModuleRouter.getInstance().
		enterForeground(defineModulesNeedManagedByModuleName());
    }
    currentActivityList.add(new WeakReference<>(activity));
}
@SuppressWarnings("unchecked")
@Override
public void onActivityStopped(Activity activity) {
    for (Iterator iterator = currentActivityList.iterator(); iterator.hasNext(); ) {
        WeakReference weakReference = (WeakReference) iterator.next();
        if (null != weakReference && null != weakReference.get() && weakReference.get() == activity) {
            iterator.remove();
        }
    }
    if (currentActivityList.size() == 0) {
        ModuleRouter.getInstance().
		enterBackground(defineModulesNeedManagedByModuleName());
    }
}
@SuppressWarnings("unchecked")
@Override
public void onActivityDestroyed(Activity activity) {
    // ……
    for (Iterator iterator = activityList.iterator(); iterator.hasNext(); ) {
        WeakReference weakReference = (WeakReference) iterator.next();
        if (null != weakReference && null != weakReference.get() 
		&& weakReference.get() == activity) {
            iterator.remove();
        }
    }
}

3,mvp(基层mvp架构)

mvp最近很火,也很烦,各个公司,各位大神,对mvp的理解和应用各异,论坛上各种对mvp的详解,demo,设计分析以及基于mvp的各种开源项目 ……

作者浅见:mvp就是一种架构设计思想,目的在于把UI展现层,业务逻辑处理层,数据管理层在代码中解耦,达到某种程度的代码层次清晰明了(我的理解:某种程度!!!)。至于实际应用中以何种方式设计实现,达到何种程度? …… 因人因项目因公司而已吧,设计成本,团队理解力,学习成本,代码可读性等等……哪种才是最好的?达到目的,适合自己就够了,别出严重bug就好。另外,作者后续会对mvp的个人理解整理成文,敬请关注!

作者在接触并应用mvp设计思想的过程中,总结到一些问题(针对标准mvp):

1,频繁的接口调用和回调:V让P做事情,需要调用P的接口,P从M请求数据需要调用M的接口;M把数据返回给P做业务处理要调用P的回调接口,P处理完业务逻辑或者业务数据返回给V做交互反馈又要调用V的回调接口。 

你会发现,一套mvp代码写完,光接口就定义了一火车,烦且繁!一个简单UI交互,动辄需要2~4个甚至更多接口定义,层级解耦的开发代价是否过大呢?

2,耦合,主要是PV的耦合,很难完全避免。V依赖P,P又要持有V的接口类型,即便网上某些设计采用了各种方式极力避免(弱引用等等) …… 

那是否mvp就一定要达到一种完全解耦的效果呢?也不一定,作者从业这几年,也拜读过一些组件源码,发现一个问题,coding在封装代码的时候,往往会过度追求完美(技术流往往很执着),有时候一段很简单的代码,被设计的很复杂,层层封装,层层回调 …… 其实有时候还是适当为好吧,也要考虑开发成本,性能,代码可读性,如果是作为公共组件,还要考虑学习成本,外观接口是否便于外部调用等等因素(仅个人愚见,不喜勿喷,也许是因为作者代码能力的确有限,达不到而下意识给自己找了个借口吧)。

以最直接的方式,最简单的策略,尽可能高效滴实现需求。这是我对coding的理解。

上述浅见,作者在自己的mvp框架内,做了如下调整:

3.1. mvp策略微调

3.1.1PV之间通讯采用EventBus消息机制替换之前的接口回调机制

Android工程架构设计:Base Library(基层MVP框架)基于EventBus_第2张图片

V单项依赖于P,避免P层持有V对象引用,P回馈给V通过EventBus封装消息实现。 流程就是V向P发处理命令(V调用P的方法),P做业务处理后,向Module层索要数据,M层获取数据之后接口反馈给P,P针对不同业务做数据二次加工(这个部分也可以放在M,来分担P的压力)。P将执行结果(数据,命令)封装成消息(Event),通过EventBus发送给V进行处理。(考虑到代码可读性,可追溯性,消息机制仅限于P—>V的部分,并没有用EventBus实现PV双向通讯)

综述就是,在PV之间加了EventBus消息机制,由双向依赖变成了单项依赖,保留了业务请求接口(V—>P)

(1)  P层(BaseEvent)

Base Library在P层定义了Event基类,通过成员变量eventTag区分消息目的UI线程(消息应该发送给哪个View,eventTag值一般为View的包名 + 类名 字符串构成),通过成员变量actionTag区分同一UI线程不同类型的逻辑操作(登录,忘记密码,找回密码,刷新列表等操作类型)。

public abstract class BaseEvent {
    /**
     * default action tag for Initialization UI thread
     */
    public static final String ACTION_TAG_INIT_PROCESS = "init_process";
    /**
     * default action tag for Http Response error
     */
    public static final String ACTION_TAG_RESPONSE_ERROR = "network_response_error";
    /**
     * for different UI thread. default value: name of current class
     */
    public String eventTag;
    /**
     * same UI thread, different action
     */
    public String actionTag;
// …………
// …………
}

(2)V层

Base Library在V层提供了统一的Event接收入口,统一接收Event消息,并通过eventTag过滤,用户可以在UI线程通过接收到的Event的actionTag进行行为分发,区别响应。

public abstract class BaseActivity

extends Activity implements Contract.IView { // …………………… /** * receive Event Message * @param event BaseEvent * @param BaseEvent */ @Subscribe @Override public void onEventMessageReceive(E event) { if (null == event || !event.eventTag.equals(getSimpleTag())) { return; } switch (event.actionTag) { case BaseEvent.ACTION_TAG_INIT_PROCESS: // do sth init view initDataView(event); break; default: onHandleMessage(event); break; } } // …………………… }

其中BaseEvent.ACTION_TAG_INIT_PROCESS定义为初始化刷新UI数据行为,单独提供消息处理接口initDataView,其余类型消息由onHandleMessage接收处理。

/**
 * Init data and refresh view
 * @param event BaseEvent
 * @param    BaseEvent
 */
protected  void initDataView(E event){}
/**
 * receive and handle EventBus message
 * @param event BaseEvent
 * @param    BaseEvent
 */
protected abstract  void onHandleMessage(E event);

优势:

系统内置这套BaseEvent以及接收入口,通过eventTag区分UI线程(view),actionTag区分线程内实际操作。可大大减少EventMessage(消息类)的定义数量,改善原来EventBus对每一种消息,都需要定义一种消息类的情况。结合对actionTag的统一定义和管理,简化代码的同时,也可提高代码可读性。

争议:

如果使用系统内置这套BaseEvent以及接收入口,会导致每个注册的观察者类都会收到发送的消息:

public  void onEventMessageReceive(E event)

是否会影响性能呢?

作者认为微乎其微,可以忽略。策略本身实际是把原来EventBus对注册特定Message类型的观察者发送消息的点对点机制,变成了广播。但考虑本身app实际同时有效注册EventBus的类和方法数量有限,量级可控,性能影响可忽略。其实就相当于自定义了一个LocalBroadcast。

用户也可以抛弃Base Library内置的BaseEvent,在App层自定义一套EventMessage,并按照常规写法,在每个注册EventBus的类中,实现消息接收代码。同时在每个App中对Base Library的BaseActivity定义中间父类,隐藏相关方法,实现对子类的无感知。

public abstract class BaseActivity

extends library.base.mvp.v.activity.BaseActivity

{ // ...... @Override protected void initDataView(E event) { } @Override protected void onHandleMessage(E event) { } // ...... }

3.1.2.增加对P的缓存管理

增加对P的缓存管理,制定缓存策略(失效策略),有效解决由于手机横竖屏切换等原因(V重启生命周期),导致P重新创建,重新请求数据等资源消耗。(稍后详述)

/**
 * cache:packageName + className(V) : Presenter
 */
private LinkedHashMap presenterCache = new LinkedHashMap<>();

目前对P的缓存是对应交互业务逻辑,是按照UI的交互逻辑划分的,也就是认为PV一 一对应(key:V的package + name; value:P),也就是实际上一个P中只注册(缓存)了一个V(eventTag)

优化目标(此处只提供建议,各位可自行优化扩展):

(1)P保持按照UI的交互逻辑划分,PV实现一对多关系,实现对P的复用(key:P的package + name; value:P),P中将注册(缓存)多个V(eventTag),P与V交互的时候,会对所有缓存的eventTag,都发送一遍EventMessage。

(2)P按照项目业务需求划分,VP实现多对多关系,实现对P的真正复用(key:P的package + name; value:P)。

3.2. 契约类 Contract

契约类 Contract 来统一管理 base mvp相关接口,使得某一功能模块的接口能更加直观的呈现出来,有利于后期维护。

其中IView定义了接收系统Event消息的接口;IPresenter增加了对P生命周期接口定义;IModule定义了数据以及异常回调接口。

/**
 * @author Created by qiang.hou on 2018/4/6.
 * @version 1.0
 */
public interface IContract {

    /**
     * @author Created by qiang.hou on 2018/3/2.
     * @version 1.0
     */
    interface IView {
        @Subscribe
         void onEventMessageReceive(E event);
    }

    /**
     * @author Created by qiang.hou on 2018/3/2.
     * @version 1.0
     */
    interface IPresenter {
        void doInitProcess();

        void onCreate();

        void onStart();

        void onResume();

        void onPause();

        void onStop();

        void onSaveInstanceState(Bundle savedInstanceState);

        void onDestroy();
    }

    /**
     * @author Created by qiang.hou on 2018/5/7.
     * @version 1.0
     */
    interface IModule {

        /**
         * add
         *
         * @param modelClass    model class
         * @param modelObserver observer
         */
         void addModelObserver(Class modelClass, IModelObserver modelObserver);

        /**
         * remove
         *
         * @param modelClass model class
         */
         void removeModelObserver(Class modelClass);

        /**
         * call the notify method with model data
         *
         * @param modelClass model class
         * @param models     data
         */
         void notifyModelObserver(Class modelClass, T... models);

        /**
         * call the notify method with model data
         *
         * @param modelClass model class
         * @param e          Exception
         */
         void notifyErrorObserver(Class modelClass, E e);

        /**
         * @author Created by qiang.hou on 2018/5/9.
         * @version 1.0
         */
        interface IModelObserver {
            void onNotify(T... data);

            void onError(E e);
        }
    }

    /**
     * @author Created by qiang.hou on 2018/3/2.
     * @version 1.0
     */
    interface IPresenterManager {
        BasePresenter getPresenter(String localClassPath);

        void addPresenter(String localClassPath, BasePresenter presenter);
    }
}

3.3. V层

Base Library对ActivityFragment分别作了封装,BaseActivity,BaseAppCompatActivity,BaseFragmentActivity分别对应Activity,AppCompatActivity,FragmentActivityBaseFragment,BaseFragmentV4分别对应 android.app.Fragment,android.support.v4.app.Fragment。

UI层的封装没啥可说的,大家的做法大同小异,仅供参考。

1. Activity

Base类分别做了以下几件事情:

(1)把基础行为封装为模板(onCreate)

// 跟踪打印当前activity名
LogUtils.i(getSimpleTag(), "sky_dreaming on onCreate activity = "
        + getSimpleTag());
// 加载布局文件
if (returnLayoutId() > 0) {
    this.setContentView(returnLayoutId());
    ButterKnife.bind(this);
}
// 初始化控件
initView();
// 特殊控件设置监听器
setListener();
// 如果页面不需要在onResume生命周期中刷新数据,在onCreate中初始化加载数据;否则该行为放在onResume中执行
if (!refreshOnResume()) {
    /**
     * 初始化加载数据
     */
    initProcess();
}

(2)提供abstract方法供子类扩展

/**
 * Init views
 */
protected abstract void initView();
/**
 * receive and handle EventBus message
 * @param event BaseEvent
 * @param    BaseEvent
 */
protected abstract  void onHandleMessage(E event);
/**
 * get layout id
 * @return layout resource id
 */
protected abstract int returnLayoutId();
/**
 * create Presenter
 * @return P
 */
public abstract P createPresenter();
/**
 * if this view need EventBus
 * @return boolean
 */
protected abstract boolean needEventBus();

(3)开放Presenter注册以及解注方法

由Application在Activity生命周期回调方法中,调用registerPresenter()完成对P的创建和绑定以及解绑

public void registerPresenter() {
    if (needEventBus()) {
        registerEventBus();
    }
    mPresenter = (P) PresenterManager.getInstance().getPresenter(getSimpleTag());
    if (null == mPresenter) {
        mPresenter = createPresenter();
        if (null != mPresenter) {
            PresenterManager.getInstance().addPresenter(getSimpleTag(), mPresenter);
        }
    }
    if (null != mPresenter) {
        mPresenter.registerViewEvent(getSimpleTag());
    }
}

1)根据用户需求,选择是否注册EventBus组件

2)从缓存(PresenterManager)尝试获取presenter对象,如果获取不到,创建一个,同时将新创建的对象纳入缓存。

3)把当前UI线程的标识TAG注册给P(PV通过EventBus通讯,TAG用于区分目的UI线程)。

同时将创建P的方法createPresenter();开放给子类用户实现。

解绑:unRegisterPresenter();

public void unregisterPresenter() {
    if (null != mPresenter) {
        mPresenter.unRegisterViewEvent(getSimpleTag());
    }
    unregisterEventBus();
}

(4)开放通用行为

统一接收Event消息,并通过eventTag过滤,通过actionTag分发

@Subscribe
@Override
public  void onEventMessageReceive(E event) {
    if (null == event || !event.eventTag.equals(getSimpleTag())) {
        return;
    }
    switch (event.actionTag) {
        case BaseEvent. ACTION_TAG_INIT_PROCESS:
            // do sth init view
            initDataView(event);
            break;
        default:
            onHandleMessage(event);
            break;
    }
}

获取当前activity标识(包名 + 类名)

public String getSimpleTag() {
    return getPackageName() + this.getClass().getSimpleName();
}

跳转到指定页面

public void startNextActivity (Intent intent, boolean needForResult,
                               int requestCode, int enterAnim, int exitAnim, boolean needFinishCurrent) {
    if (needForResult) {
        startActivityForResult(intent, requestCode);
    } else {
        startActivity(intent);
    }
    if (enterAnim > 0 && exitAnim > 0) {
        overridePendingTransition(enterAnim, exitAnim);
    }
    if (needFinishCurrent) {
        finish();
    }
}

3.3.2. Fragment

Fragment在上述Activity封装策略的基础上,加了懒加载机制:

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    /**
     *  (for lazy loading data)
     */
    isViewInitiated = true;
    prepareRequestData();
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    /**
     *  (for lazy loading data)
     */
    prepareRequestData();
}
/**
 * prepare to get data (for lazy loading data)
 *
 * @return
 */
public boolean prepareRequestData() {
    // set param true: force update data when fragment visible
    return prepareRequestData(false);
}
/**
 * prepare to get data (for lazy loading data)
 *
 * @param forceUpdate true: force update data when fragment visible
 * @return
 */
public boolean prepareRequestData(boolean forceUpdate) {
    if (getUserVisibleHint() && isViewInitiated && (!isDataLoaded || forceUpdate)) {
        initProcess();
        isDataLoaded = true;
        return true;
    }
    return false;
}

3.4. P层

3.4.1. Presenter

(1)BasePresenter

Presenter对应交互业务逻辑,是按照UI的交互逻辑划分的(当前PV一对一设计)。P持有V的唯一标识(包名 + 类名)的缓存列表(当前每个P只缓存一个V的标识),通过添加,移除V标识,实现在P对V的注册解注。P通过EventBus发送带有V唯一标识的Event消息给V,V通过识别唯一标识来判断接收到的消息归属。

定义了V唯一标识的缓存列表

/**
 * cache event tag
 */
private List eventTagCache = new ArrayList<>();

提供了注册,解注的开放接口

/**
 * create relationship with view
 * @param eventTag event tag
 */
public void registerViewEvent(String eventTag) {
    if (!isViewRegistered(eventTag)) {
        validTime = System.currentTimeMillis();
        eventTagCache.add(eventTag);
    }
}
/**
 * detach the relationship
 */
public void unRegisterViewEvent(String eventTag) {
    if (isViewRegistered(eventTag)) {
        eventTagCache.remove(eventTag);
    }
    if (eventTagCache.size() == 0) {
        invalidTime = System.currentTimeMillis();
    }
}

并内置本身失效策略,为外部对P的缓存提供策略依据。

    /**
     * time for registering new event tag of view
     */
    private long validTime = 0;
    /**
     * time for clear new event tag of view
     */
    private long invalidTime = 0;
    public boolean isEffective() {
        return (invalidTime - validTime) / 1000 < PRESENTER_CACHE_TIME;
    }

提供发送EventMessage消息接口

/**
     * @param data data
     * @param aTag action tag
     * @param   data type
     */
    public  void postEvent(T data, final String aTag) {
        for (String eventTag : eventTagCache) {
            final String viewTag = eventTag;
            EventBus.getDefault().post(new BaseEvent(data) {
                @Override
                protected String returnThreadTag() {
                    return viewTag;
                }

                @Override
                protected String returnActionTag() {
                    return aTag;
                }
            });
        }
    }

    /**
     * @param data data
     * @param aTag action tag
     * @param   data type
     */
    public  void postStickyEvent(T data, final String aTag) {
        for (String eventTag : eventTagCache) {
            final String viewTag = eventTag;
            EventBus.getDefault().postSticky(new BaseEvent(data) {
                @Override
                protected String returnThreadTag() {
                    return viewTag;
                }

                @Override
                protected String returnActionTag() {
                    return aTag;
                }
            });
        }
    }

    /**
     * @param data data
     * @param aTag action tag
     * @param   data type
     * @param  data type
     */
    public  void postEvent(T data, T2 data2, final String aTag) {
        for (String eventTag : eventTagCache) {
            final String viewTag = eventTag;
            EventBus.getDefault().post(new BaseEvent(data, data2) {
                @Override
                protected String returnThreadTag() {
                    return viewTag;
                }

                @Override
                protected String returnActionTag() {
                    return aTag;
                }
            });
        }
    }

    /**
     * @param data data
     * @param aTag action tag
     * @param   data type
     * @param  data type
     */
    public  void postStickyEvent(T data, T2 data2, final String aTag) {
        for (String eventTag : eventTagCache) {
            final String viewTag = eventTag;
            EventBus.getDefault().postSticky(new BaseEvent(data, data2) {
                @Override
                protected String returnThreadTag() {
                    return viewTag;
                }

                @Override
                protected String returnActionTag() {
                    return aTag;
                }
            });
        }
    }

    /**
     * @param data data
     * @param aTag action tag
     * @param   data type
     * @param  data type
     * @param  data type
     */
    public  void postEvent(T data, T2 data2, T3 data3, final String aTag) {
        for (String eventTag : eventTagCache) {
            final String viewTag = eventTag;
            EventBus.getDefault().post(new BaseEvent(data, data2, data3) {
                @Override
                protected String returnThreadTag() {
                    return viewTag;
                }

                @Override
                protected String returnActionTag() {
                    return aTag;
                }
            });
        }
    }

    /**
     * @param data data
     * @param aTag action tag
     * @param   data type
     * @param  data type
     * @param  data type
     */
    public  void postStickyEvent(T data, T2 data2, T3 data3, final String aTag) {
        for (String eventTag : eventTagCache) {
            final String viewTag = eventTag;
            EventBus.getDefault().postSticky(new BaseEvent(data, data2, data3) {
                @Override
                protected String returnThreadTag() {
                    return viewTag;
                }

                @Override
                protected String returnActionTag() {
                    return aTag;
                }
            });
        }
    }

    /**
     * @param aTag action tag
     */
    public void postEvent(final String aTag) {
        for (String eventTag : eventTagCache) {
            final String viewTag = eventTag;
            EventBus.getDefault().post(new BaseEvent() {
                @Override
                protected String returnThreadTag() {
                    return viewTag;
                }

                @Override
                protected String returnActionTag() {
                    return aTag;
                }
            });
        }
    }

    /**
     * @param aTag action tag
     * @param   E extends BaseEvent
     */
    public  void postStickyEvent(final String aTag) {
        for (String eventTag : eventTagCache) {
            final String viewTag = eventTag;
            EventBus.getDefault().postSticky(new BaseEvent() {
                @Override
                protected String returnThreadTag() {
                    return viewTag;
                }

                @Override
                protected String returnActionTag() {
                    return aTag;
                }
            });
        }
    }

    /**
     * @param event E extends BaseEvent
     */
    public  void postEvent(E event) {
        EventBus.getDefault().post(event);
    }

    /**
     * @param event E extends BaseEvent
     */
    public  void postStickyEvent(E event) {
        EventBus.getDefault().postSticky(event);
    }

(2)PresenterManager

P缓存管理类,内置缓存池,开放get,add接口,同时在每次get调用之前,轮询检查缓存,剔除无效缓存。

之所以设计Presenter缓存策略,主要考虑两点因素,一是对多V复用,二是节省资源,避免由于V生命周期异常等原因,导致P重构,浪费资源。之前有考虑把P的生成,P对V的注册,解注也放到管理类中实现,后来取消了,有心者可以尝试变更。

public class PresenterManager implements Contract.IPresenterManager {
    /**
     * cache
     */
    private LinkedHashMap presenterCache = new LinkedHashMap<>();
    
    // ......
     
    /**
     * @param localClassPath packageName + className
     * @return BasePresenter
     */
    public BasePresenter getPresenter(String localClassPath) {
        /*
         * clear Invalid presenter
         */
        for (Map.Entry entry : presenterCache.entrySet()) {
            if (null == entry.getKey() || null == entry.getValue()) {
                presenterCache.remove(entry.getKey());
                continue;
            }
            if (!entry.getValue().isEffective() && !entry.getKey().equals(localClassPath)) {
                presenterCache.remove(entry.getKey());
            }
        }
        if (presenterCache.containsKey(localClassPath)) {
            return presenterCache.get(localClassPath);
        } else {
            return null;
        }
    }
    /**
     * @param localClassPath packageName + className
     * @param presenter      BasePresenter
     */
    public void addPresenter(String localClassPath, BasePresenter presenter) {
        if (null == localClassPath || null == presenter) {
            return;
        }
        presenterCache.put(localClassPath, presenter);
    }
    // ......
}

3.4.2. Event

Event包提供了EventMessage的基类BaseEvent,定义了eventTagactionTag关键字段,用于区分UI线程以及业务操作,同时定义了T data,T2 data2,T3 data3增加了对Data数据的承载,用于需要传输数据的场景。

按照计划,App所有与mvp相关的消息体,都会继承BaseEvent,为UI线程统一接收消息提供支持,可以大大减少EventMessage类的定义数量,简化代码。

public abstract class BaseEvent {
    /**
     * default action tag for Initialization UI thread
     */
    public static final String ACTION_TAG_INIT_PROCESS = "init_process";
    /**
     * default action tag for Http Response error
     */
    public static final String ACTION_TAG_RESPONSE_ERROR = "network_response_error";
    /**
     * for different UI thread. default value: name of current class
     */
    public String eventTag;
    /**
     * same UI thread, different action
     */
    public String actionTag;
    /**
     * extra data
     */
    public T data;
    /**
     * extra data
     */
    public T2 data2;
    /**
     * extra data
     */
    public T3 data3;

    protected abstract String returnThreadTag();

    protected abstract String returnActionTag();

    public BaseEvent() {
        init();
    }

    public BaseEvent(T data) {
        this.data = data;
        init();
    }

    public BaseEvent(T data, T2 data2) {
        super();
        this.data = data;
        this.data2 = data2;
        init();
    }

    public BaseEvent(T data, T2 data2, T3 data3) {
        super();
        this.data = data;
        this.data2 = data2;
        this.data3 = data3;
        init();
    }

    private void init() {
        eventTag = returnThreadTag() == null ? getClass().getPackage() + getClass().getSimpleName() : returnThreadTag();
        actionTag = returnActionTag() == null ? ACTION_TAG_INIT_PROCESS : returnActionTag();
    }
}

3.5. M层

Module对应业务数据管理,是按照数据业务划分的(一个Module对应并管理多个Model(数据Bean,可以理解为接口,网络接口,数据库接口等))。

无论对于功能型mvp架构(mvp作为顶层节点,每个M,V,P中进行业务模块划分)而言,还是对于业务型mvp架构(业务模块作为顶层节点,每个业务节点中做mvp层次划分)而言,Module就是P的数据管理员(按业务模块划分),P管理业务,Module管理数据,至于Module把业务中涉及到的数据(Model)存到remote还是local,P并不关心。Module管理当前业务模块中各个Model(Bean)的存储;Repository负责对数据在对象与存储介质之间进行校验,封装,转换(可有可无)。

结构说明:P ——> Module ->(Repository ->)(LoginModel –> net,RegisterModel -> local)

Module将被设计为数据存储层(Model)向上层业务逻辑层(Presenter)提供服务的入口(外观)。并负责协调Data Repository,管理并加工业务数据。

Base Library对Module的封装比较简单,按照MP以接口调用及回调的设计思想,BaseModule做了如下封装:

(1)缓存数据回调Observers

/**
 * model callback observer
 */
private Map modelChangeObserver;

说明一下:数据回调的Observer是针对Model(数据)的,不是针对P的,所以一个P中可能会向Module注册多个Observer用于接收不同的类型的Model。

(2)对P回调接口的注册解注:

    /**
     * add
     *
     * @param modelClass    model class
     * @param modelObserver observer
     */
    public  BaseModule addModelObserver(Class modelClass, IModelObserver modelObserver) {
        if (null == modelChangeObserver) {
            modelChangeObserver = new HashMap<>();
        }

        if (!modelChangeObserver.containsKey(modelClass)) {
            modelChangeObserver.put(modelClass, modelObserver);
        }
        return this;
    }

    /**
     * remove
     *
     * @param modelClass model class
     */
    public  void removeModelObserver(Class modelClass) {
        if (modelChangeObserver.containsKey(modelClass)) {
            modelChangeObserver.remove(modelClass);
        }
    }

P中初始化Module时,根据P负责处理的业务,把对应不同Model(数据)的回调接口注册给Module。

(3)按照Model类型做数据以及异常回调

@SuppressWarnings("unchecked")
@Override
public  void notifyModelObserver(Class modelClass, T... models) {
    if (modelChangeObserver.containsKey(modelClass)) {
        modelChangeObserver.get(modelClass).onNotify(models);
    }
}
@SuppressWarnings("unchecked")
@Override
public  void notifyErrorObserver(Class modelClass, E e) {
    if (modelChangeObserver.containsKey(modelClass)) {
        modelChangeObserver.get(modelClass).onError(e);
    }
}

Module子类中,针对业务需求扩展获取Model(数据)的方法,获取Model(数据)后,调用notifyModelObserver方法把数据回传给P。

(4)定义数据回调接口

    /**
     * @author Created by qiang.hou on 2018/5/9.
     * @version 1.0
     */
    public interface IModelObserver {
        void onNotify(T... data);
    }

4,GlobalField

静态全局参数,默认配置参数等,不做赘述

public class GlobalField {
    public static final String SHARED_PREFERENCE_NAME = "default_shared_preference";

    public static final long PRESENTER_CACHE_TIME = 20;
}

总结

Base Library是一个android库,也是一个完整的android工程,其他主工程app1,app2,app3需要添加Base Library工程依赖。

mvp是一种设计思想,致力于层级解耦,但它也只是一种架构思想,具体实现不应被mvp固定模式所束缚。

Base Library可优化的方向(仅供参考)

1,按照业务逻辑而非UI逻辑划分P,实现PV多对多,实现对P的充分复用。

2,Module与Model之间,增加Repository,用于对原始数据(remote,localDB)的业务性加工处理。

3,放大EventBus消息机制的使用范围,目前只用于P—>V业务回调部分。

 

最后,好抢手是子弹喂出来的,好coding是代码练出来的,Lib中涉及到的关键代码(基本上是所有)都已贴出,真正有兴趣的不妨整理优化一下,欢迎交流心得体会。     

源码:https://gitee.com/sky_dreaming/App_M/tree/library/library_base

 

 

你可能感兴趣的:(架构设计)