我是靠谱客的博主 英勇发卡,这篇文章主要介绍Android工程架构设计:Base Library(基层MVP框架)基于EventBus1,IApplication(接口):2,BaseApplication(抽象基类)3,mvp(基层mvp架构)4,GlobalField总结,现在分享给大家,希望可以做个参考。

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

目录

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中实现。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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(抽象基类)

复制代码
1
public abstract class BaseApplication extends MultiDexApplication implements IApplication

BaseApplication需要做四件事情:

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override public void onCreate() { super.onCreate(); INSTANCE = this; registerActivityLifecycleCallbacks(this); /* * 组件化框架使用,非组件化无用 */ initModules(); /* * 组件化框架使用,非组件化无用 */ initRouter(); initNetworkConfig(); initSharedPreference(defineSharedPreferenceName()); initOtherConfig(); /* * 组件化框架调用组件生命周期,非组件化无用 */ ModuleRouter.getInstance().onModulesCreate(defineModulesNeedManagedByModuleName()); }

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

复制代码
1
2
3
4
5
6
7
8
9
@Override public void initModules() { ModuleRouter.getInstance().loadModules(this); } @Override public void initSharedPreference(String sharedName) { SharedUtils.initInstance(getApplicationContext(), sharedName); }

2.3 Application关键方法

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@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。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@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 定义与公共行为相关的抽象方法(具体行为),供子类扩展

复制代码
1
2
3
4
5
6
protected abstract String defineSharedPreferenceName(); /** * define modules which need managed in Application lifecycle(组件化使用) */ protected abstract String[] defineModulesNeedManagedByModuleName(); // other methods ...

