Broadcast

**

Broadcast

**

广播的优先级的作用?如何设置广播优先级?

可以给广播接收者设定优先级来控制接收顺序,并却可以中断广播传递
相同优先级的情况下,动态注册优先级别高于静态注册
使用**intent-filter里面的android: priority=”xxx”去解决或在java代码中用setPriority(xxx)**来设置

1. Broadcast的分类?

无序广播

通过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中注册

 <receiver
      android:name=".MyBroadcastReceiver"
      android:enabled="true"
      android:exported="true">
      <intent-filter android:priority="500">
         <action android:name="Intercept_Stitch" />
      </intent-filter>
</receiver>
<receiver
      android:name=".MyBroadcastReceiver2"
      android:enabled="true"
      android:exported="true">
    <intent-filter android:priority="214748367">
          <action android:name="Intercept_Stitch" />
     </intent-filter>
</receiver>

有序广播

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

----------静态发送有序广播

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

---------动态发送有序广播

MyBroadcastReceiver receiver = new MyBroadcastReceiver();
MyBroadcastReceiver2 receiver2 = new MyBroadcastReceiver2();

IntentFilter filter = new IntentFilter("Intercept_Stitch");
IntentFilter filter2 = new IntentFilter("Intercept_Stitch");
filter.setPriority(999);
filter2.setPriority(500);

registerReceiver(receiver, filter);
registerReceiver(receiver2, filter2);

Intent intent = new Intent();
intent.setAction("Intercept_Stitch");
sendOrderedBroadcast(intent, null);

系统广播:

Android内置很多系统级别广播,如手机开机后发一条广播,电池电量发生变化发一条广播等等。
在这里插入图片描述

本地广播(App应用内广播)

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

具体使用1 - 将全局广播设置成局部广播
1.注册广播时将exported属性设置为false,使得非本App内部发出的此广播不被接收;
2.在广播发送和接收时,增设相应权限permission,用于权限验证;
3.指定该广播接收器所在的包名,通过intent.setPackage(packageName)指定包名

具体使用2 - 使用封装好的LocalBroadcastManager类
LocalBroadcastManager发送的应用内广播只能通过LocalBroadcastManager动态注册,不能静态注册

1.发广播:

Intent intent = new Intent();
intent.setAction(Constants.ANSWERED_RECEIVER_ACTION);//自定义action
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);

2.接收广播:
1.实现BroadCastReceiver类:

private class AnsweredReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            postPaperRecord(examPaperBean);
       }
}

2.注册该广播接收器:

