Android开发笔记(四十二)Broadcast的生命周期

2019-01-18 10:40:58 浏览数 (1)

Broadcast是什么

广播的特性

广播(Broadcast)用于Android组件之间的灵活通信,它与Activity和Service的区别在于: 1、Activity和Service都只能一对一地通信,而Broadcast可以一对多,一人发送广播,多人接收处理; 2、对于发送者来说,广播不需要考虑接收者有没有在工作,接收者有在工作则接收广播,不在工作则丢弃广播; 3、对于接收者来说,会收到各式各样的广播,所以接收者首先要自行过滤符合条件的,然后才能进行解包处理; 4、通常情况下,Activity和Service都是在线程内部通信,而Broadcast既可用于线程内通信,也可用于线程间通信,还能用于进程间通信;

广播的用途

实际开发中,广播一般有以下用途: 1、适用于在不同代码文件中操纵对方页面控件的场景,比如说FragmentActivity与Fragment代码间通信,以及Activity与Adapter代码间通信; 2、适用于不同线程之间的通信,虽然线程间通信可使用Thread Handler、AsyncTask等方式,但是广播的适应面显然更广,Android总线通信框架EventBus就是基于Broadcast来构建的; 3、适用于不同进程之间的通信,既可用于不同APP之间的通信,也可用于系统与APP之间的通信;

Broadcast的调用

广播的调用方法

sendBroadcast : 发送广播 registerReceiver : 注册接收器,一般在onStart或者onResume方法中注册 unregisterReceiver : 注销接收器,一般在onStop或者onPause方法中注销

进程内广播与进程间广播

如果广播是在应用之内使用,即不需要跨进程,可以考虑使用LocalBroadcastManager,因为这样更有效率(不需要跨进程通信),而且不用考虑广播开放造成的安全问题(如果其他应用也能收到广播的话)。 进程内广播,推荐使用LocalBroadcastManager类下的registerReceiver和unregisterReceiver方法,代码示例如下:

代码语言:javascript复制
//注册接收器
LocalBroadcastManager.getInstance(this).registerReceiver(guestReceiver, filter);
//注销接收器
LocalBroadcastManager.getInstance(this).unregisterReceiver(guestReceiver);

进程间通讯,推荐使用Context类下的registerReceiver和unregisterReceiver方法,代码示例如下:

代码语言:javascript复制
//注册接收器,如在activity使用,可去掉mContext,直接调用registerReceiver和unregisterReceiver
mContext.registerReceiver(guestReceiver, filter);
//注销接收器
mContext.unregisterReceiver(guestReceiver);

Broadcast的生命周期

发送广播

发送广播很简单,只管把请求发出去,不关心请求的处理结果,代码示例如下:

代码语言:javascript复制
Intent intent = new Intent("com.example.exmbrdlife.fragment");
intent.putExtra("guest", "孙悟空");
//发送全局广播
//mContext.sendBroadcast(intent);
//发送本地广播
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);

接收广播的方式

广播接收分动态注册、静态注册、嵌套注册三种方式。 动态注册,指的是在代码中调用方法registerReceiver和unregisterReceiver;它的生命周期开始于registerReceiver,结束于unregisterReceiver,通常伴随某个Activity的生命周期。 静态注册,指的是在AndroidManifest.xml中注册receiver接收器,receiver节点与activity和service节点是平级关系;它的生命周期开始于系统启动,结束于系统关机,在系统运行过程中,只要收到符合条件的广播,接收器便会启动工作。下面是在xml文件中静态注册的例子:

代码语言:javascript复制
        <receiver android:name="com.app.mastersec.notify.BootReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />


                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </receiver>

嵌套注册,也要在AndroidManifest.xml中注册receiver接收器。它与静态注册的区别在于:静态注册的receiver代码是单独的java文件,而嵌套注册的receiver代码是嵌入在某个java类中,所以注册时要在receiver类名前加上“属主类名$”。另外,嵌套注册的receiver类在定义时也要加上static标记,这样才能正常访问。下面是在xml文件中嵌套注册的例子:

代码语言:javascript复制
        <receiver android:name=".DownloadActivity$DownloadCompleteReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
            </intent-filter>
        </receiver>

接收APP广播(动态注册方式)

接收APP广播即可采用动态注册也可采用静态注册,下面代码以动态注册方式举例说明:

