7. 广播

一、广播的定义

广播是一盒全局的监听器,属于 Android 四大组件之一。Android广播分为两个角色:广播发送者、广播接收者。Android 的广播按照发送方式主要可以分成两种类型:标准广播和有序广播;按照注册方式主要可以分为:动态注册广播和静态注册广播;按照定义方式主要可以分为:系统广播和自定义广播。

1. 标准广播(Normal broadcasts)

一种完全异步执行的广播,广播发出去之后,所有的广播接收者几乎是同一时间收到消息的。他们之间没有先后顺序可言,而且这种广播是没法被截断的。

在这里插入图片描述

2. 有序广播

是一种同步执行的广播,在广播发出去之后,同一时刻只有一个广播接收器可以收到消息。当广播中的逻辑执行完成后,广播才会继续传播。

在这里插入图片描述

二、广播接收器(Broadcast Receivers)

广播接收器用于响应来自其他应用程序或者系统的广播消息。这些消息有时被称为事件或者意图。例如,应用程序可以初始化广播来让其他的应用程序知道一些数据已经被下载到设备,并可以为他们所用。这样广播接收器可以定义适当的动作来拦截这些通信。

有以下两个重要的步骤来使系统的广播意图配合广播接收器工作。

  • 创建广播接收器
  • 注册广播接收器

还有一个附加的步骤,要实现自定义的意图,你必须创建并广播这些意图。

1. 创建广播接收器

广播接收器需要实现为BroadcastReceiver类的子类,并重写onReceive()方法来接收以Intent对象为参数的消息。

public class MyReceiver extends BroadcastReceiver {
   @Override
   public void onReceive(Context context, Intent intent) {
      Toast.makeText(context, "Intent Detected.", Toast.LENGTH_LONG).show();
   }
}
2. 注册广播接收器

应用程序通过在AndroidManifest.xml中注册广播接收器来监听制定的广播意图。假设我们将要注册MyReceiver来监听系统产生的ACTION_BOOT_COMPLETED事件。该事件由Android系统的启动进程完成时发出。

根据注册方式又分为:动态注册、静态注册。

2.1 动态注册

简单来说就是通过代码添加响应的Action。后面可以通过代码修改,不是固定的,所以称为动态注册。

在activity中通过代码动态注册广播,定义类extends BroadcastReceiver,重写onReceiver方法,通过registerReceiver注册广播。在onDestory方法中通过unregisterReceiver取消注册。自由控制注册和取消,具有灵活性,缺点是程序启动后才能接受广播。

定义广播接收器:

class NetWorkReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            networkInfo = connectivityManager.getActiveNetworkInfo();//需要申请权限
            if (networkInfo != null && networkInfo.isAvailable())
                Toast.makeText(context,"网络开启了",Toast.LENGTH_SHORT).show();
            else
                Toast.makeText(context,"网络关闭了",Toast.LENGTH_SHORT).show();
        }
    }

Activity中创建实例:

public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    private NetworkInfo networkInfo;
    private NetWorkReceiver netWorkReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentFilter = new IntentFilter();
        netWorkReceiver = new NetWorkReceiver();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");//设置广播接收器接受的内容
        registerReceiver(netWorkReceiver,intentFilter);//注册广播接收器
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 取消注册广播接收器
        unregisterReceiver(netWorkReceiver);
    }

}

2.2 静态注册

androidManifest.xml文件中声明响应的Action

定义接收器:

public class BootCompleteReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"开机了!",Toast.LENGTH_LONG).show();
    }
}

注册接收器:

<application>
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        //广播接收器注册
        <receiver android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action
                    android:name="android.intent.action.BOOT_COMPLETED">					</action>
            </intent-filter>
        </receiver>
</application>

有几个系统产生的事件定义在最后意图类的静态字段。下表列出了一些重要的系统事件。

事件常量描述
android.intent.action.BATTERY_CHANGED持久广播含充电状态,级别,以及其他相关的电池信息。
android.intent.action.BATTERY_LOW显示设备的电池电量低。
android.intent.action.BATTERY_OKAY指示电池正在低点后但没有问题。
android.intent.action.BOOT_COMPLETED一次播出后,系统已完成启动。
android.intent.action.BUG_REPORT显示活动报告的错误。
android.intent.action.CALL执行呼叫由数据指定某人。
android.intent.action.CALL_BUTTON用户按下“呼叫”按钮进入拨号器或其他适当的用户界面发出呼叫。
android.intent.action.DATE_CHANGED日期改变。
android.intent.action.REBOOT有设备重启。
3. 发送自定义广播并接收
1.发送标准广播

类继承BroadcastReceiver,重写onReceiver方法,在AndroidManifest文件中声明:

