今天来学习下广播onReceive()方法的context类型探究:
出于安全原因的考虑,Android是不允许Activity或者Dialog凭空出现的,一个Activity的启动必须建立在另一个Activity的基础之上,也就是形成返回栈。而普通Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog),因此在这种场景下,我们只能使用Activity类型的context。否则将会出错。
非Acticity类型的context并没有所谓的任务栈。
1 静态注册的广播,其onReceive()方法里的context类型
静态注册广播,如果没有声明android:process,那么BroadcastReceiver和Activity是在同一个进程的(其实废话,android:process是声明其他进程唯一方式,否则就是包名命名)
我们可以看到此时onReceive方法的context是android.app.ReceiverRestrictedContext类型,我们可以查看源码看下:它是继承ContextWrapper类的。
2 动态广播
因此:静态注册时onReceive方法的context不是Activity类型,而是ReceiverRestrictedContext类型。动态注册时广播里的onReceive方法的context来自Activity。
在onReceive方法的解释中,我们可以理解几个点。
不要在广播的onReceive方法中执行耗时操作(因为在主线程中运行的),也不远添加过多的逻辑,也不允许在这里面开子线程(下面解释)。当onReceive运行时间超过10s而没有结束,会报ANR。广播接收器的作用用于打开其他组件。
至于为啥不允许在广播接收器中开启线程:
对于静态注册的广播接收器而言,广播接收器的生命周期较短,执行完onReceive()方法会变成垃圾对象而被回收,在子线程执行完之前,若对应的Activity退出,他们所在进程就变成了空进程(没有任何活动组件的进程),系统需要内存时可能会优先终止该进程,进程被终止,其内的子线程也会被终止,导致子线程的任务代码无法执行完。
对于动态注册的广播接收器而言,Activity退出时会调用unregisterReceiver()方法进行反注册,此时广播接收器也会变成垃圾对象而被回收。在子线程执行完之前,对应的Activity退出,同样他们所在进程也会变成空进程,其内的子线程也无法执行完。
如果必须执行耗时任务 可以考虑在里面开启Service来执行,系统就会认为这个进程里还有其他活动组件在运行,就不会任意时刻回收此进程。