Broadcasting of the Four Components

What is Broadcast?

Broadcasting is a mechanism for transmitting messages between program components. The content of broadcasting is an intent, which carries data and has no user interface.
Different components in the same APP are transmitted, and messages are transmitted between different APP components.
By default broadcast receivers run on the UI thread.

The life cycle of the broadcast receiver is very short. It is created when the broadcast is received and destroyed after the onReceive() method ends; do not do some time-consuming work in the broadcast receiver, otherwise the Application No Response error dialog box will pop up; Do not create sub-threads in the broadcast receiver to do time-consuming work, because the process becomes an empty process after the broadcast receiver is destroyed, and it is easy to be killed by the system; the time-consuming and long-term work is best done in the service .

broadcast receiver

  • Standard broadcast: asynchronous execution, the receiver receives the broadcast almost at the same time after sending.
  • Orderly broadcast: Synchronous execution, only one receiver can receive it at the same time, the receiver can choose to stop, continue to transmit after the logic is executed, and modify the content of the broadcast.
  • Sticky broadcast: After the sticky broadcast is sent, it will wait forever if no receiver is found, and the receiver will receive the broadcast when it rebuilds. (Ensure that important state-changed information is persisted and can be broadcast to new broadcast receivers at any time)
  • System broadcast: A broadcast sent by a system program is a standard broadcast. Mainly related to the basic operation of the mobile phone

Standard broadcast: standard broadcast is divided into two types: dynamic registration and static registration

Static broadcast registration

The MyStaticReceiver class is very simple, it only prints the received information:

package com.hope.demo.broadcast;
 
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
 
import com.hxc.supreme.utils.ToastUtil;
 
public class MyStaticReceiver extends BroadcastReceiver {
 
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("MyStaticReceiver", "onReceive: "+intent.getStringExtra("info"));
    }
}

 Code block in Manifest:

<receiver
       android:name=".broadcast.MyStaticReceiver"
       android:enabled="true"
       android:exported="true">
       <intent-filter>
            <action android:name="hopu"/>
       </intent-filter>
</receiver>

Then there is a click button on the main interface, and the layout file is very simple:

public class BroadcastActivity extends AppCompatActivity implements View.OnClickListener {
 
    private TextView tvStaticBroadcast;
    private TextView tvDynamicBroadcast;
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_broadcast);
        tvStaticBroadcast = findViewById(R.id.tv_static_broadcast);
        tvDynamicBroadcast = findViewById(R.id.tv_dynamic_broadcast);
        tvStaticBroadcast.setOnClickListener(this);
        tvDynamicBroadcast.setOnClickListener(this);
    }
 
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.tv_static_broadcast:
                sendBroadcast();
                break;
            case R.id.tv_dynamic_broadcast:
                break;
        }
    }
 
    private void sendBroadcast() {
        Intent intent = new Intent();
        intent.setAction("hopu");
        intent.putExtra("info", "这是一条静态广播");
        sendBroadcast(intent);
    }
 }

Then look at the log output in logcat:

MyStaticReceiver: onReceive: This is a static broadcast

However, in Android 8.0 and above systems, static broadcasts cannot be received! Google found out that after 8.0, in order to improve efficiency , Google deleted the static registration to prevent the broadcast from continuing after closing the app, causing memory leaks. Now the broadcast of static registration needs to specify the package name! ! !

It means that after 8.0, Google officially recommends replacing static registration with dynamic registration, so let's specify the package name to see if it works:

The code only changes the method of sending the broadcast:

private void sendBroadcast() {
        Intent intent = new Intent();
        intent.setPackage(getPackageName());//Android8.0以上需指定包名
        intent.setAction("hopu");
        intent.putExtra("info", "这是一条静态广播");
        sendBroadcast(intent);
    }

Look at the output log of logcat:

MyStaticReceiver: onReceive: This is a static broadcast

The facts prove that it is possible, but Google recommends the use of dynamic registration, so let's take a look at how to use dynamic registration.

Dynamic broadcast registration

public class BroadcastActivity extends AppCompatActivity implements View.OnClickListener {
 
    private TextView tvStaticBroadcast;
    private TextView tvDynamicBroadcast;
    private DynamicReceiver dynamicReceiver;
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_broadcast);
        tvStaticBroadcast = findViewById(R.id.tv_static_broadcast);
        tvDynamicBroadcast = findViewById(R.id.tv_dynamic_broadcast);
        tvStaticBroadcast.setOnClickListener(this);
        tvDynamicBroadcast.setOnClickListener(this);
        dynamicReceiver = new DynamicReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("husanity");
        registerReceiver(dynamicReceiver, intentFilter);
    }
 
 
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.tv_static_broadcast:
                sendBroadcast();
                break;
            case R.id.tv_dynamic_broadcast:
                sendDynamicBroadcast();
                break;
        }
    }
 
    private void sendBroadcast() {
        Intent intent = new Intent();
        intent.setPackage(getPackageName());//Android8.0以上需指定包名
        intent.setAction("hopu");
        intent.putExtra("info", "这是一条静态广播");
        sendBroadcast(intent);
    }
 
    private void sendDynamicBroadcast() {
        Intent intent = new Intent();
        intent.setAction("hopu");
        intent.putExtra("extra", "这是一条动态广播");
        sendBroadcast(intent);
 
    }
 
    class DynamicReceiver extends BroadcastReceiver {
 
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i("BroadcastActivity", "onReceive: " + intent.getStringExtra("extra"));
 
        }
    }
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //onDestroy中需要反注册,用来优化内存空间避免内存泄漏
        unregisterReceiver(dynamicReceiver);
    }
}

