定义

广播,是一个全局的监听器,属于四大组件之一,Android广播分为两个角色一个是广播发送者,一个是广播接收者。

作用

监听/接受App发出的广播消息,并做出响应。

应用场景

  1. Android不同组件间的通信
  2. 多线程通信
  3. 与Android系统在特定情况下的通信,如电话呼入、网络可用

实现原理

广播接收器注册

静态注册

使用:在AndroidManifest.xml中通过标签声明

特点:常驻、不受任何组件的声明周期的影响,即使在应用程序关闭后,仍有信息广播,程序依旧会被系统调用。

应用场景:需要时刻监听广播

动态注册

使用:在代码中调用Context.registerReceiver()方法

特点:非常驻、灵活、跟随组件的生命周期变化,在组件结束之前必须移除广播接收器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.tuanzhiriji.androidstudy.broadcast;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.tuanzhiriji.androidstudy.R;

public class BroadcastTest extends AppCompatActivity {
private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
@Override
protected void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast);
//1,实例化BroadcastReceiver子类,意图过滤器(IntentFilter)
intentFilter = new IntentFilter();
networkChangeReceiver = new NetworkChangeReceiver();
//2,设置接受广播的类型(这里设置的是网络变化的广播)
intentFilter.addAction("android.net.com.CONNECTIVITY_CHANGE");
//3,动态注册,调用Context的registerReceiver()方法
registerReceiver(networkChangeReceiver, intentFilter);
}

@Override
protected void onDestroy() {
super.onDestroy();
//销毁广播
unregisterReceiver(networkChangeReceiver);
}

class NetworkChangeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {

ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if(networkInfo != null && networkInfo.isAvailable()){
Toast.makeText(getApplicationContext(), "network is available", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), "network is unavailable", Toast.LENGTH_LONG).show();
}
// Toast.makeText(getApplicationContext(), "network changes", Toast.LENGTH_LONG).show();
}
}
}

发送自定义广播

发送标准广播

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.tuanzhiriji.androidstudy.broadcast;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

public class MyBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "MyBroadcastReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "receiver in MyBroadcastReceiver", Toast.LENGTH_SHORT).show();

Log.e(TAG, "onReceive: receiver");
}
}

package com.tuanzhiriji.androidstudy.broadcast;

import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.tuanzhiriji.androidstudy.R;

public class MyBroadActivity extends AppCompatActivity {
private static final String TAG = "MyBroadActivity";
@Override
protected void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Log.e(TAG, "onClick: start");
Intent intent = new Intent("BROADCAST_ACTION");
intent.setComponent(new ComponentName(MyBroadActivity.this, MyBroadcastReceiver.class));
sendBroadcast(intent);

//Log.e(TAG, "onClick: end");
//Toast.makeText(getApplicationContext(), "broadcast", Toast.LENGTH_SHORT).show();
}
});
}
}

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

在写自定义广播时,安卓广播无法响应

之前发送广播的代码是下面的两行,无论怎么点击安卓广播就是没有相应,后来我就去查了,发现在sendBroadcast(intnet)之前需要添加setComponent(new Component(“参数一”, “参数二”))

1
2
Intent intent = new Intent("BROADCAST_ACTION");
sendBroadcast(intent);

修改之后的代码如下,修改了之后广播就可以响应了。

1
2
3
 Intent intent = new Intent("BROADCAST_ACTION");
intent.setComponent(new ComponentName(MyBroadActivity.this, MyBroadcastReceiver.class));
sendBroadcast(intent);

发送有序广播

1
sendOrderedBroadcast(intent, null);

使用上述代码发送的广播可被截断,而且接收者可以修改其中要发送的内容,修改和添加都是可以的,这就意味着优先接收者对数据修改之后,下一个接收者接受的数据是上一个接收者已经修改了的。

如果在onReceiver()方法中调用了abortBroadcast();就表示将这条广播截断。

使用本地广播

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package com.tuanzhiriji.androidstudy.broadcast;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;


import com.tuanzhiriji.androidstudy.R;

public class LocalBroadcastActivity extends AppCompatActivity {
private LocalReceiver localReceiver;
private IntentFilter intentFilter;
private LocalBroadcastManager localBroadcastManager;

@Override
protected void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast);

