Android basics-BroadcastReceiver comprehensive analysis

Introduction

  • BroadcastReceiver, also one of the four major components of Android, has two important roles: broadcast publisher and broadcast receiver.

Usage scenarios and functions

effect

  • It is used to receive or monitor the broadcast sent by the application and respond accordingly.

scenes to be used

  • Used for communication between different components, including interactive communication within an application and between different applications.
  • Monitor system resource changes, such as network changes, SD card status, etc.
  • Multi-process communication

Realization principle

It is an application of the typical observer pattern, based on the message publisher/message subscriber model.

Write picture description here

Principle description

  1. Message subscribers (broadcast receivers) register in the message center AMS through the Binder mechanism
  2. The message publisher (broadcast publisher) sends a broadcast to the message center AMS through the Binder mechanism
  3. According to the requirements of the broadcast publisher, AMS searches for a matching subscriber in the registered list. If a matching subscriber is found, the message center AMS will send the corresponding broadcast to the subscriber.
    1. The basis of the message center AMS search is: intent filter (IntentFilter) and permission (permission).
  4. Finally, after the message subscriber (broadcast receiver) receives the broadcast, the onReceiver method will be called back.

1. Broadcast publisher: sendBroadcast, sendOrderedBroadcast
2. Broadcast receiver: BroadcastReceiver

Specific use

  • Inherit the BroadcastReceiver class and override the onReceiver method. After the broadcast is received, it will actively call back the method.
  • Register a broadcast receiver

There are two ways to register a broadcast receiver: static registration and dynamic registration.

Static registration:

Just declare it in the AndroidMainfest file, and the attributes are as follows:

<receiver
    android:enabled=["true" | "false"]
    //此broadcastReceiver能否接收其他App的发出的广播
    //默认值是由receiver中有无intent-filter决定的:如果有intent-filter,默认值为true,否则为false
    android:exported=["true" | "false"]
    android:icon="drawable resource"
    android:label="string resource"
    //继承BroadcastReceiver子类的类名
    android:name=".mBroadcastReceiver"
    //具有相应权限的广播发送者发送的广播才能被此BroadcastReceiver所接收;
    android:permission="string"
    //BroadcastReceiver运行所处的进程
    //默认为app的进程,可以指定独立的进程
    //注:Android四大基本组件都可以通过此属性指定自己的独立进程
    android:process="string" >

    //用于指定此广播接收器将接收的广播类型
    //本示例中给出的是用于接收网络状态改变时发出的广播
    <intent-filter>
          <action android:name="android.net.conn.CONNETIVITY_CHANGE"/>
    </intent-filter >
</receiver>

Static registration, the BroadcastReceiver class will be instantiated when the App is started for the first time, and the broadcast receiver will also be registered in the AMS. That is to say, the onReceiver method will be called back when the App is started.
To increase the priority of the broadcast, you can set the attribute priority in the intent-filter. The larger the value, the higher the priority.

<receiver android:name=".MyBroadcastReceiver">
    <intent-filter android:priority="100">        
     </intent-filter>
</receiver>

Dynamic registration:

Register using the registerReceiver method of Content

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

The above is one of the most parameters in the registerReceiver method. Receiver and filter must be passed, and the others are optional

  • receiver: used to process the received broadcast, that is, the broadcast receiver
  • filter: Intent filter, you can set the priority of the broadcast and accept the type of broadcast.
  • broadcastPermission: Set the broadcast permission, that is, the broadcast intent (Intent) sent must contain the same string. Optional
  • scheduler: Set the thread where the broadcast receiver accepts processing messages (onReceiver), optional, the default is on the main thread
  • flags: some additional flag options, optional
//注册广播
 mReceiver = new MyBroadcastReceiver();
 IntentFilter filter = new IntentFilter();
 //必须action的匹配规则,否则无法接收到消息,在发送广播的意图中必须匹配action的字符串
 filter.addAction("test");
 registerReceiver(mReceiver,filter);

