在Activity中registeReceiver或者bindService,如果Activity销毁时还没进行unregisterReceiver或者unbindService,就会出现如下错误:
1、未调用unregisterReceiver:android.app.IntentReceiverLeaked: Activity xxxxx has leaked
2、未调用unbindService:android.app.ServiceConnectionLeaked: Activity xxxxx has leaked
出现这两个错误的原因是:Activity在退出后会调用onDestroy方法,然后会释放一些资源,流程如下:
最终运行LoadedApk.removeContextRegistrations,该方法就是用来实现Receiver和Service的泄漏处理。
在Activity.finish后如果没有调用unregisterReceiver,就会出现泄漏。其中mReceivers是当前App注册的所有Receiver,在如果rmap不为空,且size大于0,说明Activity对应的Context中的Receiver还没有回收,Receiver会引用Activity,Activity就存在Leak。那么mReceiver中的值是哪里来的呢?答案就是regeisterReceiver函数,流程如下:
在注册广播的时候调用LoadedApk.getReceiverDispatcher会将BroadcastReceiver存储到mReceiver中,unRegisterReceiver会通过forgetReceiverDispatcher将BroadcastReceiver从mReceiver中移除,如果没有unRegisterReceiver,在退出Activity就会出现android.app.IntentReceiverLeaked: Activity xxxxx has leaked错误。
如果smap中Activity的Context对应的ServiceDispatcher不为空,说明Activity在调用bindService后没有主动调用unbindService,而ServiceConnectin会引用Activity,Activity就会存在Leak。流程和Receiver类似:
bindService或调用LoadedApk.getServiceDispatcher将ServiceDispatcher加入mService中,unbindService通过forgetServiceDispatcher将ServiceDispatcher进行移除。如果不调用unbindService就会出现Activity Leak。
但是在APP运行的时候并没有出现Crash,是因为LoadedApk.removeContextRegistrations只是打印了泄漏信息,之后会再次调用AMS的unregisterReceiver或者unbindService。
因此,Receiver和bindService可以实现和Activity生命周期的联动。