详解广播机制

广播的类型

广播类型分为有序广播和标准广播。标准广播是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎在同一时间接收到这条广播信息,没有先后顺序可言,无法被截断。有序广播是同步执行的广播,同一时间只有一个广播接收器可以接收这条消息,只有当广播接收器中的逻辑执行完毕,广播才能继续传递。此时广播接收器是有先后顺序的,前面的广播接收器还可以截断正在传递的广播。

动态注册广播:

需要在代码中注册广播

public class MainActivity extends AppCompatActivity {

    private IntentFilter intentFilter;
    private NetworkChangeReceiver networkChangeReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_ CHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver,intentFilter);
    }
    @Override
    protected void onDestroy(){
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }
    private class NetworkChangeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent){
            ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            if(networkInfo != null && networkInfo.isAvailable()){
                Toast.makeText(context,"network is available",Toast.LENGTH_SHORT).show();;
            }else{
                Toast.makeText(context,"network is unavailable",Toast.LENGTH_SHORT).show();
            }
        }
    }
}

在MainActivity中定义一个内部类NetworkChangeReceiver,该类继承自BroadcastReceiver,并重写onReceive()方法。每当网络状态发生变化时,执行onReceive()方法。在onCreate()中创建IntentFilter 实例,为它添加值为android.net.conn.CONNECTIVITY_CHANGE的action,当网络状态发生改变时,系统发出的就是一条值为android.net.conn.CONNECTIVITY_CHANGE的广播,广播接收器想要监听什么广播只需要添加相应的action。接下来创建一个NetworkChangeReceiver的实例,然后调用registerReceiver()方法进行注册,将NetworkChangeReceiver和IntentFilter 实例传入。为防止内存泄露,在onDestroy()方法调用unregisterReceiver()方法实现取消注册广播功能。在onReceive()方法中,通过getSystemService()方法得到了ConnectivityManager的实例,这是个系统服务类,专门用于管理网络连接,然后调用getActiveNetworkInfo()方法可以得到NetworkInfo的实例,接着调用NetworkInfo的isAvailable()方法,就可以判断是否有网络。最后需要在AndroidManifest.xml文件声明权限访问网络状态。

静态注册广播

静态注册广播可以在程序未启动时便能接收到广播。这里我们准备让程序接收一条开机广播,当收到这条广播时就可以在onReceive()方法里执行相应的逻辑,从而实现开机启动的功能。新建一个BootCompleteReceiver继承自BroadcastReceiver,代码如下所示:

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

先在AndroidManifest.xml文件添加如下权限


然后在application标签中添加标签注册广播接收器,在标签中加入想要接收的广播。由于Android系统启动完成后会发出一条值为android.intent.action.BOOT_COMPLETED的广播,因此我们在这里添加了相应的action。

 
            
                
            

发送标准广播

首先定义一个广播接收器

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

}

然后在AndroidManifest.xml对这个广播接收器进行注册,让其接收一条值为com.example.broadcasttest. MY_BROADCAST的广播


            
                
            
 

然后在MainActivity构建Intent对象,并吧要发送的广播的值传入,然后调用context的sendBroadcast()方法将广播发送出去。

public class MainActivity extends Activity {
	……
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Button button = (Button) findViewById(R.id.button);
		button.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Intent intent = new Intent("com.example.broadcasttest. MY_BROADCAST");
				sendBroadcast(intent);
			}
		});
	}
}

发送有序广播

发送广播方式区别于标准广播,使用如下代码,第二个参数是一个与权限相关的字符串

sendOrderedBroadcast(intent, null);

有序广播可以通过设置广播接收器的优先级,改变先后顺序,还可以将广播截断,主要在注册中设定,在AndroidManifest.xml中的广播接收器中加入如下代码

 

同时也可以截断广播,只需要在广播接收器的onReceive()方法中加入如下代码

abortBroadcast();

使用本地广播

首先是通过LocalBroadcastManager的getInstance()方法得到了它的一个实例,然后在注册广播接收器的时候调用的是LocalBroadcastManager的registerReceiver()方法,在发送广播的时候调用的是LocalBroadcastManager的sendBroadcast()方法,仅此而已。这里我们在按钮的点击事件里面发出了一条com.example.broadcasttest. LOCAL_BROADCAST广播,然后在LocalReceiver里去接收这条广播

public class LocalBroadcastActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    private LocalBroadcastManager localBroadcastManager;
    private LocalReceiver localReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.local_activity);
        localBroadcastManager = LocalBroadcastManager.getInstance(this);// 获取实例
        Button btn = (Button)findViewById(R.id.button2);
        btn.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);
    }
    private class LocalReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,"received local broadcast",Toast.LENGTH_SHORT).show();
        }
    }
}

最后我们再来盘点一下使用本地广播的几点优势吧。
1.可以明确地知道正在发送的广播不会离开我们的程序,因此不需要担心机密数据泄漏的问题。
2.其他的程序无法将广播发送到我们程序的内部,因此不需要担心会有安全漏洞的隐患。
3.发送本地广播比起发送系统全局广播将会更加高效。

你可能感兴趣的:(详解广播机制)