public class MyBroadcastReceiver extends BroadcastReceiver {
    @0verride
    public void onReceive(Context context, Intent intent) {
    	Toast.makeText(context, "received in MyBroadcastReceiver", Toast. LENGTH_SHORT).show();
	}
}

注册:

<receiver
    android: name=".MyBroadcastReceiver"
    and roid: enabled="true"
    android: exported="true">
    <intent-filter>
    	<action android: name="com.example.broadcasttest.MY_BROADCAST"/>
    </ intent-filter>
</ receiver>

发送广播:(可以是自己写的App)使用Intent发送自定义广播。

Intent intent = new Intent("com.override0330.example");
sendBroadcast(intent);
2.发送有序广播

步骤同发送标准广播一致,但是多加入一个优先级的设置。

......
<intent-filter android:priority="98">//设置优先级为98,最高为100
                <action
                    android:name="com.override0330.example"></action>
            </intent-filter>
......

发送有序广播:

Intent intent = new Intent("com.override0330.example");
sendOrderBroadcast(intent, null);//null参数为一个与权限相关的字符串,一般情况传入null

在广播接收器的onReceive里使用abortBroadcast()截断广播。

三、本地广播

优势:正在发送的广播不会离开我们的程序,不必担心数据泄露。其他程序无法将广播发送到我们程序内部,不必担心安全漏洞。发送本地广播比系统全局广播更高效。

private LocalReceiver localReceiver ;
private LocalBroadcastManager localBroadcastManager;
@Override
protected 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() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent("com.example.broadcasttest.LOCAL_      									BROADCAST");
            localBroadcastManager.sendBroadcast(intent); // 发送本地广播
		}
	});
    intentFilter = new IntentFilter();
    intentFilter . addAction("com.example.broadcasttest.LOCAL_BROADCAST");
    LocalReceiver = new LocaLReceiver();
    //注册本地广播监听器
    LocalBroadcastManager.registerReceiver(localReceiver, intentFilter); 
}

@Override
protected void onDestroy() {
    super.onDestroy();
    // 取消注册
    localBroadcastManager.unregisterReceiver(localReceiver);
}
class LocalReceiver extends BroadcastReceiver {
    @Override
    public void onReceive (Context context, Intent intent) {
    	Toast.makeText (context, "received Local broadcast", Toast.LENGTH_ SHORT).show( ) ;
    }
}
四、广播与服务

举个例子:模拟下载过程,下载时利用广播获取进度并实时更新进度条。

自定义下载服务:模拟下载过程并发送广播

public class MsgService extends Service {
	/**
	 * 进度条的最大值
	 */
	public static final int MAX_PROGRESS = 100;
	/**
	 * 进度条的进度值
	 */
	private int progress = 0;
	
	private Intent intent = new Intent("com.example.communication.RECEIVER");


	/**
	 * 模拟下载任务,每秒钟更新一次
	 */
	public void startDownLoad(){
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				while(progress < MAX_PROGRESS){
					progress += 5;
					
					//发送Action为com.example.communication.RECEIVER的广播
					intent.putExtra("progress", progress);
                    // ----------------发送广播--------------
					sendBroadcast(intent);
					
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
				}
			}
		}).start();
	}	

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		startDownLoad();
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}
}

定义广播接收器:

public class MsgReceiver extends BroadcastReceiver{
	 
		@Override
		public void onReceive(Context context, Intent intent) {
			//拿到进度,更新UI
			int progress = intent.getIntExtra("progress", 0);
			mProgressBar.setProgress(progress);
		}	
	}

注册广播接收器:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //动态注册广播接收器
    msgReceiver = new MsgReceiver();
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("com.example.communication.RECEIVER");
    registerReceiver(msgReceiver, intentFilter);


    mProgressBar = (ProgressBar) findViewById(R.id.progressBar1);
    Button mButton = (Button) findViewById(R.id.button1);
    mButton.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            //启动服务
            mIntent = new Intent("com.example.communication.MSG_ACTION");
            startService(mIntent);
        }
    });	
}
五、限制

Google为了降低功耗,改进Android系统的电池表现,为APP注册的静态广播导致耗电添加了限制

Google所加入的限制很重要的一部分就是后台执行限制,其中对广播的限制为许多隐式广播无法在manifest中静态注册的BroadcastReceiver收到(其实这一举措在Android7.0中已经初见端倪)。除了由系统发出的隐式广播之外,在应用中自定义的广播也无法被静态注册的BroadcastReceiver收到。
那么问题来了,自定义的广播如何被静态注册的BroadcastReceiver接收到呢?

解决方法有两种:

  • 使用动态注册广播接收器,而不使用静态注册的广播接收器。
  • 官方推荐使用JobScheduler替代原来用隐式广播实现功能,但是没有广播那么灵活。
  • 发送广播之前,Intent调用setPackage()方法设置Package,使得发送的广播改为显示广播。

参考:Android O 对隐式广播的限制以及对策

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值