//发送广播
Intent intent = new Intent();
intent.setAction("test");
 sendBroadcast(intent);

If there is registration, it will inevitably be deregistered. Generally, deregister in onDestroy or onPause. If you do not deregister, it will cause memory leaks.

 @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mReceiver);
    }

During dynamic registration, please note that the new MyBroadcastReceiver() object cannot be registered repeatedly, otherwise the onReceiver method will be called back multiple times, which will cause some additional problems.

The difference between the two registration methods

Write picture description here

Broadcast classification

  • Normal Broadcast
  • System Broadcast
  • Ordered Broadcast
  • Sticky Broadcast
  • Local Broadcast in App

Normal Broadcast

1. Register the broadcast receiver on the homepage (BroadcastReceiver). For the dynamic registration method, you need to set the matching field action, otherwise the broadcast cannot be received

mReceiver = new MyBroadcastReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("test");
registerReceiver(mReceiver,filter);

//或者

<receiver android:name=".MyBroadcastReceiver">
   <intent-filter>
     <action android:name="test"/>
    </intent-filter>
</receiver>

2. To send a broadcast through the Intent intention, the intention must be added with the same string of action (the same as the registered one), otherwise the broadcast cannot be received

 Intent intent = new Intent();
 intent.setAction("test");
 sendBroadcast(intent);

3. After receiving the broadcast, it will actively call back the onReceive method in BroadcastReceiver

public class MyBroadcastReceiver extends BroadcastReceiver{
    
    

    private static final String TAG = "BroadcastReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "onReceive: "+intent.getAction());

    }
}

System Broadcast

There are many system broadcasts built in the Android system. When the system status information changes, it will send out corresponding broadcasts, such as power-on, battery changes, network changes... We know that the same action is required to register and send broadcasts, and system broadcasts There are also different actions. The Android system broadcasts actions as follows:

Write picture description here

<receiver android:name=".MyBroadcastReceiver">
            <intent-filter>
                <!-- 应用添加 -->
                <action android:name="android.intent.action.PACKAGE_ADDED"/>
                <!-- 应用删除 -->
                <action android:name="android.intent.action.PACKAGE_REMOVED"/>
                <!-- 应用替换 -->
                <action android:name="android.intent.action.PACKAGE_REPLACED"/>
                <!-- 应用重新启动 -->
                <action android:name="android.intent.action.PACKAGE_RESTARTED"/>

                <!--必须设置scheme,相当于URI,不然收不到系统广播-->
                <data android:scheme="package"/>
            </intent-filter>
        </receiver>

When using the system broadcast, you only need to define the relevant action when registering the broadcast receiver, and you don’t need to manually send the broadcast. When the system has related operations, the system broadcast will be performed automatically.

You can also dynamically register:

 mReceiver = new MyBroadcastReceiver();
 IntentFilter filter = new IntentFilter();
 filter.addAction("android.intent.action.PACKAGE_REMOVED");
 filter.addAction("android.intent.action.PACKAGE_ADDED");
 filter.addDataScheme("package");
 registerReceiver(mReceiver,filter);

Ordered Broadcast

After the same broadcast is received by a broadcast receiver at the same time, the service logic of the current broadcast receiver must be executed before the broadcast will continue to be delivered. It is received in order, and the receiving rules are as follows:

  1. By default, under the same registration method, they will be received in the order of registration
  2. Sort by Priority attribute value from largest to smallest
  3. If the Priority attribute value is the same, the dynamically registered broadcast takes precedence.

If a broadcast is interrupted, the following broadcast receiver will not be able to receive the broadcast

example:

1. Broadcast receiver

public class MyBroadcastReceiver extends BroadcastReceiver{
    
    

    private static final String TAG = "BroadcastReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "onReceive: "+intent.getAction());

        for (int i = 0; i < 5; i++) {
            Log.e(TAG, "onReceive: "+i);
        }
    }
}

