Android中的有序和無序廣播淺析

BroadcastReceiver所對應(yīng)的廣播分兩類:無序廣播和有序廣播。

無序廣播即為我們平時經(jīng)常使用的廣播,其主要是通過public abstract void sendBroadcast (Intent intent)方法進(jìn)行發(fā)送,并通過intent傳遞數(shù)據(jù)。代碼示例如下:

Intent nonOrderIntent = new Intent();
nonOrderIntent.setAction(ACTION);
sendBroadcast(nonOrderIntent);

無序廣播會被注冊了的相應(yīng)的感興趣(intent-filter匹配)接收,且順序是無序的。如果發(fā)送廣播時有相應(yīng)的權(quán)限要求,BroadCastReceiver如果想要接收此廣播,也需要有相應(yīng)的權(quán)限。

無序廣播的廣播接收者不可以使用setResultData()方法和abortBroadcast()方法,如果使用了會報錯。 但是可以使用getResultData()方法,雖然不報錯,但是獲取到的數(shù)據(jù)為null。但是在一種<u>特殊情況</u>下,getResultData()方法能取到無序廣播傳遞的數(shù)據(jù),下文會說明在什么情況下。

無序廣播不可以被攔截,不可以被終止,不可以被修改,無序廣播任何接收者只要匹配條件都可以接收到,無優(yōu)先級問題。

如果想通過無序廣播傳遞數(shù)據(jù),則可以調(diào)用intent.putExtra方法傳遞, 接收者可通過intent.get...接收,不可通過getResultData接收。

有序廣播主要是通過public abstract void sendOrderedBroadcast (Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)方法進(jìn)行發(fā)送。代碼示例如下:

Intent intent = new Intent();
intent.setAction(ACTION);
sendOrderedBroadcast(intent, null, new Priority2BroadcastReceiver(), null, Activity.RESULT_OK, "MainActivity發(fā)送了一個有序廣播", null);

先介紹一下public abstract void sendOrderedBroadcast (Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)方法

官網(wǎng)api的參數(shù)解釋:

Parameters
intent The Intent to broadcast; all receivers matching this Intent will receive the broadcast.
receiverPermission String naming a permissions that a receiver must hold in order to receive your broadcast. If null, no permission is required.
resultReceiver Your own BroadcastReceiver to treat as the final receiver of the broadcast.
scheduler  A custom Handler with which to schedule the resultReceiver callback; if null it will be scheduled in the Context's main thread.
initialCode    An initial value for the result code. Often Activity.RESULT_OK.
initialData    An initial value for the result data. Often null.
initialExtras  An initial value for the result extras. Often null.

第一個intent:不多說指定intent,所有廣播接收者的匹配規(guī)則

第二個receiverPermission:指定廣播接收器的權(quán)限,一般自定義,不常用,可傳null。

第三個resultReceiver:指定一個最終的廣播接收器,相當(dāng)于finally功能,不論優(yōu)先級,最后都要接收一次廣播,而這一次收到的廣播為無序廣播(可以在BroadcastReceiver中通過boolean orderedBroadcast = isOrderedBroadcast()方法驗證),但是卻可以通過getResultData等方法取得數(shù)據(jù),這就是上面提到的特殊情況。

第四個scheduler:看英文沒怎么看懂什么意思,一般傳null。

第五個initialCode:指定一個code,一般傳Activity.RESULT_OK。

第六個initialData:傳一個字符串?dāng)?shù)據(jù)。對應(yīng)的在BroadcastReceiver中通過String resultData = getResultData()取得數(shù)據(jù);通過setResultData("優(yōu)先級為3的setResultData的數(shù)據(jù)")修改數(shù)據(jù),將數(shù)據(jù)傳給下一個優(yōu)先級較低的BroadcastReceiver;如果在優(yōu)先級較高的BroadcastReceiver中沒有使用setResultData修改數(shù)據(jù),那么優(yōu)先級較低的接收到的數(shù)據(jù)還是最原始的數(shù)據(jù),即initialData的值。

