Android基础:BroadcastReceiver(应用场景)

广播的类型

广播的类型主要分为:

  • 普通广播
  • 系统广播
  • 无序广播
  • 有序广播
  • 粘性广播
  • App应用内广播

普通广播(intent得广播)

普通广播对于多个接收者来说是完全异步的,通常每个接收者都无需等待即可以接收到广播,接收者相互之间不会有影响。对于这种广播,接收者无法终止广播,即无法阻止其他接收者的 接收动作。

Intent intent = new Intent();
//对应BroadcastReceiver中intentFilter的action                
intent.setAction("MyBroadcastReceiver");
sendBroadcast(intent);//发送广播
  • 若被注册了的广播接收者中注册时intentFilter的action与上述匹配,则会接收此广播(即进行回调onReceive())。如下MyBroadcastReceiver则会接收上述广播

      
            
      

  • 若发送广播有相应权限,那么广播接收者也需要相应权限

系统广播

Android中内置了很多系统广播:只要涉及到手机的基本操作(开机、网络变化、插入耳机等),都可以通过发送系统广播来监听变化,通过发送对应的intent-filter(包括action)

系统操作 action
监听网络变化 android.net.conn.CONNECTIVITY_CHANGE
关闭或打开飞行模式 Intent.ACTION_AIRPLANE_MODE_CHANGED
充电时或电量发生变化 Intent.ACTION_BATTERY_CHANGED
电池电量低 Intent.ACTION_BATTERY_LOW
电池电量充足(即从电量低变化到饱满时会发出广播 Intent.ACTION_BATTERY_OKAY
系统启动完成后(仅广播一次) Intent.ACTION_BOOT_COMPLETED
关闭或打开飞行模式 Intent.ACTION_AIRPLANE_MODE_CHANGED
按下照相时的拍照按键(硬件按键)时 Intent.ACTION_CAMERA_BUTTON
屏幕锁屏 Intent.ACTION_CLOSE_SYSTEM_DIALOGS
设备当前设置被改变时(界面语言、设备方向等) Intent.ACTION_CONFIGURATION_CHANGED
插入耳机时 Intent.ACTION_HEADSET_PLUG
未正确移除SD卡但已取出来时(正确移除方法:设置--SD卡和设备内存--卸载SD卡) Intent.ACTION_MEDIA_BAD_REMOVAL
插入外部储存装置(如SD卡) Intent.ACTION_MEDIA_CHECKING
成功安装APK Intent.ACTION_PACKAGE_ADDED
成功删除APK Intent.ACTION_PACKAGE_REMOVED
重启设备 Intent.ACTION_REBOOT
屏幕被关闭 Intent.ACTION_SCREEN_OFF
屏幕被打开 Intent.ACTION_SCREEN_ON
关闭系统时 Intent.ACTION_SHUTDOWN
重启设备 Intent.ACTION_REBOOT

注:当使用系统广播时,只需要在注册广播接收者时定义相关的action即可,并不需要手动发送广播,当系统有相关操作时会自动进行系统广播
这里通过一个简单的耳机插入/拔掉时的监听来看下系统广播

第一步(注册广播)
IntentFilter intentFilter = new IntentFilter();
//只需用改变这里的action来区别不同的系统广播
intentFilter.addAction("android.intent.action.HEADSET_PLUG");
registerReceiver(broadcastReceiver, intentFilter);
第二步(接收广播)
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            AudioManager locationManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
            headsetOn = locationManager.isWiredHeadsetOn();
            if (headsetOn){
                Toast.makeText(context, "插入耳机", Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(context, "拔出耳机", Toast.LENGTH_SHORT).show();
            }
        }
    };
第三步(注销广播)
@Override
    protected void onDestroy() {
        super.onDestroy();
        if (broadcastReceiver != null) {
            unregisterReceiver(broadcastReceiver);
        }
    }
系统广播.gif

无序广播

无序广播即为我们平时经常使用的广播,其主要是通过public abstract void sendBroadcast (Intent intent)方法进行发送,并通过intent传递数据。代码示例如下:

Intent intent = new Intent();
 //定义广播事件类型
intent.setAction("Intercept_Stitch");
//Android8.0以上必须加这个,不然静态注册收不到广播
intent.setPackage(getPackageName());
// 发送广播
sendBroadcast(intent);//无序广播

无序广播会被注册了的相应的感兴趣(intent-filter匹配)接收,且顺序是无序的。如果发送广播时有相应的权限要求,BroadCastReceiver如果想要接收此广播,也需要有相应的权限。
无序广播不可以被拦截,不可以被终止,不可以被修改,无序广播任何接收者只要匹配条件都可以接收到,无优先级问题。

