Broadcast 使用详解
极力推荐文章:欢迎收藏
Android 干货分享
阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android
本篇文章主要介绍 Android
开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:
- 广播的生命周期
- 四大组件之一,必须在Androidmainfest.xml中注册
- 广播的注册(静态广播、动态广播)
- 广播的发送(正常、有序、持续)
- 广播接收(系统广播、自定义广播)
Broadcast
是 Android
四大组件之一,是一种广泛运用在应用程序之间异步传输信息的机制。
Broadcast
本质上是一个Intent
对象,差别在于Broadcast
可以被多个 BroadcastReceiver
处理。BroadcastReceiver
是一个全局监听器,通过它的 onReceive()
可以过滤用户想要的广播,进而进行其它操作。
1. BroadcastReceiver简介
BroadcastReceiver继承关系
BroadcastReceiver
默认是在主线程中执行,如果onReceiver()
方法处理事件超过10s
,则应用将会发生ANR(Application Not Responding)
,此时,如果建立工作线程并不能解决此问题,因此建议:如处理耗时操作,请用 Service
代替。
BroadcastReceiver
继承关系 如下:
java.lang.Object
↳ android.content.BroadcastReceiver
BroadcastReceiver
的主要声明周期方法onReceiver()
,此方法执行完之后,BroadcastReceiver
实例将被销毁。
2.四大组件之一,必须在Androidmainfest.xml中注册
<receiver
android:name="ReceiverMethod"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="String....." />
</intent-filter>
</receiver>
注意:
如不注册,将导致无法接收处理广播消息
3.广播的注册(静态注册、动态注册)
广播的注册分两种,一种在ndroidMfest.xml
中静态注册,另一种是在Java
代码中动态注册。
1.静态注册
一些系统发送的广播需要在Androidmainfest.xml
中静态注册,例如 开机广播,apk状态改变广播,电量状态改变广播等。这些静态注册的广播,通常在Androidmainfest.xml
中拦截特定的字符串。
静态注册广播的方法如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.programandroid"
android:versionCode="1"
android:versionName="1.0" >
... ...
<receiver
android:name="com.programandroid.BroadcastReceiver.NotificationReceived"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="Notification_cancel" />
<action android:name="Notification_music_pre" />
<action android:name="Notification_music_play" />
<action android:name="Notification_music_next" />
</intent-filter>
</receiver>
... ...
1.静态注册开机广播方法
开机广播比较特殊,需要在Androidmainfest.xml
中添加权限。否则,无法获取开机广播。
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
//静态注册广播的方法
<receiver
android:name=".component.BroadcastReceiver.BootReceiverMethod"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
2.动态注册广播
在Java中动态注册广播,通常格式如下:
//动态注册广播
registerReceiver(BroadcastReceiver, IntentFilter);
动态注册 监听灭屏、点亮屏幕的广播
在广播中动态注册广播请注意一定要使用context.getApplicationContext()
,防止context
为空 ,引起空指针异常。
public class ScreenOnOffReceiver {
public static void ReceiverScreenOnOff(Context context) {
IntentFilter screenOffFilter = new IntentFilter();
screenOffFilter.addAction(Intent.ACTION_SCREEN_OFF);
screenOffFilter.addAction(Intent.ACTION_SCREEN_ON);
BroadcastReceiver mScreenOnOffReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String action = intent.getAction();
if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Toast.makeText(context, "接收屏幕熄灭广播", Toast.LENGTH_SHORT).show();
}
if (action.equals(Intent.ACTION_SCREEN_ON)) {
Toast.makeText(context, "接收屏幕点亮广播", Toast.LENGTH_SHORT).show();
}
}
};
/**
* context.getApplicationContext()
* 在广播中注册广播时候需要注意,防止context 为空 ,引起空指针异常
* **/
// 2.动态注册广播的方法
context.registerReceiver(mScreenOnOffReceiver, screenOffFilter);
}
}
4.广播的发送(无序、有序、持续)
1.发送无序广播的方法
发送无序广播在Android
中很常见,是一种一对多的关系,主要通过 sendBroadcast(intent);
发送广播。
发送自定义广播案例
广播说白了就是一个带Action
等字符串标记的Intent
。发送自定义广播举例如下:
Intent customIntent=new Intent();
customIntent.setAction("SendCustomBroadcast");
sendBroadcast(customIntent);
接收自定义广播的方法
当用户对某些广播感兴趣的话,此时可以获取此广播,然后在onReceive
方法中处理接收广播的一下操作。
public class CustomBroadcast extends BroadcastReceiver {
public CustomBroadcast() {
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("SendCustomBroadcast")){
Toast.makeText(context,"自定义广播接收成功:Action:SendCustomBroadcast",Toast.LENGTH_SHORT).show();
}
}
}
注意自定义广播是在
Androidmanfest.xml
中静态注册的。
2.发送有序广播
广播在Android
是有优先级的,优先级高的广播可以终止或修改广播内容。发送有序广播的方法如下sendOrderedBroadcast(intent,"str_receiver_permission");
例如:发送自定义有序广播
Intent customOrderIntent=new Intent();
customOrderIntent.setAction("SendCustomOrderBroadcast");
customOrderIntent.putExtra("str_order_broadcast","老板说:公司每人发 10 个 月饼");
sendOrderedBroadcast(customOrderIntent,"android.permission.ORDERBROADCAST");
广播属于四大组件,一定要在AndroidMainfest.xml
中注册。
有序广播静态注册
接收有序广播的静态注册方法如下:
<receiver
android:name=".component.BroadcastReceiver.CustomHightBrodcast"
android:enabled="true"
android:exported="true"
>
<intent-filter android:priority="1000">
<action android:name="SendCustomOrderBroadcast" />
</intent-filter>
</receiver>
<receiver
android:name=".component.BroadcastReceiver.CustomMiddleBroadcast"
android:enabled="true"
android:exported="true"
>
<intent-filter android:priority="500">
<action android:name="SendCustomOrderBroadcast" />
</intent-filter>
</receiver>
<receiver
android:name=".component.BroadcastReceiver.CustomLowerBroadcast"
android:enabled="true"
android:exported="true"
>
<intent-filter android:priority="100">
<action android:name="SendCustomOrderBroadcast" />
</intent-filter>
</receiver>
-
- 有序广播,高优先级广播可以优先处理
public class CustomHightBrodcast extends BroadcastReceiver {
public CustomHightBrodcast() {
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("SendCustomOrderBroadcast")) {
Toast.makeText(context, intent.getStringExtra("str_order_broadcast"), Toast.LENGTH_SHORT).show();
Bundle bundle=new Bundle();
bundle.putString("str_order_broadcast","经理说:公司每人发 5 个 月饼");
// 修改广播传输数据
setResultExtras(bundle);
}
}
}
-
- 中优先级的广播后序处理
public class CustomMiddleBroadcast extends BroadcastReceiver {
public CustomMiddleBroadcast() {
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("SendCustomOrderBroadcast")) {
Toast.makeText(context, getResultExtras(true).getString("str_order_broadcast"), Toast.LENGTH_SHORT).show();
Bundle bundle=new Bundle();
bundle.putString("str_order_broadcast","主管说:公司每人发 2 个 月饼");
setResultExtras(bundle);
}
}
}
-
- 低优先级广播最后处理
public class CustomLowerBroadcast extends BroadcastReceiver {
public CustomLowerBroadcast() {
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("SendCustomOrderBroadcast")) {
String notice= getResultExtras(true).getString("str_order_broadcast");
Toast.makeText(context,notice, Toast.LENGTH_SHORT).show();
// 终止广播继续传播下去
abortBroadcast();
}
}
}
注意 :
有序广播需要声明并使用权限
- 1.声明使用权限
<!-- 申请使用自定义 有序广播的权限 -->
<uses-permission > android:name="android.permission.ORDERBROADCAST" />
- 2.声明权限
<!-- 自定义 有序广播的权限 -->
<permission>
android:name="android.permission.ORDERBROADCAST"/>
在有序广播中高优先级的广播接收广播,可以修改数据,然后传给低优先级的广播。
3.发送持续广播(已经被弃用)
粘性广播会在Android
系统中一直存在,不过随着 Android
系统的不断更新,此方法逐渐被抛弃,使用方法如下:sendStickyBroadcast(intent);
5.广播接收(系统广播、自定义广播)
当广播发出后,如何接收广播呢,下面将介绍接收广播的方法。
接受广播类 主要继承 BroadcastReceiver
,然后在onReceive
方法,过滤广播Action
中携带的Intent
,然后进行相关处理。
接收开机广播的方法
1. 实现BootReceiverMethod 继承 BroadcastReceiver
p ublic class BootReceiverMethod extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 接收开机广播处理事情,比如启动服务
Intent mStartIntent = new Intent(context, StartServiceMethods.class);
context.startService(mStartIntent);
}
}
2.在Androidmainfest.xml 声明组件信息,并过滤开机完成 Action
<receiver
android:name=".component.BroadcastReceiver.BootReceiverMethod"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
3.声明接收开机广播完成的权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
极力推荐文章:欢迎收藏
Android 干货分享
阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android
本篇文章主要介绍 Android
开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:
- Service 简介
- 四大组件之一,必须在Androidmainfest.xml 中注册
- 启动模式启动服务
- 绑定模式绑定服务
- 前台服务
- AIDL远程服务
Service
是Android
四大组件之一(Activity
活动,Service
服务,ContentProvider
内容提供者,BroadcastReceiver
广播),与Activity
相比,Activity
是运行在前台,用户可以看得见,Service
则是运行在后台,无用户界面,用户无法看到。
Service
主要用于组件之间交互(例如:与Activity
、ContentProvider
、BroadcastReceiver
进行交互)、后台执行耗时操作等(例如下载文件,播放音乐等,但Service
在主线程运行时长不能超过20s
,否则会出现ANR
,耗时操作一般建议在子线程中进行操作)。
1.Service 简介
在了解Service
的生命周期的之前,我们先了解一下Service
的继承关系,方便我们更好的了解Service
。
Service 继承关系如下:
java.lang.Object
↳ android.content.Context
↳ android.content.ContextWrapper
↳ android.app.Service
Service 的两种启动模式
Service
有两种不同的启动模式 ,不同的启动模式对应不同生命周期.
Service
启动模式主要分两种: 1. 启动模式。 2. 绑定模式。
1.启动模式
此模式通过 startService()
方法启动,此服务可以在后台一直运行,不会随启动组件的消亡而消亡。只能执行单一操作,无法返回结果给调用方,常用于网络下载、上传文件,播放音乐等。
2.绑定模式
此模式 通过绑定组件(Activity
等)调用 bindService()
启动,此服务随绑定组件的消亡而解除绑定。
如果此时没有其它通过startService()
启动,则此服务会随绑定组件的消亡而消亡。
多个组件不仅可以同时绑定一个Service
,而且可以通过进程间通信(IPC)
执行跨进程操作等。
3.两种服务可以同时运行
启动模式与绑定模式的服务可以同时运行,在销毁服务时,只有两种模式都不在使用Service
时候,才可以销毁服务,否则会引起异常。
4. 两种 Service 模式的生命周期
两种 Service
模式的生命周期如下:
2.四大组件之一,必须在Androidmainfest.xml 中注册
Service 注册方法如下:
<manifest ... >
...
<application ... >
<service android:name=".ServiceMethods" />
...
</application>
</manifest>
注意:
Service
如不注册 ,不会像Activity
那样会导致App Crash
,Service
不注册 不会报异常信息,但是服务会起不来,如不注意很容易迷惑。
3.启动模式
通过启动模式启动的Service
,如不主动关闭,Service
会一直在。
启动模式启动服务的方法
Intent mBindIntent = new Intent(ServiceMethods.this, BindServiceMethods.class);
startService(mStartIntent);
启动模式启动服务的生命周期
下面是验证启动模式启动服务的生命周期的方法,详细生命周期请查看上方Service
的生命周期图。
01-03 17:16:36.147 23789-23789/com.android.program.programandroid I/StartService wjwj:: ----onCreate----
01-03 17:16:36.223 23789-23789/com.android.program.programandroid I/StartService wjwj:: ----onStartCommand----
01-03 17:16:38.174 23789-23789/com.android.program.programandroid I/StartService wjwj:: ----onDestroy----
启动模式 启动服务案例
此案例功能:启动服务,在服务中创建通知
// Service 创建方法
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "----onCreate----");
}
// Service 启动方法
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "----onStartCommand----");
// 获取NotificationManager实例
notifyManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// 实例化NotificationCompat.Builder并设置相关属性
NotificationCompat.Builder builder = new NotificationCompat.Builder(
this)
// 设置小图标
.setSmallIcon(R.drawable.ic_launcher)
.setLargeIcon(
BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher))
// 设置通知标题
.setContentTitle("我是通过StartService服务启动的通知")
// 设置通知不能自动取消
.setAutoCancel(false).setOngoing(true)
// 设置通知时间,默认为系统发出通知的时间,通常不用设置
// .setWhen(System.currentTimeMillis())
// 设置通知内容
.setContentText("请使用StopService 方法停止服务");
// 通过builder.build()方法生成Notification对象,并发送通知,id=1
notifyManager.notify(1, builder.build());
return super.onStartCommand(intent, flags, startId);
}
// Service 销毁方法
@Override
public void onDestroy() {
Log.i(TAG, "----onDestroy----");
notifyManager.cancelAll();
super.onDestroy();
}
4. 绑定模式启动绑定服务
绑定模式启动的服务会随着绑定逐渐的消亡而解除Service
绑定,如果此时Service
没有通过启动模式启动,则此服务将会被销毁。
绑定模式启动绑定服务的方法
绑定模式,是通过其他组件启动的Service
。
启动绑定模式服务的方法
// 启动绑定服务处理方法
public void BtnStartBindService(View view) {
// 启动绑定服务处理方法
bindService(mBindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
isBindService = true;
Toast.makeText(ServiceMethod.this, "启动 " + mBindCount + " 次绑定服务",
Toast.LENGTH_SHORT).show();
}
public void BtnSopBindService(View view) {
if (isBindService) {
// 解除绑定服务处理方法
unbindService(serviceConnection);
Toast.makeText(ServiceMethod.this, "解除 " + mUnBindCount + " 次绑定服务",
Toast.LENGTH_SHORT).show();
isBindService = false;
}
}
绑定服务 随绑定组件的消亡而消亡
绑定模式 生命周期回调代码如下:
// Service 创建方法
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "----onCreate----");
}
// Service 绑定方法
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "----onBind----");
MyBinder myBinder = new MyBinder();
return myBinder;
}
// Service 解除绑定方法
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "----onUnbind----");
return super.onUnbind(intent);
}
// Service 销毁方法
@Override
public void onDestroy() {
Log.i(TAG, "----onDestroy----");
super.onDestroy();
}
绑定服务的生命周期代码打印Log
信息如下:
01-03 20:32:59.422 13306-13306/com.android.program.programandroid I/BindService wjwj:: ----onCreate----
01-03 20:32:59.423 13306-13306/com.android.program.programandroid I/BindService wjwj:: -----onBind-----
01-03 20:33:09.265 13306-13306/com.android.program.programandroid I/BindService wjwj:: ----onUnbind----
01-03 20:33:09.266 13306-13306/com.android.program.programandroid I/BindService wjwj:: ----onDestroy----
绑定服务案例
功能:获取绑定模式启动 绑定服务及解除绑定服务的次数
绑定服务类
package com.android.program.programandroid.component.Service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class BindServiceMethods extends Service {
private static final String TAG = "BindService wjwj:";
public BindServiceMethods() {
}
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "----onCreate----");
}
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "----onBind----");
MyBinder myBinder = new MyBinder();
return myBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "----onUnbind----");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.i(TAG, "----onDestroy----");
super.onDestroy();
}
}
- 组件与绑定服务类之间的交互
// 启动绑定服务处理方法
public void BtnStartBindService(View view) {
bindService(mBindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
isBindService = true;
Toast.makeText(ServiceMethods.this,"启动 "+mBindCount+" 次绑定服务",Toast.LENGTH_SHORT).show();
}
// 解除绑定服务处理方法
public void BtnSopBindService(View view) {
if (isBindService) {
unbindService(serviceConnection);
Toast.makeText(ServiceMethods.this,"解除 "+mUnBindCount+" 次绑定服务",Toast.LENGTH_SHORT).show();
isBindService=false;
}
}
- 组件之间交互所需的
Binder
接口类
/**
* 该类提供 绑定组件与绑定服务提供接口
* */
public class MyBinder extends Binder {
private int count = 0;
public int getBindCount() {
return ++count;
}
public int getUnBindCount() {
return count> 0 ? count-- : 0;
}
}
5. 提高服务的优先级
服务默认启动方式是后台服务,但是可以通过设置服务为前台服务,提高服务的优先级,进而避免手机内存紧张时,服务进程被杀掉。
设置前台服务的两种方法
1.设置为前台服务
//设置为前台服务
startForeground(int, Notification)
2.取消前台服务
//取消为前台服务
stopForeground(true);
startForeground 前台服务案例
功能:前台服务绑定通知信息,提高服务进程优先级,否则取消通知信息
package com.android.program.programandroid.component.Service;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import com.android.program.programandroid.R;
public class MyStartForcegroundService extends Service {
public MyStartForcegroundService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals("start_forceground_service")) {
// 获取NotificationManager实例
NotificationManager notifyManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// 实例化NotificationCompat.Builder并设置相关属性
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
// 设置小图标
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
// 设置通知标题
.setContentTitle("我是通过startForeground 启动前台服务通知")
// 设置通知不能自动取消
.setAutoCancel(false)
.setOngoing(true)
// 设置通知时间,默认为系统发出通知的时间,通常不用设置
// .setWhen(System.currentTimeMillis())
// 设置通知内容
.setContentText("请使用stopForeground 方法改为后台服务");
//通过builder.build()方法生成Notification对象,并发送通知,id=1
// 设置为前台服务
startForeground(1, builder.build());
} else if (intent.getAction().equals("stop_forceground_service")) {
stopForeground(true);
}
return super.onStartCommand(intent, flags, startId);
}
}
6. 使用AIDL接口实现远程绑定
由于内容较多,后续另开一篇详细介绍。
至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!