1.android有序广播和无序广播的区别
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属性的话,先注册的将先收到广播。
有序广播,即从优先级别最高的广播接收器开始接收,接收完了如果没有丢弃,就下传给下一个次高优先级别的广播接收器进行处理,依次类推,直到最后。
2.sendBroadcast和sendStickyBroadcast的区别
sendBroadcast中发出的intent在ReceverActivity不处于onResume状态是无法接受到的,即使后面再次使其处于该状态也无法接受到。
而sendStickyBroadcast发出的Intent当ReceverActivity重新处于onResume状态之后就能重新接受到其Intent.这就是the Intent will be held to be re-broadcast to future receivers这句话的表现。就是说sendStickyBroadcast发出的最后一个Intent会被保留,下次当Recevier处于活跃的时候,又会接受到它。
3. FLAG的影响
1)FLAG_RECEIVER_REPLACE_PENDING
这个flag 将会将之前的Intent 替代掉。加了这个flag,在发送一系列的这样的Intent 之后, 中间有些Intent 有可能在你还没有来得及处理的时候,就被替代掉了。
2)FLAG_RECEIVER_REGISTERED_ONLY:
如果Intent 加了这个Flag, 那么在Androidmanifest.xml 里定义的Receiver 是接收不到这样的Intent 的。
3)FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT:
如果Intent加了这个Flag,那么在启动检查时只能接受在代码中注册的Receiver。这个标志是唯一使用的系统服务作为一种方便避免实施更复杂的机制在启动完成检测。
sendStickyBroadcast 的理解和使用
要知道区别首先需要看一下Android Developers Reference, 它可是我们最好的老师了,sendBroadcast 大家应该都会用了我就不赘述了,下面来看看sendStickyBroadcast
google官方的解释是:
Perform a sendBroadcast(Intent)
that is "sticky," meaning the Intent you are sending stays around after the broadcast is complete, so that others can quickly retrieve that data through the return value ofregisterReceiver(BroadcastReceiver, IntentFilter)
. In all other ways, this behaves the same as sendBroadcast(Intent)
.
You must hold the BROADCAST_STICKY
permission in order to use this API. If you do not hold that permission,SecurityException
will be thrown.
大概的意思是说: 发出的广播会一直滞留(等待),以便有人注册这则广播消息后能尽快的收到这条广播。其他功能与sendBroadcast相同。但是使用sendStickyBroadcast 发送广播需要获得
BROADCAST_STICKY
permission,如果没有这个permission则会抛出异常。
这个解释看了后似懂非懂的,于是就写了个例子试了下,下面把代码贴出了,希望能还大家一起讨论
- package com.android.test;
- import android.app.Activity;
- import android.content.Context;
- import android.content.Intent;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- public class StickyBroadcastTest extends Activity {
- private Button mSendBroadcast;
- private Button mSendStickyBroadcast;
- private Button mNextActivity;
- private Context mContext;
- private int mStickyBrcCount;
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mContext = getApplicationContext();
- mSendBroadcast = (Button)findViewById(R.id.broadcast);
- mSendStickyBroadcast = (Button)findViewById(R.id.stickybroadcast);
- mNextActivity = (Button)findViewById(R.id.next_activity);
- mSendBroadcast.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent("com.android.action.broadcast");
- mContext.sendBroadcast(intent);
- }
- });
- mSendStickyBroadcast.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mStickyBrcCount++;
- Intent intent = new Intent("com.android.action.sticky.broadcast");
- intent.putExtra("sent_count", mStickyBrcCount);
- mContext.sendStickyBroadcast(intent);
- }
- });
- mNextActivity.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(StickyBroadcastTest.this, MyReceiverActivity.class);
- startActivity(intent);
- }
- });
- }
- @Override
- protected void onResume() {
- // TODO Auto-generated method stub
- super.onResume();
- mStickyBrcCount = 0;
- }
- }
- //MyReceiverActivity
- package com.android.test;
- import android.app.Activity;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- import android.os.Bundle;
- import android.util.Log;
- public class MyReceiverActivity extends Activity {
- private IntentFilter mIntentFilter;
- private final static String TAG = "MyReceiverActivity";
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.broadcast_receiver);
- mIntentFilter = new IntentFilter();
- mIntentFilter.addAction("com.android.action.broadcast");
- mIntentFilter.addAction("com.android.action.sticky.broadcast");
- }
- private BroadcastReceiver mReceiver = new BroadcastReceiver () {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- int count = intent.getIntExtra("sent_count", -1);
- Log.d(TAG, "action = " + action + "and count = " + count);
- //context.removeStickyBroadcast(intent);
- }
- };
- @Override
- protected void onPause() {
- // TODO Auto-generated method stub
- super.onPause();
- unregisterReceiver(mReceiver);
- }
- @Override
- protected void onResume() {
- // TODO Auto-generated method stub
- super.onResume();
- registerReceiver(mReceiver, mIntentFilter);
- }
- }
运行结果如图:
首先点击next Activity从代码中可以看到receiver已经注册,但Log无输出,这是当然的了~~~因为没有广播发出自然就不会有人响应了。
按back后退到上图
下面分别点击send broadcast 和 send stickybroadcast按钮,随便点击几次,此时对应的receiver并没有注册,所以是不会有人响应这两条广播的。然后点击next activity,当打开新的activity后对应的receiver被注册,此时从日志中就能看出已经收到了send stickybroadcast发出的广播,但没有send broadcast发出的广播。这就是sendStickyBroadcast的特别之处,它将发出的广播保存起来,一旦发现有人注册这条广播,则立即能接收到。
日志打印为: action = com.android.action.sticky.broadcastand count = 4
从上面的日志信息可以看出sendStickyBroadcast只保留最后一条广播,并且一直保留下去,这样即使已经处理了这条广播但当再一次注册这条广播后依然可以收到它。
如果你只想处理一遍,removeStickyBroadcast方法可以帮你,处理完了后就将它删除吧。
相似的例子:
- package com.android.testbroadcast;
- import android.app.Activity;
- import android.content.Context;
- import android.content.Intent;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- public class MainActivity extends Activity {
- Button btnSendi;
- Button btnSends;
- Button btnStart;
- Context mContext;
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- btnSendi=(Button) findViewById(R.id.sendi);
- btnSends=(Button) findViewById(R.id.sends);
- btnStart=(Button) findViewById(R.id.start);
- mContext=getApplicationContext();
- btnSendi.setOnClickListener(new OnClickListener(){
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Intent intent = new Intent();
- intent.setAction("com.android.my.action");
- intent.setFlags(1);
- mContext.sendBroadcast(intent);
- }
- });
- btnStart.setOnClickListener(new OnClickListener(){
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Intent intent = new Intent(MainActivity.this,ReceiverActivity.class);
- startActivity(intent);
- }
- });
- btnSends.setOnClickListener(new OnClickListener(){
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Intent intent = new Intent();
- intent.setAction("com.android.my.action.sticky");
- intent.setFlags(2);
- mContext.sendStickyBroadcast(intent);
- }
- });
- }
- }
- package com.android.testbroadcast;
- import android.app.Activity;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- import android.net.wifi.WifiManager;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- public class ReceiverActivity extends Activity {
- private IntentFilter mIntentFilter;
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mIntentFilter = new IntentFilter();
- mIntentFilter.addAction("com.android.my.action");
- mIntentFilter.addAction("com.android.my.action.sticky");
- }
- private BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- System.out.println("action"+action);
- }
- };
- @Override
- protected void onResume() {
- // TODO Auto-generated method stub
- super.onResume();
- registerReceiver(mReceiver, mIntentFilter);
- }
- @Override
- protected void onPause() {
- // TODO Auto-generated method stub
- super.onPause();
- unregisterReceiver(mReceiver);
- }
- }
在MainActivity里面会有sendBroadcast和sendStickyBroacat.在ReceverActivity里面通 过BroadcastReceiver来接收这两个消息,在ReceiverActivity里是通过代码来注册Recevier而不是在 Manifest里面注册的。所以通过sendBroadcast中发出的intent在ReceverActivity不处于onResume状态是无 法接受到的,即使后面再次使其处于该状态也无法接受到。而sendStickyBroadcast发出的Intent当ReceverActivity重 新处于onResume状态之后就能重新接受到其Intent.这就是the Intent will be held to be re-broadcast to future receivers这句话的表现。就是说sendStickyBroadcast发出的最后一个Intent会被保留,下次当Recevier处于活跃的 时候,又会接受到它。