在AndroidManifest.xml中注册
 
      
         
      


    
          
     

优先级的值越大它的优先级就越高。
那么priority的最大值是多少呢?
网上或有些书说的是1000,但是都不正确,正确答案是2147483647这是我通过几个实验得出的数据。优先级的值比它大1都会报错。并且优先级1001确实比优先级1000更快接收到广播。
优先级的范围是:-2147483647到2147483647
刚好它的长度范围是Integer类型数据的最大值4294967296(2的32次方)。
所有我们要知道优先级1000并不是最高的优先级,不信的话你可以试试看效果。

第一个MyBroadcastReceiver类
public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e(TAG, "onReceive: 这是静态的广播接收者(优先级500)" );
}
第二个MyBroadcastReceiver2类
public class MyBroadcastReceiver2 extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e("Receiver", "这是静态的广播接受者(优先级999)---》");
        //截断广播
        abortBroadcast();
        //无序广播是不允许截断的 不然会报错BroadcastReceiver trying to return result during a non-ordered broadcast
        //只有有序广播可以截断
}
1559030003(1).jpg

动态发送无序广播会在下方和动态发送有序广播在一起,其实主要的区别就是

  • sendOrderedBroadcast(intent, null);//发送有序广播
  • sendBroadcast(intent);//发送无序广播

有序广播

有序广播比较特殊,每次发送广播会先发送到优先者高的地方,然后再通过优先者高的往低的发送,优先者高的可以截断广播,那么之后的接收者就接收不到广播了,可以在广播注册时使用intent-filter里面的android: priority=”xxx”去解决或在java代码中用setPriority(xxx)来设置。

静态发送有序广播
//静态发送有序广播
Intent intent = new Intent();
 //定义广播事件类型
intent.setAction("Intercept_Stitch");
intent.setPackage(getPackageName());
// 发送广播
sendOrderedBroadcast(intent,null);//有序广播
  • 无截断


    无截断.jpg
  • 有截断


    有截断.jpg

由此可看出添加截断广播可将之后的广播截断

动态发送有序广播
package com.dongbo.model;

import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class Main4Activity extends AppCompatActivity {

    private MyBroadcastReceiver receiver;
    private MyBroadcastReceiver2 receiver2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main4);
        //创建广播接收者对象
        receiver = new MyBroadcastReceiver();
        receiver2 = new MyBroadcastReceiver2();
        //注册广播接收者,需要一个意图对象,也需要action参数,这里是定义Action参数
        IntentFilter filter = new IntentFilter("Intercept_Stitch");
        IntentFilter filter2 = new IntentFilter("Intercept_Stitch");
        //动态设置广播的优先级
        filter.setPriority(999);
        filter2.setPriority(500);
        //注册广播,
        // 动态广播拦截?先注册者先收到消息???
        registerReceiver(receiver2, filter);
        registerReceiver(receiver, filter);
    }

    @Override
    protected void onDestroy() {
        //在适当的时候要解除广播接收者的绑定
        unregisterReceiver(receiver);
        unregisterReceiver(receiver2);
        super.onDestroy();
    }

    public void click(View view) {
        Intent intent = new Intent();
        intent.setAction("Intercept_Stitch");
        //发送有序广播
//        sendOrderedBroadcast(intent, null);
        //发送无序广播
        sendBroadcast(intent);
    }
}
//接收的地方还是和上面的接受一样 这里就不做粘贴了 

粘性广播

粘性消息在发送后就一直存在于系统的消息容器里面,等待对应的处理器去处理,如果暂时没有处理器处理这个消息则一直在消息容器里面处于等待状态,粘性广播的Receiver如果被销毁,那么下次重建时会自动接收到消息数据。

虽然在我们现在的开发中,很少有用到粘性广播,但是这里我们也可以理解一下来实现一下粘性广播

使用场景

发送一个粘性广播(StickyBroadcast),但是现在并没有一个广播接收者来接收该广播发出的数据. 而是在某个时间后,才注册一个receiver,但是也能收到之前StickyBroadcast发出的广播. 这点就和平常用的普通广播很不一样了.

1.发送一个粘性广播
2.5秒之后启动一个新的Activity
3.在新的Activity中注册receiver并且接收粘性广播发送的数据
4.注意这里的权限一定不能少

