Android系统广播(Broadcast)注册,发送,接收流程解析

Android系统广播(Broadcast)注册,发送,接收流程解析,第1张

以下广播简称Broadcast

  是Android四大组件之一,在四大组件的另外两个组件 和 拥有发送和接收广播的能力。Android 是在 进程间通信机制的基础上实现的,内部基于消息发布和订阅的事件驱动模型,广播发送者负责发送消息,广播接收者需要先订阅消息,然后才能收到消息。 进程间通信与 的区别在于:

  有三种类型

   存在一个注册中心,也可以说是一个调度中心,即 。广播接收者将自己注册到 中,并指定要接收的广播类型;广播发送者发送广播时,发送的广播首先会发送到 , 根据广播的类型找到对应的 ,找到后边将广播发送给其处理。

   这里以普通广播为例子, 接收者有两种注册方式,一种是 ,一种是 :

(广播的发送分为 两种,这里针对有序的广播) 中的android:priority=""和 中的IntentFilter.setPriority(int)可以用来设置广播接收者的优先级,默认都是0 , 范围是[-1000, 1000],值越大优先级越高,优先级越高越早收到。

   在相同优先级接收同个类型广播时, 的广播接收器比 的广播接收者更快的接收到对应的广播,这个之后会进行分析。

   注:以下源码基于rk3399_industry Android7.1.2

   的流程可分为 , 和 三个部分,这里依次分析下

   在Android系统的 机制中,前面提到, 作为一个注册和调度中心负责注册和转发 。所以 的注册过程就是把它注册到 的过程。

   这里我们分析 广播的过程, 和 有一个共同的父类 ,所以它们对应的注册过程其实是调用 ,接下来我们按照流程逐步分析调用流程的源码。

frameworks/base/core/java/android/content/ContextWrapper.java

   在之前的 Android应用程序启动入口ActivityThread.main流程分析 分析过,在我们启动 Activity 时会创建一个 对象,然后通过 传给我们启动的 ,其内部就会将该对象赋值给 ; 的 方法也是类似的赋值流程,这里放个简易的源码应该更好理解

   可以看到最后都会将生成的 对象赋值给对应的

对象。接下来继续分析 , 即 函数。

/frameworks/base/core/java/android/app/ContextImpl.java

   这里我们首先看下如何将广播接收者 封装成一个 接口的 本地对象

/frameworks/base/core/java/android/app/LoadedApk.java

   每一个注册过广播接收者的 或 组件在<font color='Crimson'>LoadedApk </font>类中都有个对应的 对象,该对象负责将 与 组件关联起来。这些对象,以关联的 作为关键字保存在一个 中。之后对应的 又以 的 作为关键字保存在 的成员变量 对象中。最后通过 对应的 方法获得其 接口的 本地对象。之后再回到 注册方法内,将 对象发给 进行注册。

/frameworks/base/core/java/android/app/ActivityManagerNative.java

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

   在的 或 注册一个 时,并不是将其注册到<font color='OrangeRed'>AMS</font>中,而是将与它关联的<font color='OrangeRed'>InnerReceiver</font>对象注册到<font color='OrangeRed'>AMS</font>中,当<font color='OrangeRed'>AMS</font>接收到广播时,会根据 在内部找到对应的<font color='OrangeRed'>InnerReceiver</font>对象,然后在通过这个对象将这个广播发送给对应的 处理。

   注册过程这边画了一个简单的流程图:

   <font color='OrangeRed'>Broadcast</font>的发送过程可简单描述为以下几个过程:

frameworks/base/core/java/android/content/ContextWrapper.java

/frameworks/base/core/java/android/app/ContextImpl.java

/frameworks/base/core/java/android/app/ActivityManagerNative.java

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

有两种注册广播方式:

1.常驻型广播

常驻型广播,当应用程序关闭了,如果有广播信息来,写的广播接收器同样的能接收到,它的注册方式就是在应用程序的AndroidManifast.xml 中进行注册,这种注册方式通常又被称作静态注册。这种方式可以理解为通过清单文件注册的广播是交给 *** 作系统去处理的。示例代码如下:

AndroidManifest.xml中配置广播

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="spl.broadCastReceiver"

android:versionCode="1"

android:versionName="1.0">

<application android:icon="@drawable/icon" android:label="@string/app_name">

<activity android:name=".BroadCastReceiverActivity"

android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

<!--广播注册、name里面填写广播类的路径-->

<receiver android:name=".SmsBroadCastReceiver">

<intent-filter android:priority="20">

<action android:name="android.provider.Telephony.SMS_RECEIVED"/>

</intent-filter>

</receiver>

</application>

<uses-sdk android:minSdkVersion="7" />

<!-- 权限申请 -->

<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>

</manifest>

2.非常驻型广播

非常驻型广播,当应用程序结束了,广播自然就没有了,比如在 Activity 中的 onCreate 或者 onResume 中注册广播接收者,在 onDestory 中注销广播接收者。这样广播接收者就一个非常驻型的了,这种注册方式也叫动态注册。这种方式可以理解为通过代码注册的广播是和注册者关联在一起的。比如写一个监听 SDcard 状态的广播接收者:

package cn.sunzn.mosecurity.activity

import android.app.Activity

import android.content.BroadcastReceiver

import android.content.Context

import android.content.Intent

import android.content.IntentFilter

import android.os.Bundle

import android.os.Environment

public class SDcard extends Activity {

SdcardStateChanageReceiver sdcardStateReceiver

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState)

sdcardStateReceiver = new SdcardStateChanageReceiver()

IntentFilter filter = new IntentFilter()

filter.addAction(Intent.ACTION_MEDIA_REMOVED)

filter.addAction(Intent.ACTION_MEDIA_EJECT)

filter.addAction(Intent.ACTION_MEDIA_MOUNTED)

filter.addDataScheme("file")

registerReceiver(sdcardStateReceiver, filter)

}

protected void onDestroy() {

unregisterReceiver(sdcardStateReceiver)

}

class SdcardStateChanageReceiver extends BroadcastReceiver {

public void onReceive(Context context, Intent intent) {

checkSDCard()

}

public void checkSDCard() {

String state = Environment.getExternalStorageState()

System.out.println(state)

if (state.equals(Environment.MEDIA_REMOVED) || state.equals(Environment.MEDIA_UNMOUNTED)) {

System.out.println("SDCard 已卸载!")

}

}

}

}

2种方式

1.在androidmainfest.xml中注册

2.<receiver>

3. <intent-filter>

4. <action android:name = "android.intent.action.PICK"/>

5. </intent-filter>

6.</receiver>

7.缺点:常驻型,占资源比较大

8.

9.registerReceiver(receiver,filter)BroadcastReceiver更新UI一般用这种方法


欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/bake/11648404.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-17
下一篇 2023-05-17

发表评论

登录后才能评论

评论列表(0条)

保存