answeredReceiver = new AnsweredReceiver();
IntentFilter filter = new IntentFilter(Constants.ANSWERED_RECEIVER_ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(answeredReceiver,filter);

3.注销该广播接收器:

LocalBroadcastManager.getInstance(context).unregisterReceiver(answeredReceiver);

2. 粘性广播有什么作用?怎么使用?

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

在Android系统粘性广播一般用来确保重要的状态改变后的信息被持久保存,并且能随时广播给新的广播接收器,比如电源的改变,因为耗电需要一个过程,前一个过程必须提前得到,否则可能遇到下次刚好接收到的广播后系统自动关机了,随之而来的是kill行为,所以对某些未处理完的任务来说,后果很严重。

发送粘性广播需要权限(这里的权限是保存信息的权限和由系统发送未处理的广播的权限)

<uses-permission android:name="android.permission.BROADCAST_STICKY" />

粘性广播的发送,和普通广播的发送方式是一致的

Intent intent = new Intent();
intent .setAction(StickyBroadcastReceiver.Action);
intent .putExtra("info", "sticky broadcast has been receiver");
sendStickyBroadcast(intent );

-----------------------------------------------------使用普通广播接收器,注意,必须在Manifiest或者发送之前接收(这和定义有点违背,因为这种方式不是正确的接收方式,在Manifest注册了广播接收器相当于在发送广播之前接收)

public class StickyBroadcastReceiver extends BroadcastReceiver {
 
    public static final String Action = "com.sample.test.sticky.broadcast.receiver";
    public static final String PERMISSION = "com.sample.test.permission.sticky.receiver";
    @Override
    public void onReceive(Context context, Intent intent)
    {
        int checkCallingOrSelfPermission = context.checkCallingOrSelfPermission(PERMISSION);
        if(PackageManager.PERMISSION_GRANTED == checkCallingOrSelfPermission) //权限判断
        {
            Toast.makeText(context, "授权成功", Toast.LENGTH_SHORT).show();
        }else{
            Toast.makeText(context, "授权失败", Toast.LENGTH_SHORT).show();
            throw new RuntimeException("permission denied");
        }
        if(intent!=null&&Action.equals(intent.getAction()))
        {
            Toast.makeText(context, intent.getStringExtra("info"), Toast.LENGTH_SHORT).show();
        }
    }
 
}

Mainifest.xml

<!--自定义权限-->
<permission android:name="com.sample.test.permission.sticky.receiver" android:protectionLevel="normal" />
<!--使用自定义权限-->
<uses-permission android:name="com.sample.test.permission.sticky.receiver"/>
<!--使用粘性广播发送权限-->
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
 
<!--省略一部分-->
 
<receiver android:name="test.view.weitop.home.StickyBroadcastReceiver"
    android:permission="com.sample.test.permission.sticky.receiver" >
    <!--android:permission 其他应用使用时,需要检测的权限-->
    <intent-filter >
         <action android:name="com.sample.test.sticky.broadcast.receiver"/>
    </intent-filter>
</receiver>

---------------------------------------------------使用正确的方式接收(推荐)

正确的接收方式不应该使用BroadcastReceiver就可以接收到

只需要将SenderActivity的onResume稍作修改即可

@Override
protected void onResume() {
    super.onResume();
//3秒后发送
 getWindow().getDecorView().postDelayed(new Runnable() {
 
    @Override
        public void run()
         {
         sendStickyBroadcast();
      }
    }, 3*1000);


 
//15秒后就收
getWindow().getDecorView().postDelayed(new Runnable() {
 
    @Override
    public void run()
    {
        IntentFilter intentFilter = new IntentFilter(StickyBroadcastReceiver.Action);
        Intent data = registerReceiver(null, intentFilter);
        if(data!=null&&StickyBroadcastReceiver.Action.equals(data.getAction()))
        {
            Toast.makeText(this, data.getStringExtra("info"), Toast.LENGTH_SHORT).show();
        }
    }
    }, 15*1000);
}

在这样一个相差10秒左右的时间段 【先发送,后接收】,说明了粘性广播的已经将信息完全保存起来了,只要我们去使用如下方式,即可获取到,而且无限次获取。

Intent data = registerReceiver(null, intentFilter); //注意,不需要接收器,否则可能无法接收到

附注:这种广播也可以被移除 ,我们可以接收到 广播后调用 removeStickyBroadcast(intent);

3. Broadcast有哪几种注册的方式?如何注册?

1.静态注册:在Manifest.xml中注册完成就一直运行,App关闭了也不受影响。

<receiver android: name =“Receiver1”>

     <intent-filter>

         <!----和Intent中的action对应--->

         <actionandroid: name=“com.forrest.action.mybroadcast”/>

     </intent-filter>

</receiver>

2.动态注册:在代码中注册,跟随Activity的生命周期。

1) IntentFilter filter = new IntentFilter(“com.forrest.action.mybroadcast”);//和广播中Intent的action对应;

2) MyBroadcastReceiver br= new MyBroadcastReceiver();

3) registerReceiver(br, filter);

两种注册方式的区别:
在这里插入图片描述

4. BroadcastReceiver反注册

Android BroadcastReceiver 注册和反注册
说起来这个问题很简单,只要注册和反注册成对出现就行,好像很多教材都是如此介绍。但实际开发中,对广播注册和反注册的时机把握还是很重要的。

关于广BroadcastReceiver注册和反注册时机,主要有以下几点:

