Android 四大组件之“ BroadcastReceiver ”

前言

Android四大组件重要性已经不言而喻了,今天谈谈的是Android中的广播机制。在咱们上学的时候,每一个班级的教室里都会装有一个喇叭,这些喇叭都是接入到学校的广播室的,一旦有什么重要的通知,就会播放一条广播来告知全校的师生。相似的工做机制其实在计算机领域也有很普遍的应用,若是你了解网络通讯原理应该会知道,在一个 IP 网络范围中最大的 IP 地址是被保留做为广播地址来使用的。好比某个网络的 IP 范围是 192.168.0.XXX,子网掩码是 255.255.255.0,那么这个网络的广播地址就是 192.168.0.255。 广播数据包会被发送到同一网络上的全部端口,这样在该网络中的每台主机都将会收到这条广播。为了方便于进行系统级别的消息通知,Android 也引入了一套相似的广播消息机制。html

目录

  • 广播机制介绍
  • BroadcastReceiver用法
  • 发送自定义广播
  • 本地广播介绍
  • 广播的注册过程
  • 广播的发送和接受过程
  • 总结

广播机制介绍

为何说 Android中的广播机制更加灵活呢?这是由于 Android中的每一个应用程序均可以对本身感兴趣的广播进行注册,这样该程序就只会接收到本身所关心的广播内容,这些 播多是来自于系统的,也多是来自于其余应用程序的。Android提供了一套完整的 API, 容许应用程序自由地发送和接收广播。接收广播的方法则须要引入一个新的概念,广播接收器(Broadcast Receiver),它就是用来接收来自系统和应用中的广播。java

在Android广播中,主要分为两种类型:标准广播和有序广播。android

标准广播(Normal broadcasts)是一种彻底异步执行的广播,在广播发出以后,全部的 广播接收器几乎都会在同一时刻接收到这条广播消息,所以它们之间没有任何前后顺序可 言。这种广播的效率会比较高,但同时也意味着它是没法被截断的。标准广播的工做流程如图所示。安全

标准广播

有序广播(Ordered broadcasts)则是一种同步执行的广播,在广播发出以后,同一时刻只会有一个广播接收器可以收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。因此此时的广播接收器是有前后顺序的,优先级高的广播接收器就能够先收到广播消息,而且前面的广播接收器还能够截断正在传递的广播,这样后面的广播接收器就没法收到广播消息了。性能优化

有序广播

BroadcastReceiver用法

BroadcastReceiver主要包括两方面的内容,一个是广播的注册过程,另外一个是广播的发送和接收过程。那么该如何建立一个广播接收器呢?其实只须要新建一个类,让它继承自BroadcastReceiver, 并重写父类的 onReceive()方法就好了。这样当有广播到来时,onReceive()方法就会获得执行, 具体的逻辑就能够在这个方法中处理。 广播的使用方法有两个:静态方法和动态方法。网络

动态方法app

public class MainActivity extends Activity {    
  private IntentFilter intentFilter;  
  private NetworkChangeReceiver networkChangeReceiver;  
  
  @Override  
  protected void onCreate(Bundle savedInstanceState) {   
    super.onCreate(savedInstanceState);   
    setContentView(R.layout.activity_main);   
    intentFilter = new IntentFilter();
    intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");  
    networkChangeReceiver = new NetworkChangeReceiver();       
    registerReceiver(networkChangeReceiver, intentFilter);
  }   
  
  @Override 
  protected void onDestroy() {   
    super.onDestroy();  
    unregisterReceiver(networkChangeReceiver);  
  }  
  
  private class NetworkChangeReceiver extends BroadcastReceiver {  
    @Override   
    public void onReceive(Context context, Intent intent) { 
        Toast.makeText(context, "网络变化", Toast.LENGTH_SHORT).show(); 
    }  
 }  
}

能够看到,咱们在 MainActivity 中定义了一个内部类 NetworkChangeReceiver,这个类 是继承自 BroadcastReceiver的,并重写了父类的 onReceive()方法。这样每当网络状态发生变 化时,onReceive()方法就会获得执行,这里只是简单地使用 Toast提示了一段文本信息。框架

