大家都清楚由于onReceive()函数是由进程的主线程调用的,生命期在10s左右,如果遇上了耗时操作,官网的BroadcastReceiver中onReceive(context,intent)部分建议如下:
in particular, for interacting with services, you should use startService(Intent) instead of bindService(Intent, ServiceConnection, int). If you wish to interact with a service that is already running, you can use peekService(Context, Intent)
就是说涉及到跟service交互的话,不要用bindService方法,因为可能binder对象还没返回回来这个receiver就killed掉了。建议使用peekService(context,intent)方法,这个方法还是比较少用到的,也不清楚这个函数返回的Ibinder对象来自于哪儿。所以下面写了个demo来看看这个peekService怎么用.
从官网提供来看:
Provide a binder to an already-running service. This method is synchronous and will not start the target service if it is not present, so it is safe to call from onReceive(Context, Intent).
可见我们在调用peekService前需要保证intent参数内的service是一个已经启动的service,peekService是一个同步的操作,所以在onReceive函数内部执行时安全的。
写了一个小demo如下:
当我触发sendBroadcast()函数后,打印的内容如下
E/MyService: onCreate()
E/MyService: onBind()…//停止13s
E/MyService: 13s已经过去了,但是onReceive函数依旧可以接收任务返回的结果
可见在onReceive 函数里调用peekService函数并没有再次调用已经启动的service的onBind()函数。那么在peekService函数这个binder是如何不调用onBind()而获取到的呢?
我尝试看源码
1234567891011 public IBinder peekService(Context myContext, Intent service) {IActivityManager am = ActivityManagerNative.getDefault();IBinder binder = null;try {service.prepareToLeaveProcess();binder = am.peekService(service, service.resolveTypeIfNeeded(myContext.getContentResolver()), myContext.getOpPackageName());} catch (RemoteException e) {}return binder;}
到了am.peekService()这里就无法继续的深入寻找原理,很惭愧。还请大神们多多指教!!!
更新:good tips for this problem
提示我们需要注意,如果再次启动这个service导致执行的是reStart()那么MyService.MyBinder binder = (MyService.MyBinder) peekService(context, intent1);返回的binder就是一个null对象,因为跳过了onBind()函数,无法生成一个binder.