从mms源码看IM应用的架构<二>

本文探讨了Android即时通讯应用mms如何利用Action和IntentService架构处理后台任务。Action作为耗时任务的逻辑载体,IntentService负责在单独线程中执行任务。ActionMonitor则维护Action的状态,便于与外界交互。该架构使得复杂的后台任务管理变得有序。
摘要由CSDN通过智能技术生成

Action+ IntentService架构

  这一部分给大家总结一下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,包括DeleteConversationActionDeleteMessageAction

DownloadMmsActionDumpDatabaseActionHandleLowStorageActionMarkAsReadActionReceiveSmsMessageActionUpdateMessagePartSizeAction等。这些纷繁的后台任务因为有了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源码。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值