而后观察 onCreate()方法,首先咱们建立了一个 IntentFilter 的实例,并给它添加了一个 值为 android.net.conn.CONNECTIVITY_CHANGE 的 action,为何要添加这个值呢?由于 当网络状态发生变化时,系统发出的正是一条值为 android.net.conn.CONNECTIVITY_ CHANGE 的广播,也就是说咱们的广播接收器想要监听什么广播,就在这里添加相应的 action就好了。接下来建立了一个 NetworkChangeReceiver的实例,而后调用 registerReceiver() 方法进行注册,将 NetworkChangeReceiver 的实例和 IntentFilter 的实例都传了进去,这样 NetworkChangeReceiver就会收到全部值为android.net.conn.CONNECTIVITY_CHANGE的广 播,也就实现了监听网络变化的功能。异步

最后要记得,动态注册的广播接收器必定都要取消注册才行,这里咱们是在 onDestroy() 方法中经过调用 unregisterReceiver()方法来实现的。ide

静态方法

动态注册的广播接收器能够自由地控制注册与注销,在灵活性方面有很大的优点,可是 它也存在着一个缺点,即必需要在程序启动以后才能接收到广播,由于注册的逻辑是写在 onCreate()方法中的。那么有没有什么办法可让程序在未启动的状况下就能接收到广播 呢?这就须要使用静态注册的方式了。

这里咱们准备让程序接收一条开机广播,当收到这条广播时就能够在 onReceive()方法里 执行相应的逻辑,从而实现开机启动的功能。新建一个 BootCompleteReceiver 继承自 BroadcastReceiver,代码以下所示

public class BootCompleteReceiver extends BroadcastReceiver {
    @Override  
    public void onReceive(Context context, Intent intent) { 
        Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();  
    }  
}

能够看到,这里再也不使用内部类的方式来定义广播接收器,由于稍后咱们须要在 AndroidManifest.xml中将这个广播接收器的类名注册进去。在 onReceive()方法中,仍是简单 地使用 Toast弹出一段提示信息。

而后修改 AndroidManifest.xml文件,代码以下所示:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"                
  package="com.example.broadcasttest"     
  android:versionCode="1" 
  android:versionName="1.0" >    
    ……     
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />    
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />          
      <application 
        android:allowBackup="true"   
        android:icon="@drawable/ic_launcher"      
        android:label="@string/app_name"     
        android:theme="@style/AppTheme" >  
        <receiver android:name=".BootCompleteReceiver" >       
            <intent-filter>                 
                <action android:name="android.intent.action.BOOT_COMPLETED" /> 
            </intent-filter>    
        </receiver>     
      </application>
</manifest>

标签内出现了一个新的标签 ,全部静态注册的广播接收器 都是在这里进行注册的。它的用法其实和 标签很是类似,首先经过 android:name 来指定具体注册哪个广播接收器,而后在 标签里加入想要接收的广播就好了, 因为Android系统启动完成后会发出一条值为android.intent.action.BOOT_COMPLETED的广 播,所以咱们在这里添加了相应的 action。

另外,监听系统开机广播也是须要声明权限的,能够看到,咱们使用 标签又加入了一条 android.permission.RECEIVE_BOOT_COMPLETED权限

发送自定义广播

如今你已经学会了经过广播接收器来接收系统广播,接下来咱们就要学习一下如何在应用程序中发送自定义的广播。前面已经介绍过了,广播主要分为两种类型,标准广播和有序 广播。

在API文档中关于BroadcastReceiver的概述:

  • 广播接收器是一个专一于接收广播通知信息,并作出对应处理的组件。不少广播是源自于系统代码的──好比,通知时区改变、电池电量低、拍摄了一张照片或者用户改变了语言选项。应用程序也能够进行广播──好比说,通知其它应用程序一些数据下载完成并处于可用状态。
  • 应用程序能够拥有任意数量的广播接收器以对全部它感兴趣的通知信息予以响应。全部的接收器均继承自BroadcastReceiver基类。
  • 广播接收器没有用户界面。然而,它们能够启动一个activity来响应它们收到的信息,或者用NotificationManager来通知用户。通知能够用不少种方式来吸引用户的注意力──闪动背灯、震动、播放声音等等。通常来讲是在状态栏上放一个持久的图标,用户能够打开它并获取消息。

