android有序广播和无序广播的区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android有序广播和无序广播的区别相关的知识,希望对你有一定的参考价值。

同一优先级的广播接收器,动态的要比静态注册的早。
动态注册:即由代码注册的广播接收器静态注册:即在 androidManifest.xml 中注册的广播接收器 优先级: 当广播为有序发送的时候,要按这个排序并顺序发送。 sendBroadcast 发送的是无序广播。sendOrderedBroadcast 发送的是有序广播。 好了,现在寻找问题原因,在找原因前肯定有这样的想法,一个有序队列,既然允许有相同的优先级存在,那么在同优先级内要不然有排序子因素,要不基就是按照某种操作可能影响顺序。后者可能性很大。 打开源码,顺着 动态注册广播接受器 找,最后是 ActivityManagerService.java 这个文件找到了 registerReceiver 的实现。同地也看到,存储的广播接收器列表是 HashMap mRegisteredReceivers 这个变理。 里面有一段代码为: ReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder()); if (rl == null) rl = new ReceiverList(this, callerApp, Binder.getCallingPid(), Binder.getCallingUid(), receiver); if (rl.app != null) rl.app.receivers.add(rl); else try receiver.asBinder().linkToDeath(rl, 0); catch (RemoteException e) return sticky; rl.linkedToDeath = true; mRegisteredReceivers.put(receiver.asBinder(), rl); 在里面查找有没有这个 Receiver , 如果没有 put 进去。 看到这里貌似没有对广播的顺序做处理。是不是有别的地方做排序呢,找找成员变理,发现一个可疑的变量:final ArrayList mOrderedBroadcasts没错,感觉就应该是它了。 找找对它的操作,只有一处 mOrderedBroadcasts.set ,把代码摘录一下: BroadcastRecord r = new BroadcastRecord(intent, callerApp,
callerPackage, callingPid, callingUid, requiredPermission,
sticky, false); mOrderedBroadcasts.set(i, r);在这里放入了一个 BroadcastRecord 对像,而这个对像中主要的东西其实是 receivers向上跟踪 int NT = receivers != null ? receivers.size() : 0; int it = 0; ResolveInfo curt = null; BroadcastFilter curr = null; while (it < NT && ir < NR) if (curt == null) curt = (ResolveInfo)receivers.get(it); if (curr == null) curr = registeredReceivers.get(ir); if (curr.getPriority() >= curt.priority) // Insert this broadcast record into the final list. receivers.add(it, curr); ir++; curr = null; it++; NT++; else // Skip to the next ResolveInfo in the final list. it++; curt = null; 发现了一段 对 receivers 排序的代码,并且判断也是 priority 的值,用的是 >= 方式 感觉的找到了地方,但是对 Activity Manager Service 这个模块却更加的不懂了,以后有机会一定要分析一下这块是怎样设计的,才能确定本文的问题所在。暂时记录,以后分析!
参考技术A BroadcastReceiver所对应的广播分两类:普通广播和有序广播。
普通广播:通过Context.sendBroadcast()方法来发送,它是完全异步的。
所有的receivers(接收器)的执行顺序不确定,因此所有的receivers(接收器)接收broadcast的顺序不确定。
这种方式效率更高,但是BroadcastReceiver无法使用setResult系列、getResult系列及abort(中止)系列API

有序广播:是通过Context.sendOrderedBroadcast来发送,所有的receiver依次执行。
BroadcastReceiver可以使用setResult系列函数来结果传给下一个BroadcastReceiver,通过getResult系列函数来取得上个BroadcastReceiver返回的结果,并可以abort系列函数来让系统丢弃该广播,使用该广播不再传送到别的BroadcastReceiver。
可以通过在intent-filter中设置android:priority属性来设置receiver的优先级,优先级相同的receiver其执行顺序不确定。
如果BroadcastReceiver是代码中注册的话,且其intent-filter拥有相同android:priority属性的话,先注册的将先收到广播。

有序广播,即从优先级别最高的广播接收器开始接收,接收完了如果没有丢弃,就下传给下一个次高优先级别的广播接收器进行处理,依次类推,直到最后。如果多个应用程序设置的优先级别相同,则谁先注册的广播,谁就可以优先接收到广播。
这里接收短信的广播是有序广播,因此可以设置你自己的广播接收器的级别高于系统原来的级别,就可以拦截短信,并且不存收件箱,也不会有来信提示音。
实现方法是:
<receiver android:name=".SmsReceiver">

<intent-filter android:priority="100">

<action android:name="android.provider.Telephony.SMS_RECEIVED"/>

</intent-filter>

</receiver>
里面的android:priority="100"就是设定广播接收器的级别,这个值从1000~-1000,数值越大,优先级别就越高。

Android-有序广播

在之前的博客,Android-广播概念,中介绍了(广播和广播接收者)可以组件与组件之间进行通讯,有两种类型的广播(无序广播 和 有序广播),这篇博客就来讲解有序广播的代码实现:

 

有序广播:接收者 可以自己设置接受的顺序,所以叫有序广播

 

定义 MyBroadcastReceiver 接收者

package liudeli.croadcast1;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

/**
 * 定义 接收者
 */
public class MyBroadcastReceiver extends BroadcastReceiver {

    private final String TAG = MyBroadcastReceiver.class.getSimpleName();

