定制Android系统开发之十——优化系统服务中的回调

上一篇博文中,实现了简单的系统服务的回调。在这个简单化的实例中,回调有如下几个明显的缺点:

  1. 只支持注册一个listener。
  2. 注销的时候不能指定注销的listener。
  3. 回调的时候可能会因为APP没有及时处理导致服务卡住。

在这篇博文中,我们将逐步解决这几个问题。

SystemManager中的注册与注销

我们先来看一下上一篇博文中所实现的SystemManager中的注册函数与注销函数:

/**
 * 注册回调。
 * 
 * @param listener
 * @return 成功返回0,失败请参考错误码ErrorCode
 */
public int registerListener(SystemManagerListener listener) {
    try {
        SystemManagerListenerTransfer transfer = new SystemManagerListenerTransfer(listener);
        return mService.registerListener(transfer);
    } catch (RemoteException e) {
        e.printStackTrace();
        return SystemManagerCons.ErrorCode.ERROR_REMOTE_EXCEPTION;
    }
}

/**
 * 注销回调。
 * 
 * @param listener 回调。
 * @return 注销成功返回0,否则返回ErrorCode。
 */
public int unregisterListener() {
    try {
            return mService.unregisterListener();
        }
    } catch (RemoteException e) {
        e.printStackTrace();
        return SystemManagerCons.ErrorCode.ERROR_REMOTE_EXCEPTION;
    }
}

在注册函数中,我们是用SystemManagerListener构造了一个SystemManagerListenerTransfer并将这个Transfer传入了Service,那么,在注销的时候,如果我们又new一个SystemManagerListenerTransfer并传入Service,那么对于Service来说,两次传入的是两个对象,无法进行正确的注销。

所以,我们需要将第一次new出来的Transfer缓存下来,当需要注销的时候,根据Listener查找对应的Transfer传入Service进行注销即可。为了快速查询,我们是用java中的map。代码如下:

// 声明一个HashMap对象来缓存new出来的Transfer。
private HashMap<SystemManagerListener, SystemManagerListenerTransfer> mCachedSystemManagerListener;

public SystemManager(Context context, ISystemManager service) {
    mContext = context;
    mService = service;
    // 初始化这个HashMap。
    this.mCachedSystemManagerListener = new HashMap<SystemManagerListener, SystemManagerListenerTransfer>();
}

/**
 * 注册回调。
 * 
 * @param listener
 * @return 成功返回0,失败请参考错误码ErrorCode
 */
public int registerListener(SystemManagerListener listener) {
    Log.d(TAG, "registerListener() is called");
    if (mService == null) {
        Log.d(TAG, "mService is null, return.");
        return SystemManagerCons.ErrorCode.ERROR_SERVICE_NULL;
    }

    // 检查非空。
    if (listener == null) {
        Log.d(TAG, "listener is null, error.");
        return SystemManagerCons.ErrorCode.ERROR_NULL_OBJECT;
    }

    // 检查是否为重复注册。
    if (this.mCachedSystemManagerListener.containsKey(listener)) {
        Log.d(TAG, "this listener is already registered");
        return SystemManagerCons.ErrorCode.ERROR_LISTENER_ALREADY_REGISTERED;
    }

    try {
        SystemManagerListenerTransfer transfer = new SystemManagerListenerTransfer(listener);
        // 把new出来的Transfer缓存下来。
        this.mCachedSystemManagerListener.put(listener, transfer);
        return mService.registerListener(transfer);
    } catch (RemoteException e) {
        e.printStackTrace();
        return SystemManagerCons.ErrorCode.ERROR_REMOTE_EXCEPTION;
    }
}

/**
 * 注销回调。
 * 
 * @param listener 回调。
 * @return 注销成功返回0,否则返回ErrorCode。
 */
public int unregisterListener(RadioManagerListener listener) {
    Log.d(TAG, "unregisterListener() is called");
    if (mService == null) {
        Log.d(TAG, "mService is null, return.");
        return SystemManagerCons.ErrorCode.ERROR_SERVICE_NULL;
    }

    // 检查非空
    if (listener == null) {
        Log.d(TAG, "listener is null, error.");
        return SystemManagerCons.ErrorCode.ERROR_NULL_OBJECT;
    }

    try {
        // 在缓存中根据Listener查找Transfer
        SystemManagerListenerTransfer transfer = this.mCachedSystemManagerListener
                .remove(listener);
        if (transfer == null) { // 如果还没有被注册过
            Log.d(TAG, "listener has not been registered ye");
            return SystemManagerCons.ErrorCode.ERROR_LISTENER_NOT_REGISTERED;
        } else {
            return mService.unregisterListener(transfer);
        }
    } catch (RemoteException e) {
        e.printStackTrace();
        return SystemManagerCons.ErrorCode.ERROR_REMOTE_EXCEPTION;
    }
}