那么广播事件的流程如何呢,以下:

  • 注册广播事件:注册方式有两种,一种是静态注册,就是在AndroidManifest.xml文件中定义,注册的广播接收器必需要继承BroadcastReceiver;另外一种是动态注册,是在程序中使用Context.registerReceiver注册,注册的广播接收器至关于一个匿名类。两种方式都须要IntentFIlter。

  • 发送广播事件:经过Context.sendBroadcast来发送,由Intent来传递注册时用到的Action。

  • 接收广播事件:当发送的广播被接收器监听到后,会调用它的onReceive()方法,并将包含消息的Intent对象传给它。onReceive中代码的执行时间不要超过10s,不然Android会弹出超时dialog。

具体作法:

在发送广播以前,咱们仍是须要先定义一个广播接收器来准备接收此广播才行,否则发 出去也是白发。所以新建一个 MyBroadcastReceiver继承自 BroadcastReceiver

public class MyBroadcastReceiver extends BroadcastReceiver {    
    @Override  
    public void onReceive(Context context, Intent intent) {   
      Toast.makeText(context, "接收到广播消息", Toast.LENGTH_SHORT).show();    }  
}

这里当 MyBroadcastReceiver收到自定义的广播时,就会弹出提示语。而后在 AndroidManifest.xml中对这个广播接收器进行注册:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"                
  package="com.example.broadcasttest"     
  android:versionCode="1" 
  android:versionName="1.0" >    
    ……     
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />    
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />          
      <application 
        android:allowBackup="true"   
        android:icon="@drawable/ic_launcher"      
        android:label="@string/app_name"     
        android:theme="@style/AppTheme" >  
        <receiver android:name=".MyBroadcastReceiver" >       
            <intent-filter>                 
                <action android:name="com.example.broadcasttest.MY_BROADCAST" /> 
            </intent-filter>    
        </receiver>     
      </application>
</manifest>

能够看到,这里让 MyBroadcastReceiver 接收一条值为 com.example.broadcasttest. MY_BROADCAST的广播,所以待会儿在发送广播的时候,咱们就须要发出这样的一条广播。

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {   
      super.onCreate(savedInstanceState);   
      setContentView(R.layout.activity_main);  
      Button button = (Button) findViewById(R.id.button);  
      button.setOnClickListener(new OnClickListener() {   
        @Override    
        public void onClick(View v) {  
          Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");         
          sendBroadcast(intent);   
        }
      });   
    } 
}

能够看到,咱们在按钮的点击事件里面加入了发送自定义广播的逻辑。首先构建出了一 个 Intent对象,并把要发送的广播的值传入,而后调用了 Context的 sendBroadcast()方法将广 播发送出去,这样全部监听 com.example.broadcasttest.MY_BROADCAST 这条广播的广播接 收器就会收到消息。此时发出去的广播就是一条标准广播。

本地广播介绍

前面咱们发送和接收的广播所有都是属于系统全局广播,即发出的广播能够被其余任何的任何应用程序接收到,而且咱们也能够接收来自于其余任何应用程序的广播。这样就很容易会引发安全性的问题,好比说咱们发送的一些携带关键性数据的广播有可能被其余的应用 程序截获,或者其余的程序不停地向咱们的广播接收器里发送各类垃圾广播。

为了可以简单地解决广播的安全性问题,Android 引入了一套本地广播机制,使用这个机制发出的广播只可以在应用程序的内部进行传递,而且广播接收器也只能接收来自本应用程序发出的广播,这样全部的安全性问题就都不存在了。 本地广播的用法并不复杂,主要就是使用了一个 LocalBroadcastManager 来对广播进行管理,并提供了发送广播和注册广播接收器的方法。下面咱们就经过具体的实例来尝试一下它的用法,修改 MainActivity中的代码,以下所示:

public class MainActivity extends Activity {   
    private IntentFilter intentFilter;  
    private LocalReceiver localReceiver;  
    private LocalBroadcastManager localBroadcastManager;
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {   
      super.onCreate(savedInstanceState); 
      setContentView(R.layout.activity_main); 
      localBroadcastManager = LocalBroadcastManager.getInstance(this); 
      // 获取实例  
      Button button = (Button) findViewById(R.id.button);
      button.setOnClickListener(new OnClickListener() {  
        @Override  
        public void onClick(View v) { 
            Intent intent = new Intent("com.example.broadcasttest. LOCAL_BROADCAST");       
            localBroadcastManager.sendBroadcast(intent);// 发送本地广播 
        }
      }); 
      intentFilter = new IntentFilter();   
      intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST"); 
      localReceiver = new LocalReceiver();   
      // 注册本地广播监听器
      localBroadcastManager.registerReceiver(localReceiver, intentFilter); 
    }  
  
