《第一行代码: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 ...

 

 

时间: 2024-10-05 21:21:49

《第一行代码:Android》读书笔记——第5章 Broadcast的相关文章

阅读郭林《第一行代码》的笔记——第6章 数据存储全方案,详解持久化技术

瞬时数据是指那些存储在内存当中,有可能会因为程序关闭或其他原因导致内存被回收而丢失的数据.这对于一些关键性的数据信息来说是绝对不能容忍的,谁都不希望自己刚发出去的一条微博,刷新一下就没了吧.那么怎样才能保证让一些关键性的数据不会丢失呢?这就需要用到数据持久化技术了. 持久化技术简介 数据持久化就是指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或电脑关机的情况下,这些数据仍然不会丢失.保存在内存中的数据是处于瞬时状态的,而保存在存储设备中的数据是处于持久状态的,持久化技术则是提供了一种机

《第一行代码》读书笔记

一: 1:项目文件 开发中经常用到的有: app目录:存放项目代码.资源文件 build.gradle:项目全局gradle脚本. 2:app目录 libs:放到libs目录下的第三方jar包会自动添加到项目构建路径. java:存放java代码的地方. res:资源文件目录,包括:图片.布局.字符串.颜色.样式.菜单等. AndroidManifest.xml:项目配置文件.多用于注册四大组.添加权限等. proguard-rules.pro:项目代码混淆规则. 3:build.gradle逐

《第一行代码》读书笔记-2

gravity的对齐方式有top,bottom,left,right,center可以用"|"同时选取. wrap_content 适配内容,保证显示完整. match_parent:父布局决定大小 默认人提示性文字:hint xml中给imageview添加图片:src= activity中设置图片,imageview.setimageresource(id); progressbar visible:可见 invisible:隐身  gone:不在屏幕上 设置方法:setvisib

使用Intent在活动之间穿梭(《第一行代码》读书笔记)

以下全是个人理解//瞎扯 其实活动理解理解起来就像一个个函数 那么Intent就是调用函数和参数传递 可以有无参,仅仅是调用 Intent intent = new Intent(A.this, B.class); startActivity(intent); 由活动A调用活动B,无参,无返回值,当然B调用结束,要回到A. 可以有参数 A---Intent intent = new Intent(A.this, B.class); intent.putExtra( "这里是参数的键"

《第一行代码》读书笔记-1

assets文件夹存放随程序打包的文件 libs存放第三方Jar包 R.string.xxx获得对该字符串的引用 Log.vdiwe->i---info XM文件中引用一个id:@id/id_name 定义一个id:@+id/id_name 隐藏标题栏在activity中:requestwindowfeature(window.feature_no_title);在setcontentview之前执行. menu intent的action配合category属性区分intent的目的 inte

阅读郭林《第一行代码》的笔记——第2章 先从看得到的入手,探究活动

一.活动是什么,活动的基本用法 活动(Activity)是最容易吸引到用户的地方了,它是一种可以包含用户界面的组件,主要用于和用户进行交互.一个应用程序中可以包含零个或多个活动,但不包含任何活动的应用程序很少见,谁也不想让自己的应用永远无法被用户看到吧? Android程序的设计讲究逻辑和视图分离,最好每一个活动都能对应一个布局,布局就是用来显示界面内容的. 创建和加载布局 @Override protected void onCreate(Bundle savedInstanceState)

《第一行代码》学习笔记 第 2 章

第 2 章 先从看得到的入手,探究活动 知识点1:在活动中使用 Menu 在 res 目录下新建一个 menu 文件夹,右击 menu文件夹→New→Android XML File,文件名输入 main 在 main.xml 中添加如下代码: <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/add_item" and

《第一行代码——Android》封面诞生记

<第一行代码——Android>已经上市快一个月了,目前销售情况还算良好,也是特别感谢众多朋友的支持.其实一本书如果想要卖的好,除了内容必 须要给力之外,封面的设计也是至关重要的,而本书的封面无疑是在充实的内容之外又披上了一层华丽的外衣.作为作者,其实我的任务就是将内容写好而已,其它 所有相关工作都不是由我负责的.本书封面设计的所有细节都是由陈冰先生一手抓起的,之后他在图灵社区上记录了本书封面的诞生过程.在经过他同意的情况下, 我将这篇文章转到我的博客上,也是让感兴趣的朋友们了解一些不为人知的

历时一年,我的著作《第一行代码——Android》火爆预售!

前言 其实我当初决定开始写博客的想法挺简单的,觉得自己搞技术这么多年了,总应该要留下点什么.既然没能写出什么出色的应用,那至少也要留下点文字分享给大家,以指引在我后面的开发者们,毕竟我也从前辈们的博客那里受惠了很多. 受邀 下定决心之后我就开始了我的博客之旅,令我没想到的是,我写的文章竟然非常受大家的欢迎,短时间内就聚集了大量的人气.更令我没想到的事,在我开始写博客不久之后,人民邮电出版社图灵公司的副总编辑陈冰先生就联系上了我,希望我可以写一本关于Android开发技术的书籍! 陈冰,第一次听到

历时一年,我的著作《第一行代码——Android》已出版!

前言 事实上我当初决定開始写博客的想法挺简单的,认为自己搞技术这么多年了,总应该要留下点什么.既然没能写出什么出色的应用,那至少也要留下点文字分享给大家,以指引在我后面的开发人员们,毕竟我也从前辈们的博客那里受惠了非常多. 受邀 下定决心之后我就開始了我的博客之旅,令我没想到的是,我写的文章居然非常受大家的欢迎,短时间内就聚集了大量的人气.更令我没想到的事,在我開始写博客不久之后,人民邮电出版社图灵公司的副总编辑陈冰先生就联系上了我,希望我能够写一本关于Android开发技术的书籍! 陈冰,第一