代码语言:javascript复制
	@Override
	public void onStart() {
		super.onStart();
		guestReceiver = new GuestReceiver();
		IntentFilter filter = new IntentFilter("com.example.exmbrdlife.fragment");
		LocalBroadcastManager.getInstance(this).registerReceiver(guestReceiver, filter);
	}


	@Override
	public void onStop() {
		LocalBroadcastManager.getInstance(this).unregisterReceiver(guestReceiver);
		super.onStop();
	}


    private GuestReceiver guestReceiver;
    private class GuestReceiver extends BroadcastReceiver {


        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent != null) {
                String guest = intent.getStringExtra("guest");
                Toast.makeText(MainActivity.this, "您的客人是" guest, Toast.LENGTH_LONG).show();
            }
        }
    }

注意上面在注册广播时使用了IntentFilter类来过滤,只有符合过滤条件的广播才会被接收处理。

接收系统广播(静态注册方式)

接收系统广播只能使用静态注册方式,下面代码以系统开机广播作为例子,xml修改部分在上面AndroidManifest.xml例子中给出了:

代码语言:javascript复制
import com.app.mastersec.util.ServiceUtil;


import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import com.app.mastersec.util.LogUtil;


public class BootReceiver extends BroadcastReceiver {
	private static final String TAG = "BootReceiver";


	@Override
	public void onReceive(Context context, Intent intent) {
		if (intent != null) {
			if(intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
				//在系统开机后启动该APP的服务
				if (ServiceUtil.isWorked(context, ServiceUtil.notify_service) != true) {
					LogUtil.debug(TAG, "receive boot action, start service");
					Intent mIntent = new Intent(context, NotifyService.class);
					Bundle bundle = new Bundle();
					bundle.putInt("start_type", NotifySend.SYSTEM_BOOT);
					mIntent.putExtras(bundle);
					context.startService(mIntent);
				}
			}
		}
	}

}

系统广播列表

下面是几个常用的系统广播说明: Intent类 ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; //系统启动完毕,注意要想响应该广播的话,还需增加权限RECEIVE_BOOT_COMPLETED     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> ACTION_TIME_TICK = "android.intent.action.TIME_TICK"; //每分钟一次的广播 ACTION_TIMEZONE_CHANGED = "android.intent.action.TIMEZONE_CHANGED"; //时区设置改变 ACTION_DATE_CHANGED = "android.intent.action.DATE_CHANGED"; //日期设置改变 ACTION_TIME_CHANGED = "android.intent.action.TIME_SET"; //时间设置改变 ACTION_ALARM_CHANGED = "android.intent.action.ALARM_CHANGED"; //闹钟设置改变 ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED"; //电池电量改变 ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF"; //屏幕保护 ACTION_SCREEN_ON = "android.intent.action.SCREEN_ON"; //屏幕恢复 ConnectivityManager类 CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; //网络连接改变 WifiManager类 WIFI_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_STATE_CHANGED"; //wifi状态改变

Broadcast的演示例子

为加深对广播用法的理解,下面给出一个ActionBar与ViewPager结合的例子,在Fragment中控制ActionBar的背景。正好博主也复习下ActionBar中标签页的使用,相关博文见《Android开发笔记(二十)顶部导航栏ActionBar》。 我们知道,把ActionBar的导航模式设置为ActionBar.NAVIGATION_MODE_TABS,即可在导航栏下方调用addTab方法添加具体标签页,通过点击标签页来切换ViewPager页面,从而实现完整的Tab页切换效果。Tab标签页的点击事件需要注册监听器TabListener,在onTabSelected方法中指定当前的ViewPager页面;同样ViewPager的翻页事件也需注册监听器OnPageChangeListener,在onPageSelected方法中指定当前的Tab标签。关键方法onTabSelected和onPageSelected的代码示例如下:

代码语言:javascript复制
	@Override
	public void onTabSelected(Tab tab, FragmentTransaction ft) {
		mViewPager.setCurrentItem(tab.getPosition());
	}


	@Override
	public void onPageSelected(int arg0) {
		mActionBar.selectTab(mActionBar.getTabAt(arg0));
	}

上面可以看到,ViewPager通过setCurrentItem方法来设置当前页面,而Tab要稍复杂些,用到的有三个方法,分别是getPosition(获取当前Tab的位置)、getTabAt(获取指定位置的Tab)、selectTab(设置当前选中的Tab)。 限于篇幅,完整代码就不贴了,有需要的朋友可以在评论中留下邮箱,我看到后把实例工程给你发过去。下面是广播测试示例工程的效果图:

点击下载本文用到的Broadcast生命周期的工程代码 点此查看Android开发笔记的完整目录

0 人点赞