第七個initialExtras:傳一個Bundle對象,也就是可以傳多種類型的數(shù)據(jù)。對應(yīng)的在BroadcastReceiver中通過Bundle bundle = getResultExtras(false)取得Bundle對象,然后再通過bundle的各種get方法取得數(shù)據(jù);通過setResultExtras()傳入一個修改過的bundle,將該bundle對象傳給下一個優(yōu)先級較低的BroadcastReceiver;如果在優(yōu)先級較高的BroadcastReceiver中沒有使用setResultExtras修改數(shù)據(jù),那么優(yōu)先級較低的接收到的數(shù)據(jù)還是最原始的bundle對象,即initialExtras的值。

有序廣播所對應(yīng)的所有的receiver按照在intent-filter中設(shè)置的android:priority屬性依次執(zhí)行,android:priority表示優(yōu)先級,值越大,其所對應(yīng)的廣播接收者,越先接收到廣播。在android:priority相同的情況下,如果廣播接收器是通過靜態(tài)注冊的,則接收到廣播的順序不確定,如果是動態(tài)注冊的,先注冊的將先收到廣播。

有序廣播可以被攔截,?可以在較高優(yōu)先級的接收器中通過abortBroadcast()攔截廣播,這樣就會導(dǎo)致較低優(yōu)先級的接收器無法收到廣播了,但是sendOrderedBroadcast第三個參數(shù)指定的BroadcastReceiver還是會收到廣播的,而且能獲得數(shù)據(jù)。

有序廣播可以通過原始intent.putExtra這種方式傳遞數(shù)據(jù)給BroadcastReceiver,也能通過sendOrderedBroadcast方法的最后2個參數(shù)傳遞數(shù)據(jù),但是通過第一種方式傳遞的數(shù)據(jù)無法中途修改,通過第二種方式傳遞的可以通過上面參數(shù)說明中的方式進(jìn)行修改。

具體驗證方式可通過如下代碼驗證以上結(jié)論:

MainActivity

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

import com.tbc.hsx.testbroadcast.receiver.Priority2BroadcastReceiver;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String ACTION = "com.tbc.hsx.testbroadcast.MainActivity";
    public static final String DATA = "data";
    public static final String ORDER_DATA = "order_data";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });


        findViewById(R.id.send_broadcast_btn).setOnClickListener(this);
        findViewById(R.id.send_ordered_broadcast_btn).setOnClickListener(this);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    Handler handler = new Handler() {
        @Override
        public void dispatchMessage(Message msg) {
            super.dispatchMessage(msg);

        }
    };

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.send_broadcast_btn) {
            Intent nonOrderIntent = new Intent();
            nonOrderIntent.setAction(ACTION);
            sendBroadcast(nonOrderIntent);
        } else if (view.getId() == R.id.send_ordered_broadcast_btn) {
            Intent intent = new Intent();
            intent.putExtra(DATA, "有序廣播通過intent.putExtra傳遞的數(shù)據(jù)");
            intent.setAction(ACTION);
            Bundle bundle = new Bundle();
            bundle.putString(ORDER_DATA, "有序廣播通過bundle傳遞的數(shù)據(jù)");

            sendOrderedBroadcast(intent, null, new Priority2BroadcastReceiver(), handler, Activity.RESULT_OK, "MainActivity發(fā)送了一個有序廣播", bundle);
        }

    }
}

Priority1BroadcastReceiver

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

/**
 * Created by Doraemon
 * Date: 16/4/27
 * Time: 16:35
 * Summary:優(yōu)先級為1的廣播接收器
 */
public class Priority1BroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {

        String resultData = getResultData();//獲取有序廣播的數(shù)據(jù)
        System.out.println("優(yōu)先級為1的接收到的廣播數(shù)據(jù)resultData---->" + resultData);
        setResultData("優(yōu)先級為1的setResultData的數(shù)據(jù)");//修改有序廣播的數(shù)據(jù)
    }
}

Priority2BroadcastReceiver

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import com.tbc.hsx.testbroadcast.MainActivity;

/**
 * Created by Doraemon
 * Date: 16/4/27
 * Time: 16:35
 * Summary:
 */