    @Override 
    protected void onDestroy() { 
      super.onDestroy();  
      localBroadcastManager.unregisterReceiver(localReceiver); 
    }  
  
    private class LocalReceiver extends BroadcastReceiver {  
        @Override 
        public void onReceive(Context context, Intent intent) { 
            Toast.makeText(context, "received local broadcast", Toast.LENGTH_SHORT).show(); 
        }  
    }  
}

有没有感受这些代码很熟悉?没错,其实这基本上就和咱们前面所学的动态注册广播接 收器以及发送广播的代码是同样。只不过如今首先是经过 LocalBroadcastManager的 getInstance() 方法获得了它的一个实例,而后在注册广播接收器的时候调用的是 LocalBroadcastManager 的 registerReceiver()方法,在发送广播的时候调用的是 LocalBroadcastManager的 sendBroadcast() 方法,仅此而已。

另外还有一点须要说明,本地广播是没法经过静态注册的方式来接收的。其实这也彻底 能够理解,由于静态注册主要就是为了让程序在未启动的状况下也能收到广播,而发送本地 广播时,咱们的程序确定是已经启动了,所以也彻底不须要使用静态注册的功能。

总结下使用本地广播的几点优点吧。

  1. 能够明确地知道正在发送的广播不会离开咱们的程序,所以不须要担忧机密数据泄 漏的问题。
  2. 其余的程序没法将广播发送到咱们程序的内部,所以不须要担忧会有安全漏洞的隐 患。
  3. 发送本地广播比起发送系统全局广播将会更加高效。

广播的注册过程

咱们如今知道了广播的注册有静态注册和动态注册,其中静态注册的广播在应用安装时由系统自动完成注册的。具体来讲是由PMS(PackageManagerService)来完成整个注册过程的,除了广播觉得,其余三大组件也都是应用安装时由PMS解析并注册的,这里分析下广播的动态注册过程,动态注册过程是从ContextWrapper的registerReceiver方法开始的,和Activity以及Service同样。ContextWrapper并无作实际的工做,基本将注册过程直接交给ContextImpl来完成。

@Override
  public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
      return registerReceiver(receiver, filter, null, null);
  }

ContextImpl的registerReceiver方法调用了本身的registerReceiverInternal方法,具体实现以下:

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
    IntentFilter filter, String broadcastPermission,Handler scheduler, Context context) {
      IIntentReceiver rd = null;
      if (receiver != null) {
        if (mPackageInfo != null && context != null) {
          if (scheduler == null) {
            scheduler = mMainThread.getHandler();
          }
          rd = mPackageInfo.getReceiverDispatcher(
            receiver, context, scheduler,
            mMainThread.getInstrumentation(), true);
        } else {
          if (scheduler == null) {
            scheduler = mMainThread.getHandler();
          }
          rd = new LoadedApk.ReceiverDispatcher(
            receiver, context, scheduler, null, true).getIIntentReceiver();
        }
      }
      try {
        return ActivityManagerNative.getDefault().registerReceiver(
          mMainThread.getApplicationThread(), mBasePackageName,
          rd, filter, broadcastPermission, userId);
      } catch (RemoteException e) {
        return null;
      }
}

系统首先从mPackageInfo获取IIntentReceiver对象,而后再采用跨进程的方式向AMS发送广播注册的请求。之因此用IIntentReceiver而不是直接采用BroadcastReceiver,这是由于上述注册过程是一个进程间通讯的过程,而BroadcastReceiver做为一个Android组件是不能直接跨进程传递的,因此须要经过IIntentReceiver来中转一下,毫无疑问,IIntentReceiver必须是一个Binder接口,它的具体实现是LoadedApk.ReceiverDispatcher,ReceiverDispatcher的内部同时保存了BroadcastReceiver和InnerReceiver,这样当接收到广播时ReceiverDispatcher能够很方便地调用BroadcastReceiver的onReceiver方法。

