This is the 20th day of my participation in the August Text Challenge.More challenges in August

introduce

The Android system and applications can send and receive broadcasts to each other. Broadcasts will be sent when the event of interest occurs. Applications can register to receive specific broadcasts. Once the broadcast is sent, it is automatically transmitted to the application that agrees to receive it.

Broadcast can be used as a messaging system beyond the flow of applications and ordinary users, and abuse of post-response broadcasts and run-time operations can slow the system down.

Registration of radio

Applications can receive broadcasts in two ways: a manifest declared receiver and a context registered receiver, that is, a static register and a dynamic register.

public class MyReceiver extends BroadcastReceiver {
    private static final String TAG = "MyReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        int key = intent.getIntExtra("KEY".0);
        Log.d(TAG, "onReceive: key is "+ key); }}Copy the code

Static registered broadcast

Register in androidmanifest.xml


<application>
    ...
    <receiver
        android:name=".MyReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.android.LEARN" />
        </intent-filter>
    </receiver>
    ...
</application>
Copy the code

Note: If your application targets platform versions at API level 26 or higher, you cannot declare receivers for implicit broadcasts (broadcasts that are not specifically targeted to your application) using the manifest, but some implicit broadcasts that are not subject to this restriction are excluded from the portal.

Dynamic Registration broadcast

private void registerBroadcastReceiver(a){
    //1. Create an instance of BroadcastReceiver.
    BroadcastReceiver broadcastReceiver = new MyReceiver();
    //2. Create IntentFilter and call registerReceiver(BroadcastReceiver, IntentFilter) to register receivers
    IntentFilter filter = new IntentFilter("com.android.LEARN");
    this.registerReceiver(broadcastReceiver,filter);
}
Copy the code

As long as the Activity is not destroyed, it receives a broadcast. If you register in the application context, you will receive broadcasts whenever the application is running.

Use standard

To stop receiving radio, call unregisterReceiver (android. Content. BroadcastReceiver). When the sink is no longer needed or the context is no longer valid, it is important to unregister the sink.

Note where the receiver is registered and unregistered. For example, if the receiver is registered in onCreate(Bundle), unregister it in onDestroy() to prevent the receiver from being leaked from the Activity. If you register receivers in onResume(), you should unregister them in onPause() to prevent multiple registrations of receivers (this can reduce unnecessary overhead if you don’t want to receive broadcasts during pauses). Do not log out in onSaveInstanceState(Bundle), because this method will not be called if the user falls back in the history stack.

Impact on process status

The state of the BroadcastReceiver (whether or not it is running) affects the state of the process it is in, which in turn affects the likelihood that it will be killed by the system. For example, when a process executes onReceive(), it is considered a foreground process. The system keeps the process running unless it encounters extreme memory stress.

However, once the code is returned from onReceive(), the BroadcastReceiver is no longer active. The host process for onReceive() becomes just as important as the other application components running in it. If the process hosts only the receivers declared by the manifest (which is common for applications with which the user has never interacted or has not interacted recently), its process is considered a low-priority process when it returns from onReceive() and may be terminated so that resources can be made available to other, more important processes.

If theonReceive()The work is long enough to cause the interface thread to lose frames (>16ms), I believe that the loss of frames is difficult to optimize, or from the details

Send broadcast

Android provides three ways for applications to send broadcasts:

  • sendOrderedBroadcast(Intent, String)Orderly broadcast

The order in which receivers are run can be controlled by the Android: Priority attribute of the matching Intent-filter. Receivers with the same priority will run in random order.

  • sendBroadcast(Intent)Conventional radio
  • LocalBroadcastManager.sendBroadcastLocal radio

If you do not need to send broadcasts across applications, use local broadcasts. This implementation is more efficient (no interprocess communication is required), and you don’t have to worry about any security issues that other applications may have when sending and receiving your broadcasts.

Intent i = new Intent();
i.setAction("com.android.LEARN");
sendBroadcast(i);
Copy the code

The radio type

Broadcast is classified into system broadcast and custom broadcast.

System of radio

The Android system automatically sends a broadcast at various system times, such as when an application is installed or uninstalled.

The system broadcasts the complete list

In the SDK directorySdk\platforms\android-30\data\broadcast_actionsContains all broadcasts of the current SDK version.

Changes reported by different versions of the system

Android 9

Starting with Android 9 (API level 28), NETWORK_STATE_CHANGED_ACTION broadcasts no longer receive information about a user’s location or personally identifiable data. – > portal

In addition, on Android 9 or later devices, the system broadcast received over the WLAN does not contain the SSID, BSSID, connection information, or scan results. Call getConnectionInfo() -> portal.

Android 8

For most implicit broadcasts (broadcasts that are not explicitly targeted to an application), static registrations cannot be used. Consider using dynamic registration

Of course, static registration is not completely out of the question. It can be resolved in intent.setPackage (packageName).

public class BroadcastActivity extends AppCompatActivity {

