• $《第一行代码:Android》读书笔记——第5章 Broadcast


      (一)广播机制简介

      1、Android广播的分类:

      如图所示:

      

      2、发送广播:使用Intent;接收广播:Broadcast Receiver。

     

      (二)接收系统广播

      1、动态注册监听网络变化

      示例程序:

      (1)MainActivity(注:以下代码中的ToastUtil是自己简单封装的Toast显示功能的类):

     1 package com.example.broadcasttest;
     2 
     3 import android.app.Activity;
     4 import android.content.BroadcastReceiver;
     5 import android.content.Context;
     6 import android.content.Intent;
     7 import android.content.IntentFilter;
     8 import android.net.ConnectivityManager;
     9 import android.net.NetworkInfo;
    10 import android.os.Bundle;
    11 import android.view.Menu;
    12 import android.view.MenuItem;
    13 
    14 public class MainActivity extends Activity {
    15 
    16     private IntentFilter intentFilter;
    17     private NetworkChangeReceiver networkChangeReceiver;
    18 
    19     @Override
    20     protected void onCreate(Bundle savedInstanceState) {
    21         super.onCreate(savedInstanceState);
    22         setContentView(R.layout.activity_main);
    23 
    24         // 1.创建IntentFilter实例
    25         intentFilter = new IntentFilter();
    26         // 2.用addAction方法添加action
    27         intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
    28 
    29         // 3.创建内部类NetworkChangeReceiver实例
    30         networkChangeReceiver = new NetworkChangeReceiver();
    31         // 4.注册
    32         registerReceiver(networkChangeReceiver, intentFilter);
    33     }
    34 
    35     class NetworkChangeReceiver extends BroadcastReceiver {
    36 
    37         @Override
    38         public void onReceive(Context context, Intent intent) {
    39             // 创建ConnectivityManager实例
    40             ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    41             // 创建NetworkInfo对象(需要申请权限ACCESS_NETWORK_STATE)
    42             NetworkInfo networkInfo = connectivityManager
    43                     .getActiveNetworkInfo();
    44 
    45             // 判断NetworkInfo的状态,即网络是否可用
    46             if (networkInfo != null && networkInfo.isAvailable()) {
    47                 ToastUtil.showShort(MainActivity.this, "网络可用!");
    48             } else {
    49                 ToastUtil.showShort(MainActivity.this, "网络不可用!");
    50             }
    51 
    52         }
    53     }
    54 
    55     @Override
    56     protected void onDestroy() {
    57         super.onDestroy();
    58         unregisterReceiver(networkChangeReceiver);
    59     }
    60 
    61 }

      (2)申请权限

    1 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

      (3)xml文件:不需要添加什么内容。

      2、静态注册实现开机启动

      动态注册的一个缺点就是,必须要在程序启动之后才能接收到广播,而静态注册就可以在程序还未启动时就能接收到广播,利用这一点就可以实现诸如开机启动程序的功能。

      示例程序:

      (1)新建类BootCompleteReceiver继承自BroadcastReceiver(注:onReceive方法中红不能放过于耗时的逻辑,因为其中不允许使用线程):

     1 package com.example.broadcasttest;
     2 
     3 import android.content.BroadcastReceiver;
     4 import android.content.Context;
     5 import android.content.Intent;
     6 
     7 public class BootCompleteReceiver extends BroadcastReceiver {
     8 
     9     @Override
    10     public void onReceive(Context context, Intent intent) {
    11         ToastUtil.showShort(context, "BroadcastTest开机启动");
    12     }
    13 
    14 }

      (2)在AndroidManifest.xml静态注册广播:

     1 <application
     2         android:allowBackup="true"
     3         android:icon="@drawable/ic_launcher"
     4         android:label="@string/app_name"
     5         android:theme="@style/AppTheme" >
     6         ...
     7         <receiver android:name=".BootCompleteReceiver" >
     8             <intent-filter>
     9                 <action android:name="android.intent.action.BOOT_COMPLETED" />
    10             </intent-filter>
    11         </receiver>
    12     </application>

      (3)申请权限:

    1 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

      (三)发送自定义广播

      1、发送标准广播

      (1)在BroadcastTest项目中:

      ①创建MyBroadcastReceiver:

    1 public class MyBroadcastReceiver extends BroadcastReceiver {
    2 
    3     @Override
    4     public void onReceive(Context context, Intent intent) {
    5         ToastUtil.showShort(context, "在MyBroadcastReceiver中接收到了自定义广播!");
    6     }
    7 
    8 }

      ②在AndroidManifest.xml中注册广播接收器:

    1      <receiver android:name=".MyBroadcastReceiver" >
    2             <intent-filter>
    3                 <action android:name="com.example.broadcasttest.MY_BROADCAST" />
    4             </intent-filter>
    5         </receiver>

      ③activity_main.xml:

     1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     android:layout_width="match_parent"
     3     android:layout_height="match_parent"
     4     android:orientation="vertical" >
     5 
     6     <Button
     7         android:id="@+id/send_broadcast_btn"
     8         android:layout_width="match_parent"
     9         android:layout_height="wrap_content"
    10         android:text="发送自定义广播" />
    11 
    12 </LinearLayout>

      ④MainActivity:

     1 package com.example.broadcasttest;
     2 
     3 import android.app.Activity;
     4 import android.content.BroadcastReceiver;
     5 import android.content.Context;
     6 import android.content.Intent;
     7 import android.content.IntentFilter;
     8 import android.net.ConnectivityManager;
     9 import android.net.NetworkInfo;
    10 import android.os.Bundle;
    11 import android.view.Menu;
    12 import android.view.MenuItem;
    13 import android.view.View;
    14 import android.view.View.OnClickListener;
    15 import android.widget.Button;
    16 
    17 public class MainActivity extends Activity implements OnClickListener {
    18 
    19     private Button sendBroadcast;
    20 
    21     @Override
    22     protected void onCreate(Bundle savedInstanceState) {
    23         super.onCreate(savedInstanceState);
    24         setContentView(R.layout.activity_main);
    25 
    26         sendBroadcast = (Button) findViewById(R.id.send_broadcast_btn);
    27         sendBroadcast.setOnClickListener(this);
    28     }
    29 
    30     @Override
    31     public void onClick(View v) {
    32         switch (v.getId()) {
    33         case R.id.send_broadcast_btn:
    34             Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
    35             sendBroadcast(intent);
    36             break;
    37         default:
    38             break;
    39         }
    40     }
    41 }

      (2)创建BroadcastTest2项目,在其中:

      ①创建AnotherBroadcastReceiver:

    1 public class AnotherBroadcastReceiver extends BroadcastReceiver {
    2 
    3     @Override
    4     public void onReceive(Context context, Intent intent) {
    5         ToastUtil.showShort(context, "在AnotherBroadcastReceiver中接收到了自定义广播!");
    6     }
    7 
    8 }

      ②在AndroidManifest.xml中注册广播接收器:

    1      <receiver android:name=".AnotherBroadcastReceiver" >
    2             <intent-filter>
    3                 <action android:name="com.example.broadcasttest.MY_BROADCAST" />
    4             </intent-filter>
    5         </receiver>

      (3)同时运行BroadcastTest和BroadcastTest2程序,然后在BroadcastTest中点击“发送自定义广播”按钮,然后就会发现弹出两次Toast显示接收到了广播。

      2、发送有序广播

      在1中BroadcastTest项目的基础上,做以下修改即可(红色加下划线的代码为新增或修改的代码):

      (1)MainActivity中:

     1   @Override
     2     public void onClick(View v) {
     3         switch (v.getId()) {
     4         case R.id.send_broadcast_btn:
     5             Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
     6             sendOrderedBroadcast(intent, null);
     7             break;
     8         default:
     9             break;
    10         }
    11     }

      (2)AndroidManifest.xml中:

    1      <receiver android:name=".MyBroadcastReceiver" >
    2             <intent-filter android:priority="100" >
    3                 <action android:name="com.example.broadcasttest.MY_BROADCAST" />
    4             </intent-filter>
    5         </receiver>

      (3)MyBroadcastReceiver类中:

    1 public class MyBroadcastReceiver extends BroadcastReceiver {
    2 
    3     @Override
    4     public void onReceive(Context context, Intent intent) {
    5         ToastUtil.showShort(context, "在MyBroadcastReceiver中接收到了自定义广播!");
    6  abortBroadcast();
    7     }
    8 
    9 }

      (4)再运行两个程序,点击发送广播按钮后,发现只看到了一个Toast提示,因为另一个广播接收被截断了。 

      (四)使用本地广播

      以上的广播都是全局广播,也就是任何应用程序都能接收到。而这会引发安全性问题,如果只希望在当前应用程序内部传递广播,就要使用本地广播了。

      本地广播的关键是使用LocalBroadcastManager来发送广播。示例程序:

      1、xml文件:

     1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     android:layout_width="match_parent"
     3     android:layout_height="match_parent"
     4     android:orientation="vertical" >
     5 
     6     <Button
     7         android:id="@+id/send_broadcast_btn"
     8         android:layout_width="match_parent"
     9         android:layout_height="wrap_content"
    10         android:text="发送自定义广播" />
    11 
    12 </LinearLayout>

      2、MainActivity:

     1 package com.example.broadcasttest;
     2 
     3 import android.app.Activity;
     4 import android.content.BroadcastReceiver;
     5 import android.content.Context;
     6 import android.content.Intent;
     7 import android.content.IntentFilter;
     8 import android.net.ConnectivityManager;
     9 import android.net.NetworkInfo;
    10 import android.os.Bundle;
    11 import android.support.v4.content.LocalBroadcastManager;
    12 import android.view.Menu;
    13 import android.view.MenuItem;
    14 import android.view.View;
    15 import android.view.View.OnClickListener;
    16 import android.widget.Button;
    17 
    18 public class MainActivity extends Activity implements OnClickListener {
    19 
    20     private Button sendBroadcast;
    21 
    22     private IntentFilter intentFilter;
    23 
    24     private LocalReceiver localReceiver;
    25     private LocalBroadcastManager localBroadcastManager;
    26 
    27     @Override
    28     protected void onCreate(Bundle savedInstanceState) {
    29         super.onCreate(savedInstanceState);
    30         setContentView(R.layout.activity_main);
    31 
    32         // 1.获取localBroadcastManager实例
    33         localBroadcastManager = LocalBroadcastManager.getInstance(this);
    34 
    35         sendBroadcast = (Button) findViewById(R.id.send_broadcast_btn);
    36 
    37         // 2.在点击事件中用LocalBroadcastManager的sendBroadcast方法发送广播
    38         sendBroadcast.setOnClickListener(this);
    39 
    40         // 3.注册IntentFilter
    41         intentFilter = new IntentFilter();
    42         intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
    43         localReceiver = new LocalReceiver();
    44         localBroadcastManager.registerReceiver(localReceiver, intentFilter);
    45     }
    46 
    47     @Override
    48     public void onClick(View v) {
    49         switch (v.getId()) {
    50         case R.id.send_broadcast_btn:
    51             Intent intent = new Intent(
    52                     "com.example.broadcasttest.LOCAL_BROADCAST");
    53             localBroadcastManager.sendBroadcast(intent);
    54             break;
    55         default:
    56             break;
    57         }
    58     }
    59 
    60     @Override
    61     protected void onDestroy() {
    62         super.onDestroy();
    63         localBroadcastManager.unregisterReceiver(localReceiver);
    64     }
    65 }

      3、注册广播接收器:

    1      <receiver android:name=".LocalReceiver" >
    2             <intent-filter>
    3                 <action android:name="com.example.broadcasttest.LOCAL_BROADCAST" />
    4             </intent-filter>
    5         </receiver>

      4、这时如果也让另一个程序接收LOCAL_BROADCAST这个广播,会发现是接收不到的。

      5、本地广播的优点:

      (1)不用担心机密数据泄露。

      (2)其他程序无法将广播发送到我们程序的内容,不用担心安全漏洞的问题。

      (3)比全局广播更高效。

      (五)最佳实践——实现强制下线功能

      在登录页面输入账号密码进入主界面后,点击强制下线按钮会弹出强制下线Dialog,并且该Dialog不能被取消,当用户点击确定后会发出强制下线广播,再次跳转到登录界面。

      1、login.xml文件:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent"
     5     android:stretchColumns="1" >
     6 
     7     <TableRow>
     8 
     9         <TextView
    10             android:layout_height="wrap_content"
    11             android:text="用户名:" />
    12 
    13         <EditText
    14             android:id="@+id/user_name_et"
    15             android:layout_height="wrap_content"
    16             android:hint="请输入用户名" />
    17     </TableRow>
    18 
    19     <TableRow>
    20 
    21         <TextView
    22             android:layout_height="wrap_content"
    23             android:text="密码:" />
    24 
    25         <EditText
    26             android:id="@+id/password_et"
    27             android:layout_height="wrap_content" >
    28         </EditText>
    29     </TableRow>
    30 
    31     <TableRow>
    32 
    33         <Button
    34             android:id="@+id/login_bt"
    35             android:layout_height="wrap_content"
    36             android:layout_span="2"
    37             android:text="登录" />
    38     </TableRow>
    39 
    40 </TableLayout>

      2、ActivityCollector类:

     1 public class ActivityCollector {
     2     public static List<Activity> activities = new ArrayList<Activity>();
     3 
     4     public static void addActivity(Activity activity) {
     5         activities.add(activity);
     6     }
     7 
     8     public static void removeActivity(Activity activity) {
     9         activities.remove(activity);
    10     }
    11 
    12     public static void finishAll() {
    13         for (Activity activity : activities) {
    14             if (!activity.isFinishing()) {
    15                 activity.finish();
    16             }
    17         }
    18     }
    19 }

      3、BaseActivity类:

     1 public class BaseActivity extends Activity {
     2     @Override
     3     protected void onCreate(Bundle savedInstanceState) {
     4         super.onCreate(savedInstanceState);
     5 
     6         ActivityCollector.addActivity(this);
     7     }
     8 
     9     @Override
    10     protected void onDestroy() {
    11         super.onDestroy();
    12         ActivityCollector.removeActivity(this);
    13     }
    14 }

      4、LoginActivity类:

     1 public class LoginActivity extends BaseActivity {
     2 
     3     private EditText userNameEt;
     4     private EditText passwordEt;
     5     private Button loginBt;
     6 
     7     @Override
     8     protected void onCreate(Bundle savedInstanceState) {
     9         super.onCreate(savedInstanceState);
    10         setContentView(R.layout.login);
    11 
    12         userNameEt = (EditText) findViewById(R.id.user_name_et);
    13         passwordEt = (EditText) findViewById(R.id.password_et);
    14         loginBt = (Button) findViewById(R.id.login_bt);
    15 
    16         loginBt.setOnClickListener(new OnClickListener() {
    17 
    18             @Override
    19             public void onClick(View v) {
    20                 String userName = userNameEt.getText().toString();
    21                 String password = passwordEt.getText().toString();
    22 
    23                 // 如果用户名是admin且密码是123456,就认为登录成功
    24                 if (userName.equals("110") && password.equals("123456")) {
    25                     Intent intent = new Intent(LoginActivity.this,
    26                             MainActivity.class);
    27                     startActivity(intent);
    28                     finish();
    29                 } else {
    30                     Toast.makeText(LoginActivity.this, "用户名或密码错误!",
    31                             Toast.LENGTH_SHORT).show();
    32                 }
    33             }
    34         });
    35     }
    36 }

      5、activity_main.xml:

     1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     xmlns:tools="http://schemas.android.com/tools"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent"
     5     android:paddingBottom="@dimen/activity_vertical_margin"
     6     android:paddingLeft="@dimen/activity_horizontal_margin"
     7     android:paddingRight="@dimen/activity_horizontal_margin"
     8     android:paddingTop="@dimen/activity_vertical_margin"
     9     tools:context="com.example.broadcastbestpractice.MainActivity" >
    10 
    11     <TextView
    12         android:layout_width="wrap_content"
    13         android:layout_height="wrap_content"
    14         android:text="这里是主界面" />
    15 
    16     <Button
    17         android:id="@+id/force_offline_bt"
    18         android:layout_width="match_parent"
    19         android:layout_height="wrap_content"
    20         android:layout_margin="40dp"
    21         android:text="发送一个强制下线广播" />
    22 
    23 </RelativeLayout>

      6、MainActivity类:

     1 public class MainActivity extends Activity {
     2 
     3     @Override
     4     protected void onCreate(Bundle savedInstanceState) {
     5         super.onCreate(savedInstanceState);
     6         setContentView(R.layout.activity_main);
     7 
     8         Button forceOfflineBt = (Button) findViewById(R.id.force_offline_bt);
     9         forceOfflineBt.setOnClickListener(new OnClickListener() {
    10 
    11             @Override
    12             public void onClick(View v) {
    13                 Intent intent = new Intent(
    14                         "com.example.broadcastbestpractice.FORCE_OFFLINE");
    15                 sendBroadcast(intent);
    16             }
    17         });
    18     }
    19 
    20 }

      7、ForceOfflineReceiver:

     1 public class ForceOfflineReceiver extends BroadcastReceiver {
     2 
     3     @Override
     4     public void onReceive(final Context context, Intent intent) {
     5         AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
     6         dialogBuilder.setTitle("警告");
     7         dialogBuilder.setMessage("你将要被强制下线!请重新登录!");
     8         dialogBuilder.setCancelable(false);
     9         dialogBuilder.setPositiveButton("确定",
    10                 new DialogInterface.OnClickListener() {
    11 
    12                     @Override
    13                     public void onClick(DialogInterface dialog, int which) {
    14                         ActivityCollector.finishAll();
    15                         Intent intent = new Intent(context, LoginActivity.class);
    16                         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    17                         context.startActivity(intent);
    18                     }
    19                 });
    20 
    21         AlertDialog alertDialog = dialogBuilder.create();
    22         alertDialog.getWindow().setType(
    23                 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
    24         alertDialog.show();
    25     }
    26 }

      8、AndroidManifest.xml:

     1 ...
     2      <activity
     3             android:name=".LoginActivity"
     4             android:label="@string/app_name" >
     5             <intent-filter>
     6                 <action android:name="android.intent.action.MAIN" />
     7 
     8                 <category android:name="android.intent.category.LAUNCHER" />
     9             </intent-filter>
    10         </activity>
    11         <activity android:name=".MainActivity" >
    12         </activity>
    13 
    14         <receiver
    15             android:name=".ForceOfflineReceiver"
    16             android:exported="false" >
    17             <intent-filter>
    18                 <action android:name="com.example.broadcastbestpractice.FORCE_OFFLINE" />
    19             </intent-filter>
    20         </receiver>
    21 ...

     

     

     

     

     

     

     

     

  • 相关阅读:
    在Arduino IDE中安装ESP32 Filesystem Uploader
    人工智能必备数学基础:线性代数基础(1)
    人工智能必备数学基础:高等数学基础(3)
    迟到的=2020=年终总结
    常用软件-官方下载地址
    海康、大华的RTSP地址规则说明及通道问题(重点)
    各类服务器性能的瓶颈分析
    分析影响流媒体服务器性能的硬件瓶颈
    linux下程序、动态库、静态库内部添加版本号和编译时间与Windows下Qt 如何给程序添加版本信息
    css link import 两者之间的区别
  • 原文地址:https://www.cnblogs.com/jiayongji/p/5329265.html
Copyright © 2020-2023  润新知