onCreate - onDestroy(即便页面未显示,仍然能接受广播)
onResume - onPause(即只有页面显示时,才能接受广播)
onStart - onStop

http://stackoverflow.com/questions/21136464/when-to-use-unregisterreceiver-onpause-ondestroy-or-onstop

当注册广播时,常会遇到的问题就是重复注销广播处理函数是会报错,而且会让进程奔溃。一般来说,可以通过一个变量来保存广播处理是否被注销,每当注销时,将它标记为false。如果再次注销时遇到false就不对他进行注销处理。

曾经我遇到过几次异常,提示我的BroadcastReceiver多次被反注册,导致系统异常死掉。废了很长时间查看代码找原因。。

比如我之前常在finish方法中反注册广播,但finish方法有可能被多次调用,导致 BroadcastReceiver多次被反注册。

另外,需要注意一点,你用什么contex(上下文)注册的广播,则必须用它来反注册。

比如你调用getApplicationContext()注册,用getApplicationContext()删除。而不能直接unregisterReceiver(mFinishReceiver);和registerReceiver(mFinishReceiver, filter);有可能找不到。

另外关于BroadcastReceiver还涉及安全性问题,可参考:

http://blog.csdn.net/t12x3456/article/details/9256609

5. Broadcast的生命周期,是否可以在里面做耗时的操作?

一个进程如果正在执行BroadcastReceiver的 onReceive() 方法,就会被当做一个前台进程,不易被系统杀死。
当 onReceive() 执行完毕,BroadcastReceiver 就不再活跃,其所在进程会被系统当做一个空进程,随时有可能被系统杀死。

Broadcast的生命周期只有一个回调方法:void onReceive(Context curContext,Intent broadcastMsg)。当broadcast消息到达接收者时,Android会调用他的onReceive()方法,并且传递包含这个信息的intent对象。broadcast接收者在执行这个方法时,被认为是活动的。当onReceive()方法返回时,它停止的活动状态。

一个活动的广播接受者进程是不能被杀死的,但是当他所消耗的内存被别的进程需要时,一个非活动状态的进程可以被系统随时杀死。

这带来一个问题,相应一个广播消息是非常耗时的,因此,很多事情需要在一个独立的线程中执行,而不是在主线程里。如果onReceive()方法启动一个线程,那么整个进程包括刚启动的新线程,是非活动状态的,(除非进程里其他应用程序组件有活动的),所以有被系统销毁的危险。这个问题的解决方法是在onReceive()方法里启动一个服务然后处理一些事情,所以系统会知道在这个进程里仍然有处于活动状态的任务需要被处理。

接收广播时要对广播进行判空

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
@SuppressLint("NewApi") public class MainActivity extends Activity { SmsReceiver myReceiver; Button btn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn = (Button) findViewById(R.id.btn); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { test(); } }); } public void test(){ Cursor cursor = null; String defaultSmsApp = Telephony.Sms.getDefaultSmsPackage(this); Intent intent = new Intent(Sms.Intents.ACTION_CHANGE_DEFAULT); intent.putExtra(Sms.Intents.EXTRA_PACKAGE_NAME, this.getPackageName()); startActivity(intent); try { cursor = getContentResolver().query(Uri.parse("content://sms/inbox"), new String[] { "_id", "address", "read" }, "read = ? ", new String[] {"0" }, "date desc"); if (cursor != null) { ContentValues values = new ContentValues(); values.put("read", "1"); for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { Log.v("cky", "" + cursor.getInt(cursor.getColumnIndex("_id")) + " , " + cursor.getString(cursor.getColumnIndex("address"))); int res = getContentResolver().update(Uri.parse("content://sms/inbox"), values, "_id=?", new String[] { "" + cursor.getInt(cursor.getColumnIndex("_id")) }); Log.i("cky","geng xin = "+res); } } intent = new Intent(Sms.Intents.ACTION_CHANGE_DEFAULT); intent.putExtra(Sms.Intents.EXTRA_PACKAGE_NAME, defaultSmsApp); startActivity(intent); } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) { cursor.close(); cursor = null; } } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值