郑州网站建设zzmshl,二七区做网站,做企业网站备案都需要什么资料,开原 铁岭网站建设【Android】广播机制
前言
广播机制是Android中一种非常重要的通信机制#xff0c;用于在应用程序之间或应用程序的不同组件之间传递信息。广播可以是系统广播#xff0c;也可以是自定义广播。广播机制主要包括标准广播和有序广播两种类型。
简介
在Android中#xff0c…【Android】广播机制
前言
广播机制是Android中一种非常重要的通信机制用于在应用程序之间或应用程序的不同组件之间传递信息。广播可以是系统广播也可以是自定义广播。广播机制主要包括标准广播和有序广播两种类型。
简介
在Android中广播Broadcast是一种消息任何应用程序都可以发送广播消息任何应用程序也都可以接收广播消息。广播通常用于通知应用程序某些事件的发生比如系统启动、电量低、网络状态改变等。
广播的主要组件包括
Broadcast Receiver广播接收器用于接收广播消息并响应这些消息的组件。Intent意图用于传递广播消息的数据结构。 标准广播 标准广播Normal Broadcast是完全异步的所有接收器几乎同时接收广播并且接收顺序是不确定的。标准广播的特点是速度快因为它们不需要等待其他接收器处理完广播才能继续传递。 有序广播 有序广播Ordered Broadcast是同步的一个接收器接收到广播并处理完后广播才会继续传递给下一个接收器。接收器可以修改广播的数据或截断广播使其不再传递给其他接收器。有序广播允许通过设置优先级来控制接收器的接收顺序优先级高的接收器会先接收广播。
接收系统广播
监听网络变化
先新建BroadcastTest项目修改MainActivity
public class MainActivity extends AppCompatActivity {private IntentFilter intentFilter; // 意图过滤器用于监听特定广播事件private NetworkChangeReceiver networkChangeReceiver; // 广播接收器实例Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); // 设置布局文件intentFilter new IntentFilter();intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE); // 添加网络连接变化的广播事件networkChangeReceiver new NetworkChangeReceiver(); // 初始化广播接收器registerReceiver(networkChangeReceiver, intentFilter); // 注册广播接收器}Overrideprotected void onDestroy() {super.onDestroy();unregisterReceiver(networkChangeReceiver); // 注销广播接收器}class NetworkChangeReceiver extends BroadcastReceiver { // 内部类继承自BroadcastReceiverOverridepublic void onReceive(Context context, Intent intent) {Toast.makeText(context, network changes, Toast.LENGTH_SHORT).show(); // 网络变化时显示提示信息}}
}
动态注册的广播一定都要取消注册 取消注册原因 防止内存泄漏 如果广播接收器在不需要时未被注销它会持有对 Context 的引用可能会导致内存泄漏。特别是在 Activity 和 Service 中如果它们被销毁后广播接收器仍然存在会导致这些组件无法被垃圾回收器回收进而占用系统资源。 避免不必要的资源消耗 如果不注销广播接收器它仍然会继续接收广播即使相关的 Activity 或 Service 已经不再需要这些广播。这会导致不必要的系统资源消耗因为每次接收到广播时都会触发 onReceive 方法的执行。 防止潜在的崩溃 在一些情况下如果广播接收器在 Activity 或 Service 销毁后继续接收广播可能会导致应用程序崩溃。例如如果 onReceive 方法中试图访问已销毁的 Activity 的 UI 元素会引发 NullPointerException 等异常。 良好的编程实践 注销广播接收器是一种良好的编程习惯有助于保持代码的整洁和可靠性。它确保每个资源都被合理管理和释放避免因资源管理不当而导致的各种问题。 上面的代码只能提示网络是否变化可以对上面的代码进行优化
public class MainActivity extends AppCompatActivity {private IntentFilter intentFilter; // 意图过滤器用于监听特定广播事件private NetworkChangeReceiver networkChangeReceiver; // 广播接收器实例Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); // 设置布局文件intentFilter new IntentFilter();intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE); // 添加网络连接变化的广播事件networkChangeReceiver new NetworkChangeReceiver(); // 初始化广播接收器registerReceiver(networkChangeReceiver, intentFilter); // 注册广播接收器}Overrideprotected void onDestroy() {super.onDestroy();unregisterReceiver(networkChangeReceiver); // 注销广播接收器}class NetworkChangeReceiver extends BroadcastReceiver { // 内部类继承自BroadcastReceiverOverridepublic void onReceive(Context context, Intent intent) {ConnectivityManager connectivityManager (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); // 获取连接管理器NetworkInfo networkInfo connectivityManager.getActiveNetworkInfo(); // 获取当前活动的网络信息if (networkInfo ! null networkInfo.isAvailable()) { // 检查网络是否可用Toast.makeText(context, network is available, Toast.LENGTH_SHORT).show(); // 网络可用时显示提示信息} else {Toast.makeText(context, network is unavailable, Toast.LENGTH_SHORT).show(); // 网络不可用时显示提示信息}}}
}
就可以显式网络是否连接了
静态注册实现开机启动
先在com/example/boardcasttest包下点击New→Other→Broadcast Receiver修改名字为BootCompleteReceiver并且勾选Exported是否允许这个广播接收器接收本程序以外的广播Enabled表示是否启用这个广播接收器创建完成
修改BootCompleteReceiver中的代码
class NetworkChangeReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context context, Intent intent) {Toast.makeText(context, Boot Complete, Toast.LENGTH_SHORT).show();}
}此外还需要在AndroidManifest文件中注册但是由于我们使用的是快捷方式创建所以这一步已经被自动完成了
?xml version1.0 encodingutf-8?
manifest xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsuses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE /applicationandroid:allowBackuptrueandroid:dataExtractionRulesxml/data_extraction_rulesandroid:fullBackupContentxml/backup_rulesandroid:iconmipmap/ic_launcherandroid:labelstring/app_nameandroid:roundIconmipmap/ic_launcher_roundandroid:supportsRtltrueandroid:themestyle/Theme.BoardcastTesttools:targetApi31receiverandroid:name.BootCompleteReceiverandroid:enabledtrueandroid:exportedtrue/receiveractivityandroid:name.MainActivityandroid:exportedtrueintent-filteraction android:nameandroid.intent.action.MAIN /category android:nameandroid.intent.category.LAUNCHER //intent-filter/activity/application/manifest新建了一个标签receiver
但是目前还是接收不到开机广播需要对AndroidManifest进行修改
?xml version1.0 encodingutf-8?
manifest xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsuses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE /uses-permission android:nameandroid.permission.RECEIVE_BOOT_COMPLETED///applicationandroid:allowBackuptrueandroid:dataExtractionRulesxml/data_extraction_rulesandroid:fullBackupContentxml/backup_rulesandroid:iconmipmap/ic_launcherandroid:labelstring/app_nameandroid:roundIconmipmap/ic_launcher_roundandroid:supportsRtltrueandroid:themestyle/Theme.BoardcastTesttools:targetApi31receiverandroid:name.BootCompleteReceiverandroid:enabledtrueandroid:exportedtrueintent-filteraction android:nameandroid.intent.action.BOOT_COMPLETED////intent-filter/receiveractivityandroid:name.MainActivityandroid:exportedtrueintent-filteraction android:nameandroid.intent.action.MAIN /category android:nameandroid.intent.category.LAUNCHER //intent-filter/activity/application/manifest重新运行后就可以接收开机广播了
自定义广播
发送标准广播
首先需要定义一个广播接收器接收广播新建MyBroadcastReceiver
public class MyBroadcastReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context context, Intent intent) {Toast.makeText(context, received in MyBroadcastReceiver, Toast.LENGTH_SHORT).show();}
}
修改AndroidManifest中的代码
?xml version1.0 encodingutf-8?
manifest xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsuses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE /uses-permission android:nameandroid.permission.RECEIVE_BOOT_COMPLETED/applicationandroid:allowBackuptrueandroid:dataExtractionRulesxml/data_extraction_rulesandroid:fullBackupContentxml/backup_rulesandroid:iconmipmap/ic_launcherandroid:labelstring/app_nameandroid:roundIconmipmap/ic_launcher_roundandroid:supportsRtltrueandroid:themestyle/Theme.BoardcastTesttools:targetApi31receiverandroid:name.BootCompleteReceiverandroid:enabledtrueandroid:exportedtrueintent-filteraction android:namecom.example.broadcasttest.MY_BROADCAST////intent-filter/receiveractivityandroid:name.MainActivityandroid:exportedtrueintent-filteraction android:nameandroid.intent.action.MAIN /category android:nameandroid.intent.category.LAUNCHER //intent-filter/activity/application/manifest我们让MyBroadcastReceiver接收值为的广播
修改activity_main中的代码
?xml version1.0 encodingutf-8?
LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:idid/mainandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentButtonandroid:idid/buttonandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:textSend BoardCast//LinearLayout定义了一个按钮用于作为发送广播的触发点
修改MainActivity中的代码
public class MainActivity extends AppCompatActivity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button button (Button) findViewById(R.id.button);button.setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View v) {Intent intent new Intent(com.example.broadcasttest.MY_BROADCAST);intent.setPackage(getPackageName());sendBroadcast(intent);}});}
}首先创建intent对象将要发送的广播的值传入然后调用sendBroadcast()进行发送我们之前设置的接收器就可以接收到广播了 还要注意的是setPackage的作用是指定这条广播发送给哪个程序使得隐式广播转化为显式广播。因为Android8.0以后静态注册的BroadcastReceiver是无法接受广播的 发送有序广播
修改MainActivity中的代码
public class MainActivity extends AppCompatActivity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button button (Button) findViewById(R.id.button);button.setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View v) {Intent intent new Intent(com.example.broadcasttest.MY_BROADCAST);sendOrderedBroadcast(intent, null);}});}
}我们将sendBroadcast()方法改成了sendOrderedBroadcast()
新建一个类AnotherBroadcastReceiver继承BroadcastReceiver
public class AnotherBroadcastReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context context, Intent intent) {Toast.makeText(context, receciver in AnotherBroadcastReceiver, Toast.LENGTH_SHORT).show();abortBroadcast();//表示截断广播}
}修改AndroidManifest
?xml version1.0 encodingutf-8?
manifest xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsuses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE /uses-permission android:nameandroid.permission.RECEIVE_BOOT_COMPLETED/applicationandroid:allowBackuptrueandroid:dataExtractionRulesxml/data_extraction_rulesandroid:fullBackupContentxml/backup_rulesandroid:iconmipmap/ic_launcherandroid:labelstring/app_nameandroid:roundIconmipmap/ic_launcher_roundandroid:supportsRtltrueandroid:themestyle/Theme.BoardcastTesttools:targetApi31receiverandroid:name.MyBroadcastReceiverandroid:enabledtrueandroid:exportedtrueintent-filteraction android:namecom.example.broadcasttest.MY_BROADCAST//intent-filter/receiverreceiverandroid:name.AnotherBroadcastReceiverandroid:enabledtrueandroid:exportedtrueintent-filter android:priority100action android:namecom.example.broadcasttest.MY_BROADCAST//intent-filter/receiveractivityandroid:name.MainActivityandroid:exportedtrueintent-filteraction android:nameandroid.intent.action.MAIN /category android:nameandroid.intent.category.LAUNCHER //intent-filter/activity/application/manifest可以通过修改
intent-filter android:priority100来确定接收广播的优先级数字大的先接收
使用本地广播
public class MainActivity extends AppCompatActivity {private IntentFilter intentFilter; // 意图过滤器用于监听特定广播事件private LocalReceiver localReceiver; // 本地广播接收器实例private LocalBroadcastManager localBroadcastManager; // 本地广播管理器实例Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); // 设置布局文件localBroadcastManager LocalBroadcastManager.getInstance(this); // 获取本地广播管理器实例// 获取按钮并设置点击监听器Button button (Button) findViewById(R.id.button);button.setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View v) {// 创建一个意图并通过本地广播发送Intent intent new Intent(com.example.broadcasttest.MY_BROADCAST);localBroadcastManager.sendBroadcast(intent);}});// 初始化意图过滤器并添加广播事件intentFilter new IntentFilter();intentFilter.addAction(com.example.broadcasttest.MY_BROADCAST);// 初始化本地广播接收器localReceiver new LocalReceiver();// 注册本地广播接收器localBroadcastManager.registerReceiver(localReceiver, intentFilter);}Overrideprotected void onDestroy() {super.onDestroy();// 注销本地广播接收器localBroadcastManager.unregisterReceiver(localReceiver);}// 定义本地广播接收器类继承自BroadcastReceiverclass LocalReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context context, Intent intent) {// 接收到本地广播时显示提示信息Toast.makeText(context, received local broadcast, Toast.LENGTH_SHORT).show();}}
}广播的最佳实践——强制下线功能
先创建一个ActivityCollector类管理所有活动
public class ActivityCollector {public static ListActivity 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();}
}然后创建BaseActivity类作为所有活动的父类
public class BaseActivity extends AppCompatActivity {Overridepublic void onCreate(Nullable Bundle savedInstanceState, Nullable PersistableBundle persistentState) {super.onCreate(savedInstanceState, persistentState);ActivityCollector.addActivity(this);}Overrideprotected void onDestroy() {super.onDestroy();ActivityCollector.removeActivity(this);}
}创建LoginActivity并自动生成activity_login布局文件修改如下
?xml version1.0 encodingutf-8?
LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:orientationverticalandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentLinearLayoutandroid:orientationhorizontalandroid:layout_widthmatch_parentandroid:layout_height60dpTextViewandroid:layout_width90dpandroid:layout_heightwrap_contentandroid:layout_gravitycenter_verticalandroid:textAccount:android:textSize18sp/EditTextandroid:idid/accountandroid:layout_width0dpandroid:layout_heightwrap_contentandroid:layout_weight1android:layout_gravitycenter_vertical//LinearLayoutLinearLayoutandroid:orientationhorizontalandroid:layout_widthmatch_parentandroid:layout_height60dpTextViewandroid:layout_width90dpandroid:layout_heightwrap_contentandroid:layout_gravitycenter_verticalandroid:textPassword:android:textSize18sp/EditTextandroid:idid/passwordandroid:layout_width0dpandroid:layout_heightwrap_contentandroid:layout_weight1android:layout_gravitycenter_vertical//LinearLayoutButtonandroid:idid/loginandroid:layout_widthmatch_parentandroid:layout_height60dpandroid:textLogin//LinearLayout这个布局就不多做解释了
下来修改LoginActivity中的代码
public class LogActivity extends BaseActivity {private EditText accountEdit;private EditText passwordEdit;private Button login;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_log);accountEdit (EditText) findViewById(R.id.account);passwordEdit (EditText) findViewById(R.id.password);login (Button) findViewById(R.id.login);login.setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View v) {String account accountEdit.getText().toString();String password passwordEdit.getText().toString();if (account.equals(123) password.equals(123)) {Intent intent new Intent(LogActivity.this, MainActivity.class);startActivity(intent);finish();} else {Toast.makeText(LogActivity.this, account or password is invalid, Toast.LENGTH_SHORT).show();}}});}
}模拟了一个点单的登录功能账号为123且密码为123则登陆成功跳转到MainActivity
下来修改activity_main中的代码
?xml version1.0 encodingutf-8?
LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:idid/mainandroid:orientationverticalandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentButtonandroid:idid/force_offlineandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:textSend force offline broadcast//LinearLayout只用实现一个按钮用来触发强制下线功能
修改MainActivity中的代码
public class MainActivity extends BaseActivity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button forceOffline (Button) findViewById(R.id.force_offline);forceOffline.setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View v) {Intent intent new Intent(com.example.broadcastbestpractice.FORCE_OFFLINE);intent.setPackage(getPackageName());sendBroadcast(intent);}});}
}其中come.example.broadcastbestpractice.FORCE_OFFLINE是用来通知程序强制下线的
下来需要创建广播接收器来接收广播但是如果创建一个静态注册的广播接收器是没有办法在onReceive()里弹出对话框那样的UI控件是不现实的
我们只需要在BaseActivity中动态注册一个广播接收器就可以了因为所有活动继承自BaseActivity
修改BaseActivity中的代码
public class BaseActivity extends AppCompatActivity {private ForceOfflineReceiver receiver; // 广播接收器实例Overridepublic void onCreate(Nullable Bundle savedInstanceState, Nullable PersistableBundle persistentState) {super.onCreate(savedInstanceState, persistentState);ActivityCollector.addActivity(this); // 将活动添加到活动管理器中}Overrideprotected void onDestroy() {super.onDestroy();ActivityCollector.removeActivity(this); // 将活动从活动管理器中移除}Overrideprotected void onResume() {super.onResume();IntentFilter intentFilter new IntentFilter();intentFilter.addAction(com.example.broadcastbestpractice.FORCE_OFFLINE); // 添加广播事件receiver new ForceOfflineReceiver(); // 初始化广播接收器registerReceiver(receiver, intentFilter); // 注册广播接收器}Overrideprotected void onPause() {super.onPause();if(receiver ! null) {unregisterReceiver(receiver); // 注销广播接收器receiver null; // 将接收器置为空}}class ForceOfflineReceiver extends BroadcastReceiver { // 定义内部类继承自BroadcastReceiverOverridepublic void onReceive(final Context context, Intent intent) {AlertDialog.Builder builder new AlertDialog.Builder(context);builder.setTitle(Warning); // 设置对话框标题builder.setMessage(You are forced to be offline!); // 设置对话框消息builder.setCancelable(false); // 设置对话框不可取消builder.setPositiveButton(OK, new DialogInterface.OnClickListener() { // 设置对话框确认按钮Overridepublic void onClick(DialogInterface dialog, int which) {ActivityCollector.finishAll(); // 关闭所有活动Intent i new Intent(context, LogActivity.class); // 创建意图启动LogActivitycontext.startActivity(i); // 启动LogActivity}});builder.show(); // 显示对话框}}
}
下来对AndroidManifest文件进行修改
?xml version1.0 encodingutf-8?
manifest xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsapplicationandroid:allowBackuptrueandroid:dataExtractionRulesxml/data_extraction_rulesandroid:fullBackupContentxml/backup_rulesandroid:iconmipmap/ic_launcherandroid:labelstring/app_nameandroid:roundIconmipmap/ic_launcher_roundandroid:supportsRtltrueandroid:themestyle/Theme.BroadcastBestPracticetools:targetApi31activity android:name.MainActivity /activityactivity android:name.LogActivityandroid:exportedtrueintent-filteraction android:nameandroid.intent.action.MAIN /category android:nameandroid.intent.category.LAUNCHER //intent-filter/activity/application/manifest完成了所有代码当我们登录后点击按钮就可以实现强制退出了。
下面是实现的效果 已经到底啦