    /**
     * 接收的方法
     * @param context 传递过来的上下文
     * @param intent 传递过来的意图,可以获取很多信息
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "【111】intent.getAction():" + intent.getAction());
        Log.d(TAG, "【111】intent.getDataString():" + intent.getDataString());

        // 真实开发中是这样写的
        if ("my.MyBroadcastReceiver.custom.action2".equals(intent.getAction())) {
            String data = intent.getDataString();
            String[] dataArray = data.split(":");
            Log.d(TAG, "【111】data:" + dataArray[1]);
            Log.d(TAG, "【111】music:" + intent.getStringExtra("music"));
        } else if ("xxx.action".equals(intent.getAction())) {
            // 做相应的业务逻辑处理
            // ...
        } else if ("xxx.action".equals(intent.getAction())) {
            // 做相应的业务逻辑处理
            // ...
        }
    }
}

 

定义 MyBroadcastReceiver2 接收者

package liudeli.croadcast1;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

/**
 * 定义 接收者
 */
public class MyBroadcastReceiver2 extends BroadcastReceiver {

    private final String TAG = MyBroadcastReceiver.class.getSimpleName();

    /**
     * 接收的方法
     * @param context 传递过来的上下文
     * @param intent 传递过来的意图,可以获取很多信息
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "【222】intent.getAction():" + intent.getAction());
        Log.d(TAG, "【222】intent.getDataString():" + intent.getDataString());

        // 真实开发中是这样写的
        if ("my.MyBroadcastReceiver.custom.action2".equals(intent.getAction())) {
            String data = intent.getDataString();
            String[] dataArray = data.split(":");
            Log.d(TAG, "【222】data:" + dataArray[1]);
            Log.d(TAG, "【222】music:" + intent.getStringExtra("music"));
        } else if ("xxx.action".equals(intent.getAction())) {
            // 做相应的业务逻辑处理
            // ...
        } else if ("xxx.action".equals(intent.getAction())) {
            // 做相应的业务逻辑处理
            // ...
        }
    }
}

 

第一步:在onCreate() 订阅接收者 在订阅的时候给自己设置优先级别 -1000 --> 1000

第二步:点击按钮发送广播(原则:怎么订阅就怎么发送)

第三部:在onDestroy()解除订阅

package liudeli.croadcast1;

import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;

public class NewActivity2 extends Activity {

    private MyBroadcastReceiver myBroadcastReceiver;
    private MyBroadcastReceiver2 myBroadcastReceiver2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_new2);

        /**
         * 【Java代码方式订阅 接收者】
         * 唯一可以new的组件就是 广播 接收者
         */
        myBroadcastReceiver = new MyBroadcastReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("my.MyBroadcastReceiver.custom.action.sendOrderBroadcast");
        intentFilter.addDataScheme("zhangyusheng"); // 注意:这里不能加 :
        intentFilter.setPriority(88); // 在订阅的时候给自己设置优先级别 -1000 --> 1000
        registerReceiver(myBroadcastReceiver, intentFilter);

        /**
         * 【Java代码方式订阅 接收者】
         * 唯一可以new的组件就是 广播 接收者
         */
        myBroadcastReceiver2 = new MyBroadcastReceiver2();
        IntentFilter intentFilter2 = new IntentFilter();
        intentFilter2.addAction("my.MyBroadcastReceiver.custom.action.sendOrderBroadcast");
        intentFilter2.addDataScheme("zhangyusheng"); // 注意:这里不能加 :
        intentFilter2.setPriority(1000); // 在订阅的时候给自己设置优先级别 -1000 --> 1000
        registerReceiver(myBroadcastReceiver2, intentFilter2);
    }

    /**
     * 发送有序广播
     */
    public void sendOrderBroadcast(View view) {
        /**
         * 接收者是这样订阅的:怎么订阅,就怎么发送
         *         IntentFilter intentFilter = new IntentFilter();
         *         intentFilter.addAction("my.MyBroadcastReceiver.custom.action.sendOrderBroadcast");
         *         intentFilter.addDataScheme("zhangyusheng"); // 注意:这里不能加 :
         */
        Intent intent = new Intent();
        intent.setAction("my.MyBroadcastReceiver.custom.action.sendOrderBroadcast");
        intent.setData(Uri.parse("zhangyusheng:亚洲第一男高音")); // 注意:要加 :
        intent.putExtra("music", "我期待 作词作曲 张雨生"); // 而外携带值

        // 参数一:意图    参数二:谁能接收我的广播(自定义权限)
        sendOrderedBroadcast(intent, null);
    }

    /**
     * Java方式订阅接收者后 必须要解除订阅
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (myBroadcastReceiver != null)
            unregisterReceiver(myBroadcastReceiver);

        if (myBroadcastReceiver2 != null)
            unregisterReceiver(myBroadcastReceiver2);
    }
}

 

现在就是有序广播 接收者 的信息:【222】先打印 先接受 是因为设置了优先级别:1000  ,而【111】后接受 是因为设置了优先级别:88

12-17 08:11:45.536 4165-4165/liudeli.croadcast1 D/MyBroadcastReceiver: 【222】intent.getAction():my.MyBroadcastReceiver.custom.action.sendOrderBroadcast
12-17 08:11:45.536 4165-4165/liudeli.croadcast1 D/MyBroadcastReceiver: 【222】intent.getDataString():zhangyusheng:亚洲第一男高音
12-17 08:11:45.550 4165-4165/liudeli.croadcast1 D/MyBroadcastReceiver: 【111】intent.getAction():my.MyBroadcastReceiver.custom.action.sendOrderBroadcast
12-17 08:11:45.550 4165-4165/liudeli.croadcast1 D/MyBroadcastReceiver: 【111】intent.getDataString():zhangyusheng:亚洲第一男高音

 

以上是关于android有序广播和无序广播的区别的主要内容,如果未能解决你的问题,请参考以下文章

Android四大组件详解

Android-有序广播

Android-有序广播是可以中断的

BroadCastRecieve

有序广播与无序广播

ANR系列:广播触发ANR的原理