安卓BroadcastReceiver使用完全解析(一)

我们都知道Android四大组件,以前刚写博客的时候也写过其它组件,尽管写的不好,当做学习的笔记吧!比如Android四大组件之ActivityAndroid四大组件之Service解析两篇文章,当然还总结过Android情景案例——Activity与Service通讯交互使用到广播。所以这篇文章就总结下广播的常见使用方式,以及细节性的相关问题。
我们知道在Android开发中,我们可以通过广播进行数据的传递、通知,这种模式就是类似于观察者模式的效果。


 一、基本概述
广播接收器是一个用于接收广播通知信息,并做出对应处理的组件。比如我们常见的系统广播──通知时区改变、电池电量低、拍摄了一张照片或者用户改变了语言选项。在实际开发中我们可以拥通过集成自BroadcastReceiver基类来进行自定义广播,实现我们的业务需求的消息通讯。广播接收器没有用户界面。然而,它们可以启动一个activity来响应它们收到的信息,或者用NotificationManager来通知用户,以此来达到一种通讯。

1、广播的类别
* 有序广播(普通广播):对于多个接收者来说是完全异步的,通常每个接收者都无需等待即可以接收到广播,接收者相互之间不会有影响。对于这种广播,接收者无法终止广播,即无法阻止其他接收者的接收动作。这个也是我们使用较多的一种广播类型。
* 无序广播:它每次只发送到优先级较高的接收者那里,然后由优先级高的接受者再传播到优先级低的接收者那里,优先级高的接收者有能力终止这个广播


2、广播的使用流程
1.  继承BroadcastReceiver实现自定义广播类:这里有两种形式的广播创建:单独类文件、内部类形式。重写onReceive方法进行消息的处理。
2.  注册广播:俗称有静态注册和动态注册。静态注册指在manifest文件中注册的广播,这种注册的广播具有应用程序级别的效果。动态注册就是通过代码进行注册,比如我们在Activity中通过Context.registerReceiver进行注册,这种广播具有组件级别的效果,即当我们调用unregisterReceiver()方法或组件销毁广播就无法被接收处理了。
3.  发送广播:这里发送广播通过Context的sendBroadcast()方法或sendOrderedBroadcast()方法进行发送普通广播或有序广播。


二、广播使用
1、普通广播基本使用
(1)、我们创建一个名为GostBroadcast的类继承BroadcastReceiver,实现一个自定义的广播。
[java]  view plain  copy
  1. public class GostBroadcast extends BroadcastReceiver {  
  2.   
  3.   
  4.     @Override  
  5.     public void onReceive(Context context, Intent intent) {  
  6.         String data = intent.getStringExtra("data");  
  7.         Toast.makeText(context, data + "/cast", Toast.LENGTH_LONG).show();  
  8.     }  
  9. }  
(2)、注册广播,我们注册一个应用程序级别的广播,在manifest文件中进行注册。注意在注册广播的时候需要指定该广播的action
[java]  view plain  copy
  1. <receiver android:name="com.dsw.servicedemo.GostBroadcast"  
  2.             android:exported="false">  
  3.             <intent-filter>  
  4.                 <action android:name="com.dsw.send"/>  
  5.             </intent-filter>  
  6. </receiver>  
(3)、发送广播,通过Intent进行广播的启动发送。
[java]  view plain  copy
  1. Intent intent = new Intent();  
  2. intent.setAction("com.dsw.send");  
  3. intent.putExtra("data""data");  
  4. sendBroadcast(intent);  
通过这样一个流程,我们就完成了一个广播从创建、发送、接收处理的整个过程。最后在页面弹出Toast展示我们传递的数据。

2、匿名内部类的广播使用形式:
(1)、这里我们在ManiActivity中声明一个广播。
[java]  view plain  copy
  1. public class MainActivity extends Activity {  
  2.     .....  
  3.       
  4.     class MyBroadcastReceiver extends BroadcastReceiver{  
  5.   
  6.   
  7.         @Override  
  8.         public void onReceive(Context context, Intent intent) {  
  9.             String data = intent.getStringExtra("data");  
  10.             //tv_text.setText(data);  
  11.             Toast.makeText(context, data, Toast.LENGTH_LONG).show();  
  12.         }  
  13.     }  
  14. }  
(2)这里我们通过代码进行动态注册广播,然后点击按钮进行发送广播。
[java]  view plain  copy
  1. public class MainActivity extends Activity {  
  2.     private TextView tv_text;  
  3.       
  4.     @Override  
  5.     protected void onCreate(Bundle savedInstanceState) {  
  6.         super.onCreate(savedInstanceState);  
  7.         setContentView(R.layout.activity_main);  
  8.           
  9.         tv_text = (TextView) findViewById(R.id.tv_test);  
  10.         tv_text.setOnClickListener(new OnClickListener() {  
  11.               
  12.             @Override  
  13.             public void onClick(View v) {  
  14.                   
  15.                 Intent intent = new Intent();  
  16.                 intent.setAction("com.dsw.data");  
  17.                 intent.putExtra("data""data");  
  18.                 sendBroadcast(intent);  
  19.             }  
  20.         });  
  21.           
  22.         IntentFilter intentFilter = new IntentFilter();  
  23.         intentFilter.addAction("com.dsw.data");  
  24.         registerReceiver(new MyBroadcastReceiver(), intentFilter);  
  25.     }  
  26.       
  27.     class MyBroadcastReceiver extends BroadcastReceiver{  
  28.   
  29.   
  30.         @Override  
  31.         public void onReceive(Context context, Intent intent) {  
  32.             String data = intent.getStringExtra("data");  
  33.             tv_text.setText(data);  
  34.             Toast.makeText(context, data, Toast.LENGTH_LONG).show();  
  35.         }  
  36.     }  
  37. }  
这样,我们就实现了通过BroadcastReceiver的使用,它可以实现在activity内部的数据传递等通讯。我们知道这样注册广播是属于组件级别的广播,如果我们从别的Activity发送广播它还能收到么?带着这个疑问,我们新建一个SendActivity。实现的效果是,由ManiActivity跳转到这个SendActivity。在SendActivity中发送广播。
[java]  view plain  copy
  1. public class SendActivity extends Activity {  
  2.     private TextView tv_text;  
  3.       
  4.     @Override  
  5.     protected void onCreate(Bundle savedInstanceState) {  
  6.         super.onCreate(savedInstanceState);  
  7.         setContentView(R.layout.activity_send);  
  8.           
  9.         tv_text = (TextView) findViewById(R.id.tv_test);  
  10.         tv_text.setOnClickListener(new OnClickListener() {  
  11.               
  12.             @Override  
  13.             public void onClick(View v) {  
  14.                 Intent intent = new Intent();  
  15.                 intent.setAction("com.dsw.data");  
  16.                 intent.putExtra("data""data");  
  17.                 sendBroadcast(intent);  
  18.             }  
  19.         });  
  20.     }  
  21. }  


通过效果图我们可以看到SendActivity发送的广播MainActivity中还是能接受到,但是如果我们在MainActivity跳转后增加这样一段代码:
[java]  view plain  copy
  1. Intent intent = new Intent(MainActivity.this,SendActivity.class);  
  2. startActivity(intent);  
  3. MainActivity.this.finish();  
在来看看效果:


我们可以发现已经接受不到广播了,所以如果我们定义了一个组件级别的广播最好只用于我们组件内的简单通讯,使用后在onDestroy方法中进行unregisterReceiver()注销广播。那么如果我们定义了一个内部类的广播怎么将它转换成应用级别的广播呢?

3、组件级别广播转换应用级别广播

我们分析下,应用级别的广播是针对整个应用进行使用的,它不应该去依赖某个组件。而我们定义的组件级别的广播室在某个组件中(Activity),如果进行manifest中注册系统级别,我们就必须消除内部类对外部类(组件)的持有引用依赖。这里我们就需要使用的静态内部类,即这种形式:
[java]  view plain  copy
  1. public static class MyBroadcastReceiver extends BroadcastReceiver{  
  2.   
  3.   
  4.     @Override  
  5.     public void onReceive(Context context, Intent intent) {  
  6.         String data = intent.getStringExtra("data");  
  7.         Toast.makeText(context, data, Toast.LENGTH_LONG).show();  
  8.     }  
  9. }  
然后我们在Manifest文件中进行注册:
[java]  view plain  copy
  1. <receiver android:name="com.dsw.servicedemo.MainActivity$MyBroadcastReceiver"  
  2.             android:exported="false"  
  3.             >  
  4.     <intent-filter>  
  5.         <action android:name="com.dsw.data"/>  
  6.     </intent-filter>  
  7. </receiver>  
这样就成了应用级别的广播。这里需要注意:内部类.需要替换成$符号

4、有序广播的基本使用

有序广播,说明有多个接受者,他们都能接受到发送的这条广播,只不过他们的接受顺序有所不同。案例如下:
[java]  view plain  copy
  1. public class FirstReceiver extends BroadcastReceiver {    
  2.         
  3.     private static final String TAG = "OrderedBroadcast";    
  4.         
  5.     @Override    
  6.     public void onReceive(Context context, Intent intent) {    
  7.         String msg = intent.getStringExtra("msg");    
  8.         Log.i(TAG, "FirstReceiver: " + msg);    
  9.             
  10.         Bundle bundle = new Bundle();    
  11.         bundle.putString("msg", msg + "@FirstReceiver");    
  12.         setResultExtras(bundle);    
  13.     }    
  14.     
  15. }  
  16.   
  17.   
  18. public class SecondReceiver extends BroadcastReceiver {    
  19.         
  20.     private static final String TAG = "OrderedBroadcast";    
  21.         
  22.     @Override    
  23.     public void onReceive(Context context, Intent intent) {    
  24.         String msg = getResultExtras(true).getString("msg");    
  25.         Log.i(TAG, "SecondReceiver: " + msg);  
  26.     }    
  27.     
  28. }   
两个接收者定义好了,我们注册它们。
[java]  view plain  copy
  1. <receiver android:name=".FirstReceiver">    
  2.     <intent-filter android:priority="1000">    
  3.         <action android:name="android.dsw.data"/>  
  4.     </intent-filter>    
  5. </receiver>    
  6. <receiver android:name=".SecondReceiver">    
  7.     <intent-filter android:priority="500">    
  8.         <action android:name="android.dsw.data"/>   
  9.     </intent-filter>    
  10. </receiver>   
发送广播:
[java]  view plain  copy
  1. Intent intent = new Intent("android.intent.action.MY_BROADCAST");    
  2. intent.putExtra("msg""hello receiver");    
  3. sendOrderedBroadcast(intent, "android.dsw.data");  
看下结果:
[java]  view plain  copy
  1. FirstReceiver:hello receiver  
  2. SecondReceiver:hello receiver@FirstReceiver  
这样就可以实现广播的拦截,通过abortBroadcast();终止广播。比如系统的接收短信广播就是一个有序广播,我们就可以通过自定义的广播进行拦截,只要设置的android:priority属性,越大优先级越高。这个值介于[-1000,1000]。

二、进程间广播使用
细心点可以发现,我们在注册BroadcastReceiver的时候,会指定这样一个属性:android:exported="false",这个属性就是指定我们的广播在本进程中进行使用。当我们的广播将这个属性设置为true的时候,则其他应用中就可以发送到广播让我们的这个应用接受到。
(1)、我们修改GostBroadcast广播的注册形式。
[java]  view plain  copy
  1. <receiver android:name="com.dsw.servicedemo.GostBroadcast"  
  2.     android:exported="true">  
  3.     <intent-filter>  
  4.         <action android:name="com.dsw.send"/>  
  5.     </intent-filter>  
  6. </receiver>  
(2)、我们先建立一个应用进行发送广播。
[java]  view plain  copy
  1. public class MainActivity extends Activity {  
  2.   
  3.   
  4.     @Override  
  5.     protected void onCreate(Bundle savedInstanceState) {  
  6.         super.onCreate(savedInstanceState);  
  7.         setContentView(R.layout.activity_main);  
  8.         findViewById(R.id.myBroad).setOnClickListener(new OnClickListener() {  
  9.               
  10.             @Override  
  11.             public void onClick(View v) {  
  12.                 Intent intent = new Intent();  
  13.                 intent.setAction("com.dsw.send");  
  14.                 sendBroadcast(intent);  
  15.             }  
  16.         });  
  17.     }  
  18. }  
效果图:

我们可以看到这样就实现了跨进程的广播通讯,当然为了模拟,我们也可以直接给这个广播指定android:process属性,让它独立出来一个进程。

三、监听系统广播的使用
比如系统的开机广播、收取短信广播、电量提醒广播这类我们都可以通过自定义广播去监听,然后进行我们的业务处理。

四、总结

BroadcastReceiver的生命周期只有十秒左右,如果在 onReceive() 内做超过十秒内的事情,就会报错 。如果需要处理耗时的业务,我们可以开启Service进行处理,谨记一点:广播主要目的是监听获取通知,不要处理繁杂的业务。

猜你喜欢

转载自blog.csdn.net/weixin_39877717/article/details/79918920
今日推荐