Android BroadcastReceiver 详解(中)

152 阅读5分钟

这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战

文章目录

广播的种类

  • 普通广播/无序广播
    表现为广播的接收者们将不区分先后顺序,几乎同时接收广播,并且广播接收者们在接收广播时互不相干
  • 有序广播
    表现为广播的接收者们会根据一定的先后顺序,接收到广播。类似于生活中的“传话”的特性
  • 粘滞广播/粘性广播(也区分为有序和无序)
    无视,在Android 5.0已声明为过期

栗子:发送有序广播

对上一篇的栗子进行改进,增加1个按钮

    <Button
        android:id="@+id/btn_send_ordered_broadcast"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发送有序广播"/>

MainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    ...
    private Button btnSendOrderedBroadcast;
    ...
    private int number;

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

        ...
        btnSendOrderedBroadcast = findViewById(R.id.btn_send_ordered_broadcast);
        ...
        btnSendOrderedBroadcast.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
	        ...
            case R.id.btn_send_ordered_broadcast:
                //准备Intent对象
                Intent intent2 = new Intent();
                intent2.setPackage("com.example.testapplication");
                intent2.putExtra("_number", number);
                number++;
                intent2.setAction("CCTV1");
                //接收者的权限
                String receiverPermission = null;
                //发送有序广播
                sendOrderedBroadcast(intent2, receiverPermission);
                break;
            case R.id.btn_register_receiver:
                if (receiver == null) {
                    receiver = new InnerReceiver();
                    IntentFilter filter = new IntentFilter();
                    filter.addAction("CCTV5");
                    filter.addAction("CCTV1");
                    registerReceiver(receiver, filter);
                }
            ...
        }
    }

    private class InnerReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            //区分广播的“频道”
            String action = intent.getAction();
            if ("CCTV5".equals(action)) {
                String date = intent.getStringExtra("date");
                Log.d("BROADCAST", "InnerReceiver->onReceive();时间:" + date);
            } else if ("CCTV1".equals(action)) {
                int number = intent.getIntExtra("_number", -999);
                Log.d("BROADCAST", "InnerReceiver->onReceive();_number:" + number);
            } else {

            }
        }
    }
}

增加一个按钮,增加点击事件,让其发送有序广播,这次发送的频道是“CCTV1”,为了能让 InnerReceiver 也能接收“CCTV1”,我们在动态注册 InnerReceiver 时,除了filter.addAction("CCTV5");也增加

filter.addAction("CCTV1");

然后在接收到广播时,对“频道”进行区分,再进行不同的处理

 String action = intent.getAction();

与此同时,我们还有 CustomReceiver 和 CustomReceiver2 ,也进行同样的“频道”区分操作

CustomReceiver

public class CustomReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //区分广播的“频道”
        String action = intent.getAction();
        if ("CCTV5".equals(action)) {
            String date = intent.getStringExtra("date");
            Log.d("BROADCAST", "CustomReceiver->onReceive();时间:" + date);
        } else if ("CCTV1".equals(action)) {
            int number = intent.getIntExtra("_number", -999);
            Log.d("BROADCAST", "CustomReceiver->onReceive();_number:" + number);
        } else {
        }
    }
}

CustomReceiver2

public class CustomReceiver2 extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //区分广播的“频道”
        String action = intent.getAction();
        if ("CCTV5".equals(action)) {
            String date = intent.getStringExtra("date");
            Log.d("BROADCAST", "CustomReceiver2->onReceive();时间:" + date);
        } else if ("CCTV1".equals(action)) {
            int number = intent.getIntExtra("_number", -999);
            Log.d("BROADCAST", "CustomReceiver2->onReceive();_number:" + number);
        } else {
        }
    }
}

在AndroidManifest中进行注册

<receiver android:name=".CustomReceiver">
            <intent-filter>
                <action android:name="CCTV1"/>
                <action android:name="CCTV5"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </receiver>

        <receiver android:name=".CustomReceiver2">
            <intent-filter>
                <action android:name="CCTV1"/>
                <action android:name="CCTV5"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </receiver>

运行程序

点击发送普通广播

D/BROADCAST: Mainctivity->onClick();时间:1523513945123
D/BROADCAST: CustomReceiver->onReceive();时间:1523513945123
D/BROADCAST: CustomReceiver2->onReceive();时间:1523513945123

点击发送有序广播

D/BROADCAST: CustomReceiver->onReceive();_number:0
D/BROADCAST: CustomReceiver2->onReceive();_number:0

再次点击发送有序广播

D/BROADCAST: CustomReceiver->onReceive();_number:1
D/BROADCAST: CustomReceiver2->onReceive();_number:1