//1,实例化BroadcastReceiver的子类,IntentFilter
localReceiver = new LocalReceiver();
intentFilter = new IntentFilter();
//2,实例化LocalBroadcastManager的实例
localBroadcastManager = LocalBroadcastManager.getInstance(this);
//3,设置接收广播的类型
intentFilter.addAction("LOCAL_BROADCAST");
//4,调用localBroadcastManager实例的registerReceiver方法进行动态注册
localBroadcastManager.registerReceiver(localReceiver, intentFilter);

Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//发送应用内广播
Intent intent = new Intent("LOCAL_BROADCAST");
localBroadcastManager.sendBroadcast(intent);
}
});
}

@Override
protected void onDestroy() {
super.onDestroy();
//取消注册应用内广播接收器
localBroadcastManager.unregisterReceiver(localReceiver);
}
}

class LocalReceiver extends BroadcastReceiver{

@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "receiver local broadcast", Toast.LENGTH_SHORT).show();
}
}

本地广播是无法通过静态注册的方式来接受的,静态注册主要是为了让程序在未启动的情况下也能收到广播,而发送本地广播时,程序已经启动了,所以完全不需要使用静态注册的功能。

优点

  • 不必担心机密数据泄露
  • 无需担心有安全漏洞的隐患
  • 发送本地广播比发送系统全局广播更加高效

案例练习

实现强制下线功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package com.tuanzhiriji.androidstudy.offline;

import android.app.Activity;



import java.util.ArrayList;
import java.util.List;

public class ActivityCollector {
public static List<Activity> activities = new ArrayList<>();

public static void addActivity(Activity activity){
activities.add(activity);
}

public static void removeActivity(Activity activity){
activities.remove(activity);
}
public static void finishAll(){
for(Activity activity : activities){
if(!activity.isFinishing()){
activity.finish();
}
}
activities.clear();
}
}


package com.tuanzhiriji.androidstudy.offline;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

public class BaseActivity extends AppCompatActivity {
private ForceOfflineReceiver forceOfflineReceiver;
@Override
protected void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityCollector.addActivity(this);
}

@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.removeActivity(this);
}

@Override
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter();
forceOfflineReceiver = new ForceOfflineReceiver();
intentFilter.addAction("FORCE_OFFLINE");
registerReceiver(forceOfflineReceiver, intentFilter);
}

@Override
protected void onPause() {
super.onPause();
if(forceOfflineReceiver != null){
unregisterReceiver(forceOfflineReceiver);
forceOfflineReceiver = null;
}
}

}

class ForceOfflineReceiver extends BroadcastReceiver{

@Override
public void onReceive(Context context, Intent intent) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Warning");
builder.setMessage("You are force to be offline, Please try to login again");
builder.setCancelable(false);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
ActivityCollector.finishAll();
Intent intent = new Intent(context, LoginActivity.class);
context.startActivity(intent);
}
});
builder.show();
}
}


package com.tuanzhiriji.androidstudy.offline;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import androidx.annotation.Nullable;

import com.tuanzhiriji.androidstudy.R;

public class LoginActivity extends BaseActivity{

private EditText accountEdit;
private EditText passwordEdit;
private Button login;

@Override
protected void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView();
}

private void initView() {
accountEdit = (EditText) findViewById(R.id.account);
passwordEdit = (EditText) findViewById(R.id.password);
login = (Button) findViewById(R.id.login);
login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String account = accountEdit.getText().toString();
String password = passwordEdit.getText().toString();
if(account.equals("admin") && password.equals("123456")){
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
finish();
} else {
Toast.makeText(LoginActivity.this, "account or password is invalid", Toast.LENGTH_SHORT).show();
}
}
});
}
}
package com.tuanzhiriji.androidstudy.offline;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import androidx.annotation.Nullable;

import com.tuanzhiriji.androidstudy.R;

public class MainActivity extends BaseActivity{
@Override
protected void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}

private void initView() {
Button forceOffline = (Button) findViewById(R.id.force_offline);
forceOffline.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("FORCE_OFFLINE");
sendBroadcast(intent);
}
});
}
}

//布局就不传上去了,都是一些基本的控件,这个实例的重点在于功能