前言

在android中,播送也是咱们经常运用的组件,但是由于大部分运用场景简略,所以关注不多,今天就让咱们来探索一下Broadcast。

注册

这个是常识了,两种注册方式:静态注册(menifast)和动态注册,不展开说了。

这儿注意动态注册后,咱们一般会手动进行刊出,不过假如没有手动刊出,当context目标被毁掉时,Broadcast会主动刊出,但是咱们仍是及时刊出开释资源。

线程及ANR

默认Broadcast都是运行在主线程,并且android对它的运行(onReceive)有一个时刻约束——10秒,即ANR时刻,所以不要在onReceive履行耗时操作。

但是Broadcast其实能够运行在其他线程(这时分就没有时刻约束了),但是有必要是动态注册才能够,Context的registerReceiver其实是一系列函数,其间就有

public abstract Intent registerReceiver(BroadcastReceiver receiver,
            IntentFilter filter, @Nullable String broadcastPermission,
            @Nullable Handler scheduler)

这儿能够传入一个Handler,这个Handler就能够是其他线程创立的,这样就能够在其他线程运行Broadcast。

官方说明如下:

This method is always called within the main thread of its process, unless you

explicitly asked for it to be scheduled on a different thread using
{@link android.content.Context#registerReceiver(BroadcastReceiver, IntentFilter, String, android.os.Handler)}. When it runs on the main
thread you should
never perform long-running operations in it (there is a timeout of
10 seconds that the system allows before considering the receiver to
be blocked and a candidate to be killed). You cannot launch a popup dialog
in your implementation of onReceive().

那么既然onReceive中不能履行耗时操作,咱们是否能够在onReceive中敞开一个新的线程来处理?

在onReceive中敞开新的线程,由于与其生命周期有关,所以下面与生命周期一起来说。

生命周期

Broadcast生命周期很简略,只要onReceive,当它在履行onReceive时是活泼状况,当履行完成则处于失活状况。依据网上资料:

具有一个活泼状况的播送接收器的进程被维护起来而不会被杀死,但仅具有失活状况组件的进程则会在其它进程需要它所占有的内存的时分随时被杀掉。

而依据Broadcast的官方文档,当onReceive履行完这个Broadcast目标不再是alive状况,所以能够随时被收回毁掉。所以不能在onReceive中进行异步操作,即敞开新的线程,由于当onReceive履行完处于失活状况,它和这个新的线程可能随时被毁掉,导致不行估计的程序问题。假如想在onReceive中履行一些异步操作,那么能够运用JobService,或者service。官方文档如下:

If this BroadcastReceiver was launched through a <receiver> tag,
then the object is no longer alive after returning from this
function.
This means you should not perform any operations that
return a result to you asynchronously. If you need to perform any follow up
background work, schedule a {@link android.app.job.JobService} with
{@link android.app.job.JobScheduler}.

If you wish to interact with a service that is already running and previously
bound using {@link android.content.Context#bindService(Intent, ServiceConnection, int) bindService()},
you can use {@link #peekService}.

所以说当Broadcast履行完onReceive后就能够随时被毁掉了,当然动态注册不一样,由于它是手动创立的,所以还需要关心它的引证可达性。

一起,Broadcast的创立也一样,动态注册的时分咱们手动创立,所所以一个目标。

而静态注册的时分,应该与activity等组件相似,(binder机制中)先经过intent条件查找创立Broadcast目标,经过测试每次都是重新创立。比方咱们在menifast中静态注册一个Broadcast,然后经过一个按钮发送这个播送,在Broadcast的onReceive中打印自己的目标的toString,发现每次点击都是一个新的目标来履行。所以给Broadcast设置类变量,避免重复接收不会起作用,由于每次都是一个新的目标。

假如在onReceive中履行耗时操作,如下:

public class MyBroadcast extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e("ssss", this.toString() + ":start");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.e("ssss", this.toString() + ":end");
    }
}

再重复点击按钮发送播送,就会发现这些播送会按次序履行,当上一个履行完才开始履行下一个(由于是在一个线程中)。