这里的ActivityManagerNative.getDefault()实际上就是一个AMS。具体代码以下:

public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,Context context, Handler handler,Instrumentation instrumentation, boolean registered) {
   synchronized (mReceivers) {
     LoadedApk.ReceiverDispatcher rd = null;
     ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
     if (registered) {
       map = mReceivers.get(context);
       if (map != null) {
         rd = map.get(r);
       }
     }
     if (rd == null) {
       rd = new ReceiverDispatcher(r, context, handler,instrumentation, registered);
       if (registered) {
         if (map == null) {
           map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
           mReceivers.put(context, map);
         }
         map.put(r, rd);
       }
     } else {
       rd.validate(context, handler);
     }
     rd.mForgotten = false;
     return rd.getIIntentReceiver();
   }

因为注册的广播真正的实现过程是在AMS中,最终会把远程的InnerReceiver对象以及IntentFilter对象存储起来,这样整个广播的注册过程就完成了。

广播的发送和接受过程

当经过send方法来发送广播时,AMS会查找出匹配的广播接收者并将广播发送给他们处理。广播的发送有几种类型:普通广播,有序广播和粘性广播。这里分析下普通广播的实现。

广播的发送和接收。其本质是一个过程的两个阶段。广播的发送仍然开始于ContextWrapper的sendBroadcast方法,之因此不是Context,那是由于Context的sendBroadcast是一个抽象方法。和广播的注册过程同样ContextWrapper的sendBroadcast方法仍然什么都不作,只是把事情交给ContextImpl去处理,ContextImpl的sendBroadcast方法源码以下:

public void sendBroadcast(Intent intent) {
  warnIfCallingFromSystemProcess();
  String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
  try {
    intent.prepareToLeaveProcess();
    ActivityManagerNative.getDefault().broadcastIntent(
      mMainThread.getApplicationThread(), intent, resolvedType, null,
      Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,
      getUserId());
  } catch (RemoteException e) {
  }
}

它直接向AMS发起了一个异步请求用于发送广播。那么AMS的broadcastIntent方法的源码以下:

public final int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle map,
            String requiredPermission, boolean serialized, boolean sticky, int userId) {
        synchronized(this) {
            intent = verifyBroadcastLocked(intent);
            
            final ProcessRecord callerApp = getRecordForAppLocked(caller);
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            int res = broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo,
                    resultCode, resultData, map, requiredPermission, serialized, sticky,
                    callingPid, callingUid, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }

从代码上看,broadcastIntent调用了broadcastIntentLocked方法,但在AMS的broadcastIntentLocked方法里有这么一句:

// By default broadcasts do not go to stopped apps.
    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

这表示在Android5.0下,默认状况下广播不会发送给已经中止的应用。FLAG_EXCLUDE_STOPPED_PACKAGES的含义是表示 不包含已经中止的应用,这个时候广播不会发送给已经中止的应用。

在broadcastIntentLocked的内部,会根据intent-filter查找出匹配的广播接收者并通过一系列的条件过滤,最终会将知足条件的广播接收者添加到BroadcastQueue中,接着BroadcastQueue将会广播发送给相应的广播接收者。

if ((receivers != null && receivers.size() > 0)
                || resultTo != null) {
            BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, requiredPermission,
                    receivers, resultTo, resultCode, resultData, map, ordered,
                    sticky, false);
            if (DEBUG_BROADCAST) Slog.v(
                    TAG, "Enqueueing ordered broadcast " + r
                    + ": prev had " + queue.mOrderedBroadcasts.size());
            if (DEBUG_BROADCAST) {
                int seq = r.intent.getIntExtra("seq", -1);
                Slog.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
            }
            boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r); 
            if (!replaced) {
                queue.enqueueOrderedBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
        }

下面看下BroadcastQueue中广播的发送过程的实现。以下所示:

public void scheduleBroadcastsLocked() {
            if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
                    + mQueueName + "]: current="
                    + mBroadcastsScheduled);
            if (mBroadcastsScheduled) {
                return;
            }
            mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
            mBroadcastsScheduled = true;
        }