点击注册内部接收者,再点击发送有序广播

D/BROADCAST: InnerReceiver->onReceive();_number:2
D/BROADCAST: CustomReceiver->onReceive();_number:2
D/BROADCAST: CustomReceiver2->onReceive();_number:2

广播的接收者们的优先级

  1. 根据注册广播时,IntentFilter 的priority属性决定,该属性的值是 int 类型的数值,数值越大,则优先级越高,即更优先接收到广播
  2. 当多个广播接收者的priority属性值相同时,动态注册的广播接收者优先级更高
  3. 当根据以上 2 条无法确定优先级时,将根据注册的先后顺序进行区分,先注册的优先级更高
  4. 如果在不同的应用程序中,都使用了相同的注册方式,且 priority 属性值相同
    如果是使用的动态注册,可以直接区分出执行注册的先后顺序
    如果是使用的静态注册,则根据项目的 package 属性值,按字典排序法进行区分

栗子

现有 3 个广播接收者

这里写图片描述

代码类似,以 HighReceiver 为例

public class HighReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //区分广播的“频道”
        String action = intent.getAction();
        if("CCTV5".equals(action)){
            String date = intent.getStringExtra("date");
            Log.d("BROADCAST","HighReceiver->onReceive();时间:"+date);
        }else if("CCTV1".equals(action)){
            int number = intent.getIntExtra("_number",-999);
            Log.d("BROADCAST","HighReceiver->onReceive();_number:"+number);
        }else{

        }
    }
}

都需要在AndroidManifest中注册

<receiver android:name=".HighReceiver">
            <intent-filter>
                <action android:name="CCTV1"/>
                <action android:name="CCTV5"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </receiver>

布局和上个栗子相同
这里写图片描述
除了上面的 HighReceiver、MidReceiver 和 LowReceiver 外,我们在 MainActivity 中再定义 3 个内部接收者 InnerHighReceiver、InnerMidReceiver 和 InnerLowReceiver

MainActivity进行改进

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button btnSend;
    private Button btnResiger;
    private Button btnUnregister;
    private Button btnSendOrderedBroadcast;
    private InnerHighReceiver highReceiver;
    private InnerMidReceiver midReceiver;
    private InnerLowReceiver lowReceiver;
    private int number;

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

        btnSend = findViewById(R.id.btn_send);
        btnResiger = findViewById(R.id.btn_register_receiver);
        btnUnregister = findViewById(R.id.btn_unregister_receiver);
        btnSendOrderedBroadcast = findViewById(R.id.btn_send_ordered_broadcast);
        btnSend.setOnClickListener(this);
        btnResiger.setOnClickListener(this);
        btnUnregister.setOnClickListener(this);
        btnSendOrderedBroadcast.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_send:
                long date = System.currentTimeMillis();
                Intent intent = new Intent();
                intent.setPackage("com.example.testapplication");
                intent.setAction("CCTV5");
                intent.putExtra("date", "" + date);
                Log.d("BROADCAST", "Mainctivity->onClick();时间:" + date);
                sendBroadcast(intent);
                break;
            case R.id.btn_send_ordered_broadcast:
                //准备Intent对象
                Intent intent2 = new Intent();
                intent2.setPackage("com.example.testapplication");
                intent2.putExtra("_number", number);
                number++;
                intent2.setAction("CCTV1");
                //接收者的权限
                String receiverPermission = null;
                //发送有序广播
                sendOrderedBroadcast(intent2, receiverPermission);
                break;
            case R.id.btn_register_receiver:
                if (highReceiver == null) {
                    highReceiver = new InnerHighReceiver();
                    IntentFilter hignFilter = new IntentFilter();
                    hignFilter.addAction("CCTV5");
                    hignFilter.addAction("CCTV1");
                    registerReceiver(highReceiver, hignFilter);
                }
                if (midReceiver == null) {
                    midReceiver = new InnerMidReceiver();
                    IntentFilter midFilter = new IntentFilter();
                    midFilter.addAction("CCTV5");
                    midFilter.addAction("CCTV1");
                    registerReceiver(midReceiver, midFilter);
                }
                if (lowReceiver == null) {
                    lowReceiver = new InnerLowReceiver();
                    IntentFilter lowFilter = new IntentFilter();
                    lowFilter.addAction("CCTV5");
                    lowFilter.addAction("CCTV1");
                    registerReceiver(lowReceiver, lowFilter);
                }
                break;
            case R.id.btn_unregister_receiver:
                if (highReceiver != null) {
                    unregisterReceiver(highReceiver);
                    highReceiver = null;
                }
                if (midReceiver != null) {
                    unregisterReceiver(midReceiver);
                    midReceiver = null;
                }
                if (lowReceiver != null) {
                    unregisterReceiver(lowReceiver);
                    lowReceiver = null;
                }
                break;
        }
    }

    private class InnerHighReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            //区分广播的“频道”
            String action = intent.getAction();
            if ("CCTV5".equals(action)) {
                String date = intent.getStringExtra("date");
                Log.d("BROADCAST", "InnerHighReceiver->onReceive();时间:" + date);
            } else if ("CCTV1".equals(action)) {
                int number = intent.getIntExtra("_number", -999);
                Log.d("BROADCAST", "InnerHighReceiver->onReceive();_number:" + number);
            } else {

            }
        }
    }
    private class InnerMidReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            //区分广播的“频道”
            String action = intent.getAction();
            if ("CCTV5".equals(action)) {
                String date = intent.getStringExtra("date");
                Log.d("BROADCAST", "InnerMidReceiver->onReceive();时间:" + date);
            } else if ("CCTV1".equals(action)) {
                int number = intent.getIntExtra("_number", -999);
                Log.d("BROADCAST", "InnerMidReceiver->onReceive();_number:" + number);
            } else {

            }
        }
    }
    private class InnerLowReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            //区分广播的“频道”
            String action = intent.getAction();
            if ("CCTV5".equals(action)) {
                String date = intent.getStringExtra("date");
                Log.d("BROADCAST", "InnerLowReceiver->onReceive();时间:" + date);
            } else if ("CCTV1".equals(action)) {
                int number = intent.getIntExtra("_number", -999);
                Log.d("BROADCAST", "InnerLowReceiver->onReceive();_number:" + number);
            } else {

            }
        }
    }
}