public class MyBroadcastReceiver2 extends BroadcastReceiver{
    
    

    private static final String TAG = "BroadcastReceiver2";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "onReceive2: "+intent.getAction());

    }
}

Register to broadcast

        //注册广播
        <receiver android:name=".MyBroadcastReceiver">
            <intent-filter android:priority="100">
                <action android:name="test"/>
            </intent-filter>
        </receiver>
        //注册广播2
        <receiver
            android:name=".MyBroadcastReceiver2">
            <intent-filter android:priority="80">
                <action android:name="test"/>
            </intent-filter>
        </receiver>

     //或者
     mReceiver = new MyBroadcastReceiver();
     mReceiver2 = new MyBroadcastReceiver2();
     IntentFilter filter = new IntentFilter();
     filter.addAction("test");
     filter.setPriority(100);
     registerReceiver(mReceiver,filter);
     filter.setPriority(80);
     registerReceiver(mReceiver2,filter);

Send broadcast

Intent intent = new Intent();
intent.setAction("test");
sendOrderedBroadcast(intent,null);

Output result:
Write picture description here

The use process of ordered broadcasting is very similar to ordinary broadcasting. The only difference is that the sending method of broadcasting is different: sendOrderedBroadcast, to determine whether it is an ordered broadcasting, you can call the isOrderedBroadcast method in onReceive, and true is; if you need to interrupt the broadcast delivery, The abortBroadcast method can be called in onReceive.

Local Broadcast in App

In Android, broadcasting can communicate directly across App (cross-process) by default. Because the exported attribute is true
by default, broadcasting is cross-process by default, and broadcasting is based on the matching judgment of the sending intent Intent and the intent filter Intent-filter to determine whether the onReceiver method of BroadcastReceiver is called back. This may cause the following problems:

  • If the broadcast Intent sent by other App matches the Intent-filter of the current App, this will cause the current App to continue to receive broadcasts and process them. If the criminals know the Intent-filter of the App, they may push some bad information through this vulnerability, which will affect the security of the App.

In view of the above problems, there are the following solutions:

  1. Set global broadcast to local broadcast
    1. When the broadcast registration exported property set to false, so that the broadcast of the present App inner non sent
      is not received
    2. When sending and receiving broadcasts, add corresponding permissions for permission verification;
    <receiver android:name=".MyBroadcastReceiver"
            android:exported="false">
            <intent-filter android:priority="100">
                <action android:name="test"/>
            </intent-filter>
        </receiver>
<!--1、自定义新权限-->
 <!--自定义新权限-->
    <permission android:name="com.hzw.MY_RECEIVER"/>

    <application
        ……
        <!-- 2、发送方必须要拥有com.hzw.permission.MY_RECEIVER权限,接受器才会接受-->
        <receiver android:name=".MyBroadcastReceiver"
            android:permission="com.hzw.permission.MY_RECEIVER">
            <intent-filter android:priority="100">
                <action android:name="test"/>
            </intent-filter>
        </receiver>

       ……
    </application>

2. Use local broadcast, the LocalBroadcastManager class encapsulated by the system

mReceiver2 = new MyBroadcastReceiver2();
IntentFilter filter = new IntentFilter();
filter.addAction("test");
//获取LocalBroadcastManager类的实例,通过该实例注册广播             
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
mLocalBroadcastManager.registerReceiver(mReceiver2,filter);

//注销也需通过LocalBroadcastManager进行注销
mLocalBroadcastManager.unregisterReceiver(mReceiver2);

For in-app broadcasts sent by LocalBroadcastManager, it can only be dynamically registered through LocalBroadcastManager, not statically.

thank

https://blog.csdn.net/carson_ho/article/details/52973504
https://blog.csdn.net/javensun/article/details/7334230
http://h529820165.iteye.com/blog/1656778

Guess you like

Origin blog.csdn.net/hzw2017/article/details/80959378