BroadcastQueue的scheduleBroadcastsLocked方法并无当即发送广播,而是发送了一个BROADCAST_INTENT_MSG类型的消息,BroadcastQueue收到消息后会调用processNextBroadcast方法,BroadcastQueue的processNextBroadcast方法对普通广播的处理方式以下:

// First, deliver any non-serialized broadcasts right away.
                while (mParallelBroadcasts.size() > 0) {
                    r = mParallelBroadcasts.remove(0);
                    r.dispatchTime = SystemClock.uptimeMillis();
                    r.dispatchClockTime = System.currentTimeMillis();
                    final int N = r.receivers.size();
                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
                            + mQueueName + "] " + r);
                    for (int i=0; i<N; i++) {
                        Object target = r.receivers.get(i);
                        if (DEBUG_BROADCAST)  Slog.v(TAG,
                                "Delivering non-ordered on [" + mQueueName + "] to registered "
                                + target + ": " + r);
                        deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
                    }
                    addBroadcastToHistoryLocked(r);
                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
                            + mQueueName + "] " + r);
                }

能够看到,无序广播存储在mParallelBroadcasts中,系统会遍历mParallelBroadcasts并将其中的广播发送给它们全部接收者,具体的发送过程是经过deliverToRegisteredReceiverLocked方法来实现的。

最终呢,会调用ApplicationThread的scheduleRegisteredReceiver的实现比较简单,它经过InnerReceiver来实现广播的接收。而后InnerReceiver的performReceive方法会调用LoadedApk.ReceiverDispatcher的PerformReceive方法。最终会回调到receiver.onReceive()这个方法。

很显然,这个时候BroadcastReceiver的onReceive方法被执行了,也就是说应用收到广播了,同时,onReceive方法是在广播接收者的主线程中被调用,因此不能作耗时操做,由于是在ApplicationThread的主线程上执行的。

总结

总结一下,Android中应用程序发送广播的过程:

  • 经过sendBroadcast把一个广播经过Binder发送给ActivityManagerService,ActivityManagerService根据这个广播的Action类型找到相应的广播接收器,而后把这个广播放进本身的消息队列中,就完成第一阶段对这个广播的异步分发。
  • ActivityManagerService在消息循环中处理这个广播,并经过Binder机制把这个广播分发给注册的ReceiverDispatcher,ReceiverDispatcher把这个广播放进MainActivity所在线程的消息队列中,就完成第二阶段对这个广播的异步分发。
  • ReceiverDispatcher的内部类Args在MainActivity所在的线程消息循环中处理这个广播,最终是将这个广播分发给所注册的BroadcastReceiver实例的onReceive函数进行处理:

做为Android中四大组件之一的广播,能够应用不少场景的,好比用户异地登录强制下线,应用开机启动服务,网络状态变化通知等等,掌握好其中的定义,使用方法,背后的注册流程,发送和接收消息流程机制,对于咱们在开发时是颇有帮助的。

参考信息:

1,http://blog.csdn.net/zuolongsnail/article/details/6450156

2,《第一行代码》

阅读扩展

源于对掌握的Android开发基础点进行整理,罗列下已经总结的文章,从中能够看到技术积累的过程。
1,Android系统简介
2,ProGuard代码混淆
3,讲讲Handler+Looper+MessageQueue关系
4,Android图片加载库理解
5,谈谈Android运行时权限理解
6,EventBus初理解
7,Android 常见工具类
8,对于Fragment的一些理解
9,Android 四大组件之 " Activity "
10,Android 四大组件之" Service "
11,Android 四大组件之“ BroadcastReceiver "
12,Android 四大组件之" ContentProvider "
13,讲讲 Android 事件拦截机制
14,Android 动画的理解
15,Android 生命周期和启动模式
16,Android IPC 机制
17,View 的事件体系
18,View 的工做原理
19,理解 Window 和 WindowManager
20,Activity 启动过程分析
21,Service 启动过程分析
22,Android 性能优化
23,Android 消息机制
24,Android Bitmap相关
25,Android 线程和线程池
26,Android 中的 Drawable 和动画
27,RecylerView 中的装饰者模式
28,Android 触摸事件机制
29,Android 事件机制应用
30,Cordova 框架的一些理解
31,有关 Android 插件化思考
32,开发人员必备技能——单元测试

相关文章
相关标签/搜索