2.5 缓存管理Activity

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/** * app有效activity缓存 */ private List<WeakReference<Activity>> activityList = new ArrayList(); /** * app当前activity缓存 */ private List<WeakReference<Activity>> 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> 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<Activity> activityClass) { for (WeakReference<Activity> 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<Activity> weakReference = (WeakReference<Activity>) 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<Activity> weakReference = (WeakReference<Activity>) 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消息机制替换之前的接口回调机制

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线程不同类型的逻辑操作(登录,忘记密码,找回密码,刷新列表等操作类型)。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public abstract class BaseEvent<T, T2, T3> { /** * 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进行行为分发,区别响应。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public abstract class BaseActivity<P extends BasePresenter> extends Activity implements Contract.IView { // …………………… /** * receive Event Message * @param event BaseEvent * @param <E> BaseEvent */ @Subscribe @Override public <E extends BaseEvent> 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接收处理。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/** * Init data and refresh view * @param event BaseEvent * @param <E> BaseEvent */ protected <E extends BaseEvent> void initDataView(E event){} /** * receive and handle EventBus message * @param event BaseEvent * @param <E> BaseEvent */ protected abstract <E extends BaseEvent> void onHandleMessage(E event);

优势:

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

争议:

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

复制代码
1
public <E extends BaseEvent> void onEventMessageReceive(E event)

是否会影响性能呢?

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

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
public abstract class BaseActivity<P extends BasePresenter> extends library.base.mvp.v.activity.BaseActivity<P> { // ...... @Override protected <E extends BaseEvent> void initDataView(E event) { } @Override protected <E extends BaseEvent> void onHandleMessage(E event) { } // ...... }

3.1.2.增加对P的缓存管理

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

复制代码
1
2
3
4
/** * cache:packageName + className(V) : Presenter */ private LinkedHashMap<String, BasePresenter> 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定义了数据以及异常回调接口。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/** * @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 <E extends BaseEvent> 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 */ <T> void addModelObserver(Class<T> modelClass, IModelObserver modelObserver); /** * remove * * @param modelClass model class */ <T> void removeModelObserver(Class<T> modelClass); /** * call the notify method with model data * * @param modelClass model class * @param models data */ <T> void notifyModelObserver(Class<T> modelClass, T... models); /** * call the notify method with model data * * @param modelClass model class * @param e Exception */ <T, E extends Throwable> void notifyErrorObserver(Class<T> modelClass, E e); /** * @author Created by qiang.hou on 2018/5/9. * @version 1.0 */ interface IModelObserver<T, E extends Throwable> { 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)

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 跟踪打印当前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方法供子类扩展

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/** * Init views */ protected abstract void initView(); /** * receive and handle EventBus message * @param event BaseEvent * @param <E> BaseEvent */ protected abstract <E extends BaseEvent> 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的创建和绑定以及解绑

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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();

复制代码
1
2
3
4
5
6
public void unregisterPresenter() { if (null != mPresenter) { mPresenter.unRegisterViewEvent(getSimpleTag()); } unregisterEventBus(); }

(4)开放通用行为

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Subscribe @Override public <E extends BaseEvent> 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标识(包名 + 类名)

复制代码
1
2
3
4
public String getSimpleTag() { return getPackageName() + this.getClass().getSimpleName(); }

跳转到指定页面

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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封装策略的基础上,加了懒加载机制:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@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唯一标识的缓存列表

复制代码
1
2
3
4
5
/** * cache event tag */ private List<String> eventTagCache = new ArrayList<>();

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/** * 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的缓存提供策略依据。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
/** * 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消息接口

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/** * @param data data * @param aTag action tag * @param <T> data type */ public <T> void postEvent(T data, final String aTag) { for (String eventTag : eventTagCache) { final String viewTag = eventTag; EventBus.getDefault().post(new BaseEvent<T, T, T>(data) { @Override protected String returnThreadTag() { return viewTag; } @Override protected String returnActionTag() { return aTag; } }); } } /** * @param data data * @param aTag action tag * @param <T> data type */ public <T> void postStickyEvent(T data, final String aTag) { for (String eventTag : eventTagCache) { final String viewTag = eventTag; EventBus.getDefault().postSticky(new BaseEvent<T, T, T>(data) { @Override protected String returnThreadTag() { return viewTag; } @Override protected String returnActionTag() { return aTag; } }); } } /** * @param data data * @param aTag action tag * @param <T> data type * @param <T2> data type */ public <T, T2> void postEvent(T data, T2 data2, final String aTag) { for (String eventTag : eventTagCache) { final String viewTag = eventTag; EventBus.getDefault().post(new BaseEvent<T, T2, T>(data, data2) { @Override protected String returnThreadTag() { return viewTag; } @Override protected String returnActionTag() { return aTag; } }); } } /** * @param data data * @param aTag action tag * @param <T> data type * @param <T2> data type */ public <T, T2> void postStickyEvent(T data, T2 data2, final String aTag) { for (String eventTag : eventTagCache) { final String viewTag = eventTag; EventBus.getDefault().postSticky(new BaseEvent<T, T2, T>(data, data2) { @Override protected String returnThreadTag() { return viewTag; } @Override protected String returnActionTag() { return aTag; } }); } } /** * @param data data * @param aTag action tag * @param <T> data type * @param <T2> data type * @param <T3> data type */ public <T, T2, T3> void postEvent(T data, T2 data2, T3 data3, final String aTag) { for (String eventTag : eventTagCache) { final String viewTag = eventTag; EventBus.getDefault().post(new BaseEvent<T, T2, T3>(data, data2, data3) { @Override protected String returnThreadTag() { return viewTag; } @Override protected String returnActionTag() { return aTag; } }); } } /** * @param data data * @param aTag action tag * @param <T> data type * @param <T2> data type * @param <T3> data type */ public <E extends BaseEvent, T, T2, T3> void postStickyEvent(T data, T2 data2, T3 data3, final String aTag) { for (String eventTag : eventTagCache) { final String viewTag = eventTag; EventBus.getDefault().postSticky(new BaseEvent<T, T2, T3>(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> E extends BaseEvent */ public <E extends BaseEvent> 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 <E extends BaseEvent> void postEvent(E event) { EventBus.getDefault().post(event); } /** * @param event E extends BaseEvent */ public <E extends BaseEvent> void postStickyEvent(E event) { EventBus.getDefault().postSticky(event); }

(2)PresenterManager

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

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class PresenterManager implements Contract.IPresenterManager { /** * cache */ private LinkedHashMap<String, BasePresenter> presenterCache = new LinkedHashMap<>(); // ...... /** * @param localClassPath packageName + className * @return BasePresenter */ public BasePresenter getPresenter(String localClassPath) { /* * clear Invalid presenter */ for (Map.Entry<String, BasePresenter> 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类的定义数量,简化代码。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public abstract class BaseEvent<T, T2, T3> { /** * 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

复制代码
1
2
3
4
/** * model callback observer */ private Map<Class, IModelObserver> modelChangeObserver;

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

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/** * add * * @param modelClass model class * @param modelObserver observer */ public <T> BaseModule addModelObserver(Class<T> 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 <T> void removeModelObserver(Class<T> modelClass) { if (modelChangeObserver.containsKey(modelClass)) { modelChangeObserver.remove(modelClass); } }

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

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@SuppressWarnings("unchecked") @Override public <T> void notifyModelObserver(Class<T> modelClass, T... models) { if (modelChangeObserver.containsKey(modelClass)) { modelChangeObserver.get(modelClass).onNotify(models); } } @SuppressWarnings("unchecked") @Override public <T, E extends Throwable> void notifyErrorObserver(Class<T> modelClass, E e) { if (modelChangeObserver.containsKey(modelClass)) { modelChangeObserver.get(modelClass).onError(e); } }

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

(4)定义数据回调接口

复制代码
1
2
3
4
5
6
7
8
/** * @author Created by qiang.hou on 2018/5/9. * @version 1.0 */ public interface IModelObserver<T> { void onNotify(T... data); }

4,GlobalField

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

复制代码
1
2
3
4
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

 

 

最后

以上就是英勇发卡最近收集整理的关于Android工程架构设计:Base Library(基层MVP框架)基于EventBus1,IApplication(接口):2,BaseApplication(抽象基类)3,mvp(基层mvp架构)4,GlobalField总结的全部内容,更多相关Android工程架构设计:Base内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(76)

评论列表共有 0 条评论

立即
投稿
返回
顶部