    private Button mSendBroadcast;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_broadcast);
        mSendBroadcast = findViewById(R.id.send_broadcast);
        mSendBroadcast.setOnClickListener(v -> {
            Intent i = new Intent();
            i.setAction("com.android.LEARN");
            i.setPackage(getPackageName());
            i.putExtra("KEY".1); sendBroadcast(i); }); }}Copy the code

Statically registered in androidmanifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.shixf.servicelearn">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.ServiceLearn">
        <activity
            android:name=".BroadcastActivity"
            android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <receiver
            android:name=".MyReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.android.LEARN" />
            </intent-filter>
        </receiver>


    </application>

</manifest>
Copy the code

The Android 7.0

Android 7.0 (API level 24) and later do not send the following system broadcasts:

  • ACTION_NEW_PICTURE
  • ACTION_NEW_VIDEO

In addition, applications targeting Android 7.0 and later must register CONNECTIVITY_ACTION broadcasts using registerReceiver(IntentFilter). The receiver cannot be declared in the manifest.

Restrict broadcasts by permission

Send broadcast with permission

When calling sendBroadcast(Intent, String) or sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle), you can specify permission parameters. To receive this broadcast, a receiver must request the permission (or be granted the permission if there is a danger) through the tag in its manifest. For example, the following code sends a broadcast:

private void sendPermissionBroadcast(a){
    sendBroadcast(new Intent("com.android.LEARN"),
            Manifest.permission.CAMERA);
}
Copy the code

To receive this broadcast, the recipient APP must request the following permissions:

<uses-permission android:name="android.permission.CAMERA"/>
Copy the code

Note: Custom permissions are registered when the application is installed. The application that defines custom permissions must be installed before the application that uses custom permissions

Receive broadcast with permission

If a permission parameter is specified when registering a BroadcastReceiver (BroadcastReceiver, IntentFilter, String, Handler) or the

tag of Androidmanifest.xml, the broadcaster must request this permission (or be granted it if there is a danger) through the < uses-Permission > tag in its manifest, To send the Intent to the receiver.

Assume that the receiver APP has permission limits

<receiver
    android:name=".MyReceiver"
    android:enabled="true"
    android:exported="true"
    android:permission="android.permission.CAMERA">
    <intent-filter>
        <action android:name="com.android.LEARN" />
    </intent-filter>
</receiver>
Copy the code

Or the receiver applies a receiver with dynamic registration as follows:

IntentFilter filter = new IntentFilter("com.android.LEARN");
    registerReceiver(receiver, filter, Manifest.permission.CAMERA, null );
Copy the code

The sender, then, the APP must request the Manifest. Permission. CAMER permissions, can send broadcast notice is limit the sender to the receiver.

Safety considerations and best practices

  1. If you don’t need to send broadcasts to components outside your application, you can use LocalBroadcastManager (you now need to add dependencies) to send and receive local broadcasts. LocalBroadcastManager is more efficient (no interprocess communication is required), and it doesn’t have to take into account any security issues that other applications have when sending and receiving broadcasts. Local broadcast can be used as a general publish/subscribe event bus in your application without any system-level broadcast overhead.

  2. If many applications register to receive the same broadcast in their lists, the system may start a large number of applications, which may seriously affect device performance and user experience. To avoid this, use dynamic registrations in preference to manifest declarations (static registrations). Sometimes, the Android system itself enforces the use of dynamically registered receivers. For example, CONNECTIVITY_ACTION broadcasts are only sent to context-registered receivers.

  3. Do not use an implicit intent to broadcast sensitive information. Any application registered to receive the broadcast can read this information. You can control which applications can receive your broadcasts in the following three ways:

    • Permissions can be specified when a broadcast is sent.
    • In Android 4.0 and later, you can use it when sending a broadcastsetPackage(String)Specify the package name. The system restricts the broadcast to the set of applications that match the package.
    • You can also useLocalBroadcastManagerSend a local broadcast.
  4. When registering a receiver, any application can send potentially malicious broadcasts to our application’s receiver. You can limit the broadcasts an application can receive in the following three ways:

  • Permissions can be specified when registering a broadcast receiver.
  • For receivers declared in the listing, you can set the Android: Exported property to “false” in the listing. In this way, the receiver does not receive broadcasts from outside the application.
  • You can useLocalBroadcastManagerRestrict applications to receive only local broadcasts.
  1. The namespace for broadcast operations is global. Be sure to write operation names and other strings in your own namespace, otherwise you may inadvertently clash with other applications.

  2. Since the receiver’s onReceive(Context, Intent) method runs on the main thread, it executes quickly and returns. Be careful to generate threads or start background services if you need long-running work, as the system may terminate the entire process after onReceive() returns.

  3. Do not start the Activity from a broadcast receiver; otherwise, the user experience will be affected, especially if there are multiple receivers. Instead, consider displaying notifications

Android learning is of course a reference to the official document portal.