package com.dongbo.model;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
//第一个activity
public class Main5Activity extends AppCompatActivity {
   private Context mContext;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main5);
       mContext=this;
       sendStickyBroadcastTest();
       startAnotherActivity();
   }
   //发送粘性广播
   private void sendStickyBroadcastTest() {
       Intent intent=new Intent();
       intent.setAction("cc.vv");
       intent.putExtra("time", String.valueOf(System.currentTimeMillis()));
       Log.e("传输的time",String.valueOf(System.currentTimeMillis())+"");
       sendStickyBroadcast(intent);
   }

   // 启动其他Activity
   private void startAnotherActivity() {
       new Thread() {
           public void run() {
               try {
                   Thread.sleep(1000*5);
                   Intent intent=new Intent(mContext, Main6Activity.class);
                   mContext.startActivity(intent);
               } catch (Exception e) {
                   // TODO: handle exception
               }
           }
       }.start();

   }
   BroadcastReceiver mBroad = new BroadcastReceiver() {
       @Override
       public void onReceive(Context context, Intent intent) {
           Log.e("tent",intent.getAction()+"");
       }
   };

}
package com.dongbo.model;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

public class Main6Activity extends AppCompatActivity {
    private BroadcastReceiver mBroadcastReceiver = null;

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

    //注册广播接收者
    private void registBroadcastReceiver() {
        mBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String time = intent.getStringExtra("time");
                Log.e("收到了StickyBroadcast发出的数据"+"-------"+"发送广播的时间",time);
            }
        };
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("cc.vv");
        registerReceiver(mBroadcastReceiver, intentFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mBroadcastReceiver != null) {
            unregisterReceiver(mBroadcastReceiver);
        }
    }
}
粘性广播.jpg

App应用内更新

1.App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App。
2.相比于全局广播(普通广播),App应用内广播优势体现在:安全性高 & 效率高

  • 具体使用1 - 将全局广播设置成局部广播
    1.注册广播时将exported属性设置为false,使得非本App内部发出的此广播不被接收;
    2.在广播发送和接收时,增设相应权限permission,用于权限验证;
    3.发送广播时指定该广播接收器所在的包名,此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。

通过intent.setPackage(packageName)指定包名

  • 具体使用2 - 使用封装好的LocalBroadcastManager类
    使用方式上与全局广播几乎相同,只是注册/取消注册广播接收器和发送广播时将参数的context变成了LocalBroadcastManager的单一实例

注:对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册,不能静态注册

package com.dongbo.model;

import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class Main7Activity extends AppCompatActivity {

    private MyBroadcastReceiver mBroadcastReceiver;
    private LocalBroadcastManager localBroadcastManager;
    private String BROADCAST_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main7);

        //注册应用内广播接收器
        //步骤1:实例化BroadcastReceiver子类 & IntentFilter mBroadcastReceiver
        mBroadcastReceiver = new MyBroadcastReceiver();
        IntentFilter intentFilter = new IntentFilter();

        //步骤2:实例化LocalBroadcastManager的实例
        localBroadcastManager = LocalBroadcastManager.getInstance(this);

        //步骤3:设置接收广播的类型
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");

        //步骤4:调用LocalBroadcastManager单一实例的registerReceiver()方法进行动态注册
        localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);







    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //取消注册应用内广播接收器
        localBroadcastManager.unregisterReceiver(mBroadcastReceiver);
    }

    public void click(View view) {
        //发送应用内广播
        Intent intent = new Intent();
        intent.setAction(BROADCAST_ACTION);
        localBroadcastManager.sendBroadcast(intent);
    }
}

两个App之间进行通信

现有2个App A发送广播 B接收广播

//发送广播
Intent intent = new Intent();  //Itent就是我们要发送的内容
intent.putExtra("data", "this is data from broadcast "+ Calendar.getInstance().get(Calendar.SECOND));
intent.setAction(BROADCAST_ACTION_DISC);   //设置你这个广播的action,只有和这个action一样的接受者才能接受者才能接收广播
sendBroadcast(intent,BROADCAST_PERMISSION_DISC);   //发送广播
//使用自定义权限




注意:android:protectionLevel=”signature” 如果是同一个应用可以这么声明,如果跨app发送广播(比如A app向B app发送广播),则需要去掉android:protectionLevel=”signature”。


//B  App进行接收
 BroadcastReceiver receiveBroadCast = new ReceiveBroadCast();
IntentFilter filter = new IntentFilter();
filter.addAction(BROADCAST_ACTION_DISC); // 只有持有相同的action的接受者才能接收此广播
registerReceiver(receiveBroadCast, filter,BROADCAST_PERMISSION_DISC,null);

public class ReceiveBroadCast extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
     String data = intent.intent.getStringExtra("data");
      Log.e("data",data+");

}
两个app通信.gif
至此四大组件BroadcastReceiver的讲解就到此结束,大家阅读的过程中如果发生什么错误,请评论下来,我来进行改正!!

你可能感兴趣的:(Android基础:BroadcastReceiver(应用场景))