在不指定优先级的情况下,先点击“注册内部接收者”,然后点击发送“有序广播”
观察日志

D/BROADCAST: InnerHighReceiver->onReceive();_number:0
D/BROADCAST: InnerMidReceiver->onReceive();_number:0
D/BROADCAST: InnerLowReceiver->onReceive();_number:0
D/BROADCAST: HignReceiver->onReceive();_number:0
D/BROADCAST: MidReceiver->onReceive();_number:0
D/BROADCAST: LowReceiver->onReceive();_number:0

我们发现内部接收者会优先收到广播,下面我们手动设置priority属性

先设置内部类

 @Override
    public void onClick(View view) {
        switch (view.getId()) {
            ...
            case R.id.btn_register_receiver:
                if (highReceiver == null) {
                    highReceiver = new InnerHighReceiver();
                    IntentFilter hignFilter = new IntentFilter();
                    hignFilter.setPriority(100);
                    hignFilter.addAction("CCTV5");
                    hignFilter.addAction("CCTV1");
                    registerReceiver(highReceiver, hignFilter);
                }
                if (midReceiver == null) {
                    midReceiver = new InnerMidReceiver();
                    IntentFilter midFilter = new IntentFilter();
                    midFilter.setPriority(500);
                    midFilter.addAction("CCTV5");
                    midFilter.addAction("CCTV1");
                    registerReceiver(midReceiver, midFilter);
                }
                if (lowReceiver == null) {
                    lowReceiver = new InnerLowReceiver();
                    IntentFilter lowFilter = new IntentFilter();
                    lowFilter.setPriority(900);
                    lowFilter.addAction("CCTV5");
                    lowFilter.addAction("CCTV1");
                    registerReceiver(lowReceiver, lowFilter);
                }
                break;
            ...
        }
    }

再设置外部类

<receiver android:name=".HighReceiver">
            <intent-filter>
                <action android:name="CCTV1"/>
                <action android:name="CCTV5"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </receiver>
        <receiver android:name=".MidReceiver">
            <intent-filter android:priority="1000">
                <action android:name="CCTV1"/>
                <action android:name="CCTV5"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </receiver>
        <receiver android:name=".LowReceiver">
            <intent-filter android:priority="5000">
                <action android:name="CCTV1"/>
                <action android:name="CCTV5"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </receiver>

同样的先点击“注册内部接收者”,然后点击发送“有序广播”
观察日志

D/BROADCAST: LowReceiver->onReceive();_number:0
D/BROADCAST: MidReceiver->onReceive();_number:0
D/BROADCAST: InnerLowReceiver->onReceive();_number:0
D/BROADCAST: InnerMidReceiver->onReceive();_number:0
D/BROADCAST: InnerHighReceiver->onReceive();_number:0
D/BROADCAST: HighReceiver->onReceive();_number:0