从mms源码看IM应用的架构<二>
2016-07-14 17:35
363 查看
Action+ IntentService架构
这一部分给大家总结一下mms里面对于后台任务的处理。正常情况下,一个互联网应用可能会涉及到n多的后台任务要运行,短信应用也不例外,例如插入短信到数据库,删除短信,标记为已读,发送短信,接收短信,下载彩信等。这些都是耗时任务,并且他们之间有些还有先后顺序要求,如果没有一个良好的后台任务管理框架,拿维护起来可就要了亲命了。
这里我们就来看一下mms应用中的“Action+IntentService架构”是怎么解决这个问题的。
先简单看一下Action:
我们再来以短信发送过程为例来说明:
这个过程涉及到两个Action,InsertNewMessageAction和SendMessageAction,分别对应的是将短信插入数据库和真正发送的过程,都是耗时任务,所以都需要Action来处理。在这里我们就看到SendMessageAction需要在InsertNewMessageAction之后执行,所以被放在了mBackgroundActions中了。
而实际上,我统计了一下,整个mms应用中有大概30个Action,包括DeleteConversationAction、DeleteMessageAction、
DownloadMmsAction、DumpDatabaseAction、HandleLowStorageAction、MarkAsReadAction、ReceiveSmsMessageAction、UpdateMessagePartSizeAction等。这些纷繁的后台任务因为有了Action架构,就显得不那么乱了。
再来看一下IntentService.
Action本身只是一个后台任务逻辑载体,并没有维护线程来执行任务,所以真正的任务执行是在IntentService里面。有经验的Android工程师应该都知道IntentService,因为Service本身是运行在UI Thread中的,所以一般我们执行后台任务都要再单独开线程,而Android框架为了方便,直接又封装了一个带Thread的Service,即IntentService。并且IntentService是即用即销毁,所以我们连生命周期都不要维护,只需要实现它的onHandleIntent方法执行自己的后台逻辑即可。
我们来看一下在mms源码中对IntentService的使用:
另外,ActionMonitor也值得一说
每一个Action对应一个ActionMonitor,用于维护Action所处于的状态,这样就可以在每个状态与外界交互,比如在Action执行完之后回调onActionSucceeded方法。
当然,这里都是抽丝剥茧的说了一下整个架构,而具体的细节其实还有很多,包括各种执行失败的处理交互,各种任务的前后关联,这里面内容还是比较多的,但限于篇幅这里就不展开了,感兴趣的同学可以直接查看mms源码。
这一部分给大家总结一下mms里面对于后台任务的处理。正常情况下,一个互联网应用可能会涉及到n多的后台任务要运行,短信应用也不例外,例如插入短信到数据库,删除短信,标记为已读,发送短信,接收短信,下载彩信等。这些都是耗时任务,并且他们之间有些还有先后顺序要求,如果没有一个良好的后台任务管理框架,拿维护起来可就要了亲命了。
这里我们就来看一下mms应用中的“Action+IntentService架构”是怎么解决这个问题的。
先简单看一下Action:
public abstract class Action implements Parcelable { .......................................... public void start() { DataModel.startActionService(this); } //该Action要执行的具体后台任务放在这里,该方法需要我们继承的 //Action子类实现 protected Object executeAction() { return null; } .......................................... //需要在该Action之后执行的Action放到mBackgroundActions中,在该Action执行完 //之后会将这些mBackgroundActions取出来执行 private final List<Action> mBackgroundActions = new LinkedList<Action>(); protected void requestBackgroundWork(final Action backgroundAction) { LogUtil.i(TAG, "requestBackgroundWork"); mBackgroundActions.add(backgroundAction); } protected Bundle doBackgroundWork() throws DataModelException { return null; } .......................................... }我们大致上就可以了解Action是什么了?简单的来说,可以理解成一个Runnable,在executeAction方法中是具体的后台任务逻辑,类似于run方法。但显然Action比Runnable复杂一些,多维护了一个mBackgroundActions列表,他是一个List<Action>,维护的是需要在该Action执行之后再执行的Action,当然这些都是由Action对象本身维护和触发,是典型的面向对象的设计。这样的设计无疑给繁杂的后台任务维护指明了一条简单清晰的框架:谁关联谁维护。这样就不需要我们整体上再维护Action队列来决定先后顺序了,是一个非常不错的设计。
我们再来以短信发送过程为例来说明:
这个过程涉及到两个Action,InsertNewMessageAction和SendMessageAction,分别对应的是将短信插入数据库和真正发送的过程,都是耗时任务,所以都需要Action来处理。在这里我们就看到SendMessageAction需要在InsertNewMessageAction之后执行,所以被放在了mBackgroundActions中了。
而实际上,我统计了一下,整个mms应用中有大概30个Action,包括DeleteConversationAction、DeleteMessageAction、
DownloadMmsAction、DumpDatabaseAction、HandleLowStorageAction、MarkAsReadAction、ReceiveSmsMessageAction、UpdateMessagePartSizeAction等。这些纷繁的后台任务因为有了Action架构,就显得不那么乱了。
再来看一下IntentService.
Action本身只是一个后台任务逻辑载体,并没有维护线程来执行任务,所以真正的任务执行是在IntentService里面。有经验的Android工程师应该都知道IntentService,因为Service本身是运行在UI Thread中的,所以一般我们执行后台任务都要再单独开线程,而Android框架为了方便,直接又封装了一个带Thread的Service,即IntentService。并且IntentService是即用即销毁,所以我们连生命周期都不要维护,只需要实现它的onHandleIntent方法执行自己的后台逻辑即可。
我们来看一下在mms源码中对IntentService的使用:
public class ActionServiceImpl extends IntentService { /** *提供一个静态全局方法,方便外界直接对自己实例化 */ private static void startServiceWithIntent(final Intent intent) { final Context context = Factory.get().getApplicationContext(); final int opcode = intent.getIntExtra(EXTRA_OP_CODE, 0); // Increase refCount on wake lock - acquiring if necessary if (VERBOSE) { LogUtil.v(TAG, "acquiring wakelock for opcode " + opcode); } sWakeLock.acquire(context, intent, opcode); intent.setClass(context, ActionServiceImpl.class); // TODO: Note that intent will be quietly discarded if it exceeds available rpc // memory (in total around 1MB). See this article for background // http://developer.android.com/reference/android/os/TransactionTooLargeException.html // Perhaps we should keep large structures in the action monitor? if (context.startService(intent) == null) { LogUtil.e(TAG, "ActionService.startServiceWithIntent: failed to start service for intent " + intent); sWakeLock.release(intent, opcode); } } protected void onHandleIntent(final Intent intent) { if (intent == null) { // Shouldn't happen but sometimes does following another crash. LogUtil.w(TAG, "ActionService.onHandleIntent: Called with null intent"); return; } final int opcode = intent.getIntExtra(EXTRA_OP_CODE, 0); sWakeLock.ensure(intent, opcode); try { Action action; final Bundle actionBundle = intent.getBundleExtra(EXTRA_ACTION_BUNDLE); actionBundle.setClassLoader(getClassLoader()); switch(opcode) { case OP_START_ACTION: { action = (Action) actionBundle.getParcelable(BUNDLE_ACTION); //真正执行Action executeAction(action); break; } case OP_RECEIVE_BACKGROUND_RESPONSE: { action = (Action) actionBundle.getParcelable(BUNDLE_ACTION); final Bundle response = intent.getBundleExtra(EXTRA_WORKER_RESPONSE); processBackgroundResponse(action, response); break; } case OP_RECEIVE_BACKGROUND_FAILURE: { action = (Action) actionBundle.getParcelable(BUNDLE_ACTION); processBackgroundFailure(action); break; } default: throw new RuntimeException("Unrecognized opcode in ActionServiceImpl"); } //执行Action的BackgroundAction action.sendBackgroundActions(mBackgroundWorker); } finally { // Decrease refCount on wake lock - releasing if necessary sWakeLock.release(intent, opcode); } } }我们可以看到,这里封装了一个ActionServiceImpl类用于执行Action,同时在最后会触发Action的backgroundAction也去执行。这里注意一下,backgroundAction是在另一个IntentService即BackgroundWorkerService中执行。不过这里BackgroundWorkerService和ActionServiceImpl除了代码结构规整之外,设计BackgroundWorkerService应该还有一些用处,因为在DeleteMessageAction中有以下注释:
// Doing this work in the background so that we're not competing with sync // which could bring the deleted message back to life between the time we deleted // it locally and deleted it in telephony (sync is also done on doBackgroundWork). // // Previously this block of code deleted from telephony first but that can be very // slow (on the order of seconds) so this was modified to first delete locally, trigger // the UI update, then delete from telephony. @Override protected Bundle doBackgroundWork() { }大致意思是将删除短信的Action放在BackgroundWorkerService中执行,以避开与SyncMessagesAction竞争。但我仔细研究了一下代码也没有发现它怎么避开竞争,这一块还要再研究一下。
另外,ActionMonitor也值得一说
public class ActionMonitor { protected int mState; static void setState(final Action action, final int expectedOldState, final int newState) { int oldMonitorState = expectedOldState; int newMonitorState = newState; final ActionMonitor monitor = ActionMonitor.lookupActionMonitor(action.actionKey); if (monitor != null) { oldMonitorState = monitor.mState; monitor.updateState(action, expectedOldState, newState); newMonitorState = monitor.mState; } ............................................. } public interface ActionCompletedListener { abstract void onActionSucceeded(ActionMonitor monitor, final Action action, final Object data, final Object result); abstract void onActionFailed(ActionMonitor monitor, final Action action, final Object data, final Object result); } }
每一个Action对应一个ActionMonitor,用于维护Action所处于的状态,这样就可以在每个状态与外界交互,比如在Action执行完之后回调onActionSucceeded方法。
当然,这里都是抽丝剥茧的说了一下整个架构,而具体的细节其实还有很多,包括各种执行失败的处理交互,各种任务的前后关联,这里面内容还是比较多的,但限于篇幅这里就不展开了,感兴趣的同学可以直接查看mms源码。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories