当前位置: 代码迷 >> Android >> Android学识梳理之BroadcastReceiver整理
  详细解决方案

Android学识梳理之BroadcastReceiver整理

热度:323   发布时间:2016-04-24 11:07:03.0
Android知识梳理之BroadcastReceiver整理

               PS.不知不觉间发现自己已经做了很久很久的Android开发了,过去对知识块的梳理总是放在云笔记里面.主要的原因还是自己的笔记太杂乱,没有脉络.本着开源的精神,也趁着这段时间有空将之前云笔记里面的文章梳理下.同时将一些知识点整理出来和大家共同分享.

         转载请注明出处:http://blog.csdn.net/unreliable_narrator?viewmode=contents    

                        

          android 的广播接收者主要分为两个方面:一个方面是广播发送者另一个方面是广播接受者.广播发送者可以自定义广播进行发送.而广播接收者则是对广播进行接收并且做出相应的事件逻辑.广播接收者的主要作用就是Android组件间的通信不同进程间的通信.

       一.广播发送者:
                 广播发送者就是通过发送广播消息,让注册了该广播事件的广播接收者接收相关数据.它的主要的作用就是发送广播消息.广播的发送是通过Intent的方式来进行的,当然通过intent我们也可以携带一些相关的数据进行传递.由于需要对事件进行过滤.在使用intent发送广播的时候我们显然是不能通过显示的方式来进行的,这里就需要使用到隐式的intent来发送广播.
                 广播发送者按不同的用法大致可以分为三种:  普通广播. 有序广播.异步广播
                 1.普通广播:普通广播就是直接使用sendbroadcast()发送出去的广播,并且正是由于这种广播的接收者的接收顺序没有相关的规律.因此这种发送广播的方式效率极高,当然使用这种方式也是有弊端的,                            
           就是无法对这种广播进行拦截和终止.这种方式发送的广播在BroadcastReceiver无法使用setResult系列,getResult系列及abort系列API对广播进行相关的处理 .                    
  1. Intent intent = new Intent();
  2. intent.setAction("test");
  3. sendBroadcast(intent);
               2. 有序广播:
                 (1.)使用有序广播是可以通过设置广播接收者的优先级,从而达到优先接收到广播事件的目的.在使用的时候首先要提前对广播接收者对象设置优先级,优先级高的接收者先收到广播消息,优先级低的接收者后收到广播     
           消息,具有相同优先级的广播接收者接收到广播消息的顺序是随机的(一般是先注册的先收到);这样,按照广播接收者的优先级顺序接收的广播就是有序广播;优先级别在配置文件AndroidManifest.xml中的标签<intent-   
     filter android:priority="xxx">的属性priority中配置,其数值范围是[-1000,+1000],值越大,优先级就越高;有序广播可以终止后续的继续转播,接收者可以修改广播的内容;有序广播消息是通过函    
          数:Context.sendOrderedBroadcast(Intent,Permission)发送的;第二个参数是需要一个权限参数,如果为null则表示不要求接收者声明指定的权限,如果不为null,则表示接收者若要接收此广播,需声明指定权 
          限。这样做是从安全角度考虑的,例如系统的短信就是有序广播的形式,一个应用可能是具有拦截垃圾短信的功能,当短信到来时它可以先接受到短信广播,必要时终止广播传递,这样的软件就必须声明接收短信的 
          权限。比如,有3个广播接收者A、B、C,优先级顺序是A>B>C,则,A最先收到广播消息,当A收到广播消息之后,可以向广播消息中添加一些数据,然后再传递给下一个广播接收者(Intent.putExtra()),或者是终止广播消  
          息(Context.abortBroadcast());
  1. Intent intent = new Intent();
  2. intent.setAction("com.dapeng");
  3. sendOrderedBroadcast(intent, null);
  1. <receiver
  2. android:name=".MyReciverTwo"
  3. android:priority="1000">
  4. <intent-filter>
  5. <action android:name="com.dapeng"/>
  6. </intent-filter>
  7. </receiver>
  8. <receiver
  9. android:name=".MyReciver">
  10. <intent-filter android:priority="300">
  11. <action android:name="com.dapeng"/>
  12. </intent-filter>
  13. </receiver>
                  (2.)终止有序广播的传递:调用abortbroadcast()方法就可以直接将有序广播事件终止掉并且不再向下传递。                             
  1. public class ReciverTwo extends BroadcastReceiver {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. abortBroadcast();
  5. Log.d("--", "ReciverTwo被执行了");
  6. }
  7. }
                    (3.)对有序广播里面的内容进行修改.例如recivertwo的优先级大于reciverone的优先级我们就可以在recivertwo里面对广播数据进行修改.
  1. public class ReciverTwo extends BroadcastReceiver {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. Bundle bundle = new Bundle();
  5. bundle.putString("add", "新加的数据");
  6. setResultExtras(bundle);
  7. Log.d("--", "ReciverTwo被执行了");
  8. }
  9. }       
  1. public class ReciverOne extends BroadcastReceiver {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. Bundle resultExtras = getResultExtras(true);
  5. String add = resultExtras.getString("add");
  6. Log.d("--", "ReciverOne被执行了");
  7. Log.d("--", "ReciverOne_add==" + add);
  8. }
  9.                                                
             3.异步广播:
                       又叫做黏性广播.这个的概念并不好解释.但是通过一个例子就可以让我们明白它的意义.ActivityA发送广播到ActivityB,但BroadcastReceiver是在ActivityB中用代码进行注册的,ActivityA发送出去的广播ActivityB   
                是接收不到的,如果遇到这种情况该怎么办呢?使用sendStickyBroadcast方法就很好的解决了。sendStickyBroadcast()开启的广播并不会马上消失.后面等开启了界面还是可以收到异步的广播.在使用这个广播的时
                候要加上相对应的权限才能够正常的使用android.permission.BROADCAST_STICKYbut,这个方法有安全性的问题so.在api21中将这个方法遗弃了.使用的时候会报过时方法.
  1. public class MainActivity extends AppCompatActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_main);
  6. findViewById(R.id.btnOne).setOnClickListener(new View.OnClickListener() {
  7. @Override
  8. public void onClick(View v) {
  9. Intent intent = new Intent();
  10. intent.setAction("com.test");
  11. sendStickyBroadcast(intent);
  12. }
  13. });
  14. findViewById(R.id.btnTwo).setOnClickListener(new View.OnClickListener() {
  15. @Override
  16. public void onClick(View v) {
  17. startActivity(new Intent(MainActivity.this, SecondActivity.class));
  18. }
  19. });
  20. }
  21. }
  1. public class SecondActivity extends AppCompatActivity {
  2. private MyReciver mMyReciver;
  3. private IntentFilter mIntentFilter;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_second);
  8. //注册广播事件
  9. mMyReciver = new MyReciver();
  10. mIntentFilter = new IntentFilter();
  11. mIntentFilter.addAction("com.test");
  12. registerReceiver(mMyReciver, mIntentFilter);
  13. }
  14. public class MyReciver extends BroadcastReceiver {
  15. @Override
  16. public void onReceive(Context context, Intent intent) {
  17. Log.d("--", "我接收到了异步广播");
  18. }
  19. }
  20. @Override
  21. protected void onDestroy() {
  22. unregisterReceiver(mMyReciver);
  23. super.onDestroy();
  24. }
  25. }
  1. <uses-permission android:name="android.permission.BROADCAST_STICKY"/>

二.广播接收者.
                     广播接收者同属于四大组件之一,其主要的作用就是用来接收广播,并且根据这些广播做出相应的事件处理. 这些广播可以是系统发出来的广播,也可以是自己自已定义的广播事件的广播事件.使用它的时候有两种   
              方式可以进行注册,一种是静态注册,也就是在清单文件中配置设置过滤.另外的一种就是动态去注册广播事件.在代码中去进行注册 广播的事件.需要注意的一点就是动态注册的广播接收者的优先级始终是高于静态注  
             册的广播接收者
               1.静态注册广播:
              (1.)编写一个类继承自broadcastreciver  .          
  1. public class ReciverOne extends BroadcastReceiver {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. Log.d("--", "ReciverOne被执行了");
  5. }
  6. }
              (2.) 然后在清单文件中进行配置.action需要和发送者的action进行正确的匹配才能够正确的使用.
  1. <receiver android:name=".ReciverOne">
  2. <intent-filter android:priority="100">
  3. <action android:name="com.test"/>
  4. </intent-filter>
  5. </receiver>
          需要注意的是:从3.1开始静态注册的app如果处于退出的状态,将无法收到广播事件.主要是发送广播的时候增加了addflags()函数所致.
          FLAG_INCLUDE_STOPPED_PACKAGES:包含已经停止的应用(停止:即应用所在的进程已经退出)
          FLAG_EXCLUDE_STOPPED_PACKAGES:不包含已经停止的应用    
         系统发送的广播都是采用的不包含已经停止的包.但是我们自己发送的广播事件确可以加上相应的flag,这样一来即使app处于退出的状态,仍然是可以接收到广播事件的.
  1. Intent intent = new Intent();
  2. intent.setAction("com.test");
  3. intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
  4. intent.putExtra("name", "dapeng");
  5. sendBroadcast(intent);
            2. 动态注册: 
                (2.)动态注册的时候要在宿主activity销毁的时候对广播接收者进行解除注册.
  1. public class SecondActivity extends AppCompatActivity {
  2. private MyReciver mMyReciver;
  3. private IntentFilter mIntentFilter;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_second);
  8. //注册广播事件
  9. mMyReciver = new MyReciver();
  10. mIntentFilter = new IntentFilter();
  11. mIntentFilter.addAction("com.test");
  12. registerReceiver(mMyReciver, mIntentFilter);
  13. }
  14. public class MyReciver extends BroadcastReceiver {
  15. @Override
  16. public void onReceive(Context context, Intent intent) {
  17. //TODO do your work
  18. }
  19. }
  20. @Override
  21. protected void onDestroy() {
  22. unregisterReceiver(mMyReciver);
  23. super.onDestroy();
  24. }
  25. }
             3.补充:
                    我们知道:Android中的广播可以跨进程甚至跨App直接通信,且intent-filter的情况下属性exported的默认值是true,由此将可能出现安全隐患如下:

                  (1.)如果当前App intent-filter匹配了其他应用发出的广播,会导致当前App不断接收到广播并处理;

                       解决的方式是:将清单文件中广播接收者的exported属性人为设置成false,使得非本App内部发出的此广播不被接收;

  1. <receiver
  2. android:name=".Myreciver"
  3. android:exported="false">
  4. <intent-filter>
  5. <action android:name="com.test"/>
  6. </intent-filter>
  7. </receiver>

                  (2)其他App可以通过注册与当前App一致的intent-filter用于接收广播,获取广播具体信息。

                        解决的方式是:.发送广播时,指定特定广播接收器所在的包名,具体是通过intent.setPackage(packageName)指定在,这样此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。

  1. Intent intent = new Intent();
  2. intent.setAction("com.test");
  3. intent.setPackage(getPackageName());
  4. sendOrderedBroadcast(intent, null);

  相关解决方案