public class Priority2BroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {

        boolean orderedBroadcast = isOrderedBroadcast();

        if (orderedBroadcast) {
            System.out.println("優(yōu)先級為1的接收者接收到的是有序廣播");
        } else {
            System.out.println("優(yōu)先級為1的接收者接收到的是無序廣播");
        }


        Bundle bundle=getResultExtras(false);
        if (bundle != null) {
            String orderData = bundle.getString(MainActivity.ORDER_DATA);
            System.out.println("Priority2BroadcastReceiver-------->" + orderData);
        }

        String resultData = getResultData();//獲取有序廣播的數(shù)據(jù)
        System.out.println("優(yōu)先級為2的接收到的廣播數(shù)據(jù)resultData---->" + resultData);
        setResultData("優(yōu)先級為2的setResultData的數(shù)據(jù)");//修改有序廣播的數(shù)據(jù)
    }
}

Priority3BroadcastReceiver

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import com.tbc.hsx.testbroadcast.MainActivity;

/**
 * Created by Doraemon
 * Date: 16/4/27
 * Time: 16:32
 * Summary:
 */
public class Priority3BroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {

        Bundle bundle = getResultExtras(false);
        if (bundle != null) {
            String orderData = bundle.getString(MainActivity.ORDER_DATA);
            System.out.println("Priority3BroadcastReceiver-------->" + orderData);
        }

//        bundle.putString(MainActivity.ORDER_DATA, "優(yōu)先級為3的接收者修改了bundle數(shù)據(jù)");
//        setResultExtras(bundle);

        boolean orderedBroadcast = isOrderedBroadcast();
        if (orderedBroadcast) {
            System.out.println("優(yōu)先級為3的接收者接收到的是有序廣播");
        } else {
            System.out.println("優(yōu)先級為3的接收者接收到的是無序廣播");
        }
        String resultData = getResultData();//獲取有序廣播的數(shù)據(jù)
        System.out.println("優(yōu)先級為3的接收到的廣播數(shù)據(jù)resultData---->" + resultData);
        setResultData("優(yōu)先級為3的setResultData的數(shù)據(jù)");//修改有序廣播的數(shù)據(jù)
//        abortBroadcast();

    }
}

AndroidManifest.xml(BroadcastReceiver注冊部分)

<receiver android:name=".receiver.Priority1BroadcastReceiver">
    <intent-filter android:priority="1">
        <action android:name="com.tbc.hsx.testbroadcast.MainActivity" />
    </intent-filter>
</receiver>
<receiver android:name=".receiver.Priority2BroadcastReceiver">
    <intent-filter android:priority="2">
        <action android:name="com.tbc.hsx.testbroadcast.MainActivity" />
    </intent-filter>
</receiver>

<receiver android:name=".receiver.Priority3BroadcastReceiver">
    <intent-filter android:priority="3">
        <action android:name="com.tbc.hsx.testbroadcast.MainActivity" />
    </intent-filter>
</receiver>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Broadcasts Android apps can send or receive broadcast mes...
    woitaylor閱讀 6,737評論 0 12
  • 廣播接收器 是Android的四大組件之一,可見廣播在Android中的重要性; 1. 什么是廣播? 廣播(Bro...
    Lost_Robot閱讀 2,051評論 2 10
  • 現(xiàn)實中的廣播:電臺為了傳達(dá)一些消息而發(fā)送廣播,通過廣播攜帶要傳達(dá)的消息,群眾只要買一個收音機,就可以收到廣播了。 ...
    stevewang閱讀 4,375評論 0 8
  • 沒有一絲光亮 我在獨自尋找 是高山的巍峨 還是流水的漫長 無聲的世界 我聽見喧囂 物色的世界 我看見紛擾 可是我在...
    李瀟寒閱讀 144評論 0 0
  • 佛說,前世的500次回眸才換來今生的擦肩而過。一些愿望,如果今生屢屢矚目,就埋了一個下輩子擦肩而過的伏筆。我就想,...
    晨曦gy閱讀 147評論 0 1

友情鏈接更多精彩內(nèi)容