Look at the logcat print log:

BroadcastActivity: onReceive: This is a dynamic broadcast

Specific cases
Dynamically register broadcast receivers to receive broadcasts that have undergone changes in the network

public class HomeActivity extends AppCompatActivity {
 
    private NetWorkReceiver receiver;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
 
        //创建一个意图过滤器
        IntentFilter filter = new IntentFilter();
        //接收网络改变的action
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
 
        receiver = new NetWorkReceiver();
        //注册广播
        this.registerReceiver(this.receiver, filter);
    }
 
    /*
    * 取消注册
    * */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        this.unregisterReceiver(this.receiver);
    }
 
    public class NetWorkReceiver extends BroadcastReceiver {
 
        @Override
        public void onReceive(Context context, Intent intent) {
 
            ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
 
            //如果当前有默认的网络就返回NetworkInfo 否则就返回 null
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            //因为可能是null 所以要先判断是否为空
            if (networkInfo != null && networkInfo.isAvailable()) {
                if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                    Toast.makeText(context, "Wifi", Toast.LENGTH_SHORT).show();
 
                } else if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
                    Toast.makeText(context, "流量", Toast.LENGTH_SHORT).show();
                }
            } else {
                Toast.makeText(context, "世界上最遥远的距离就是没有网", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

Statically register broadcast receivers to realize booting

<!--注册我们的开机广播-->
<receiver
    android:name=".MyBootComplatedReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>
public class MyBootComplatedReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent gotoIntent = new Intent(context, RootComplatedActivity.class);
        context.startActivity(gotoIntent);
    }
}


orderly broadcast

Send through Context.sendOrderedBroadcast, and all receivers are executed in sequence. A BroadcastReceiver can use the setResult series of functions to pass the result to the next BroadcastReceiver, use the getResult series of functions to obtain the result returned by the previous BroadcastReceiver, and use the abort series of functions to let the system discard the broadcast, and use the broadcast to no longer send it to other BroadcastReceivers. You can set the priority of the receiver by setting the android:priority attribute in the intent-filter, and the execution order of the receivers with the same priority is uncertain.

Example:

SMS interception: You can set the level of your app's broadcast receiver to be higher than the original level of the system, and interrupt the broadcast after receiving it, so that no SMS will be received in the inbox.
 

What are the application scenarios in BroadCastReceiver?

APP internal message communication.

Message communication between different APPs.

Receive device information from the system.

Does broadcast priority work for out-of-order broadcasts?

Priority takes effect for out-of-order broadcasts

Who has a higher priority for dynamic registration?

 First, set the priority by yourself, and second, whoever registers first will be higher.

How to judge whether the broadcast received by the current broadcast receiver is ordered or disordered?

Call isOrderedBroadcast() in onReceive

Why can't time-consuming operations be performed in BroadcastReceiver?

  1. BroadcastReceiver is generally in the main thread, and an ANR error will be reported if the time exceeds 10s.
  2. BroadcastReceiver starts quickly. If there is only one receiver in the process and a time-consuming sub-thread is opened, the system will consider it an empty process after onReceive is executed and the broadcast receiver is destroyed, and the system will kill it first.
  3. If the broadcast receiver is an enabled independent thread (the process of the receiver is set in the Manifest) and a sub-thread is opened in it to perform time-consuming tasks, it will also be easily recycled when the memory is insufficient, and the tasks in the sub-thread cannot be completed , such as 2.

local broadcast

  • Both the sender and receiver of a local broadcast belong to the same APP
  • Compared with global broadcast, it has the following advantages:
  1. Others  APP will not be subject to local broadcasts, so there is no need to worry about data leakage.
  2. It is impossible for others   to send local broadcasts  APP to the current one  , so there is no need to worry about security holes being  exploited by others.APPAPP
  3. Local broadcasts are delivered more efficiently than global broadcasts delivered through the system.
  • Android v4 The class is provided in the package  LocalBroadcastManager , which is used to uniformly handle APP local broadcasts. The usage method is almost the same as that of global broadcasts, except that when calling the registration/unregistration broadcast receiver and sending broadcast occasional reading methods, it needs to be called by the instance obtained by the method of the   class LocalBroadcastManager . getInstance()

Foreground broadcast Background broadcast?

The foreground broadcast corresponds to the foreground queue, and the background broadcast corresponds to the background queue. The broadcast can be defined as a foreground broadcast by setting the Intent.FLAG_RECEIVER_FOREGROUND property. If it is not defined, the background broadcast is used by default. Foreground broadcast timeout is 10s, background is 60s.

 Static broadcast and dynamic broadcast

  • Static broadcast: as long as it  app is still running, it will always receive broadcast messages
  • Dynamic broadcast: When the registered component is destroyed, the broadcast will not be received.

Guess you like

Origin blog.csdn.net/u013773608/article/details/129551925