SystemManagerService中的注册与注销

要在SystemManagerService中支持同时注册多个Listener,就需要维护一个Listener的列表,注册的时候,将Listener加入这个列表中,注销的时候,将Listener从列表中删掉就行了。代码如下:

// 声明这个List。
private List<ISystemManagerListener> mSystemManagerListenerList;

// 在Service的构造函数里初始化List
public SystemManagerService(Context context) {
    this.mContext = context;
    this.mSystemManagerListenerList = new LinkedList<ISystemManagerListener>();
}

@Override
public int registerListener(ISystemManagerListener listener) throws RemoteException {
    Log.d(TAG, "registerListener() is called");
    if (mSystemManagerListenerList.contains(listener)) { // 已经注册过
        Log.d(TAG, "this listener has already been registered");
        return SystemManagerCons.ErrorCode.ERROR_LISTENER_ALREADY_REGISTERED;
    } else {
        mSystemManagerListenerList.add(listener);
        return SystemManagerCons.ErrorCode.ERROR_NO_ERROR;
    }
}

@Override
public int unregisterListener(ISystemManagerListener listener) throws RemoteException {
    Log.d(TAG, "unregisterListener() is called");
    if (mSystemManagerListenerList.remove(listener)) {
        return SystemManagerCons.ErrorCode.ERROR_NO_ERROR;
    } else {
        return SystemManagerCons.ErrorCode.ERROR_LISTENER_NOT_REGISTERED;
    }
}

调用过程的优化

在APP实现的Listener中,实现的函数有可能会有一些耗时的操作,如果我们直接调用这些函数,将导致服务的主线程被阻塞,这显然是不合理的。所以我们需要使用一个子线程来完成调用APP的Listener中函数的任务。为了方便主线程与子线程之间的交互,我们使用一个HandlerThread即可。HandlerThread的使用方法在拙作 Thread、Handler与HandlerThread 里已经提到过,这里直接贴出代码:

private SystemHandlerThread mSystemHandlerThread;
private Handler threadHandler;

public SystemManagerService(Context context) {
    this.mContext = context;
    this.mSystemManagerListenerList = new LinkedList<ISystemManagerListener>();

    mSystemHandlerThread = new SystemHandlerThread(TAG);
    mSystemHandlerThread.start();
    threadHandler = new Handler(mSystemHandlerThread.getLooper(), mSystemHandlerThread);
}

public SystemManagerService(Context context) {
    this.mContext = context;
    this.mSystemManagerListenerList = new LinkedList<ISystemManagerListener>();

    mSystemHandlerThread = new SystemHandlerThread(TAG);
    mSystemHandlerThread.start();
    threadHandler = new Handler(mSystemHandlerThread.getLooper(), mSystemHandlerThread);
}

private class SystemHandlerThread extends HandlerThread implements Callback {

    public SystemHandlerThread(String name) {
        super(name);
    }

    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            default:
            case MSG_PROGRESS:
                precessProgress(msg.arg1);
                break;
        }
        return true;
    }

    private void precessProgress(int progress) {

    }
}

当从jni中收到数据之后,像下面这样发送一个消息给HandlerThread即可。

threadHandler.obtainMessage(MSG_PROGRESS, progress, 0).sendToTarget();

在HandlerThread的precessProgress()函数中,在正常的情况下,只需要遍历Listener的List,依次调用Listener的onProgress()函数即可,但是如果一个APP退出了(有可能是异常导致崩溃),但是没有主动去调用注销Listener的函数,那么这个Listener的List中依然会有这个APP的Listener。在这种情况下,我们调用其onProgress()函数会发生什么呢?答案是会发生RemoteException。所以我们需要在发生RemoteException的时候,将这个Listener从List中删掉,就能防止这个List无限制增长。另外,在遍历的过程中改变List的元素也有一些小的技巧。代码如下:

private void precessProgress(int progress) {
    for (Iterator<ISystemManagerListener> it = mSystemManagerListenerList.iterator(); it
            .hasNext();) {

        ISystemManagerListener l = it.next();
        try {
            l.onProgress(progress);
        } catch (RemoteException e) {
            Log.d(TAG, "RemoteException occured when call onScanFrequency");
            it.remove();
        }
    }
}

至此,就解决了本文开头提到的三个问题。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值