zoukankan      html  css  js  c++  java
  • 关于Android8.0 静态注册广播 行为变更的说明。

    Andorid 8.0 对广播的使用做了变更。

    当广播接收器使用静态注册方式使用时,除了一些例外,这个接收器接收不到隐式广播。 注意这个“隐式”是重点。

    看了网上几篇文章,对这个变更理解有误。错误的理解是:8.0后,广播接收器使用静态注册,是无法使用的。
    实时并非如此。

    先看一个例子:

    首先,定义一个简单的广播接收器:

    public class MyReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,context.toString(),Toast.LENGTH_SHORT).show();
        }
    }

    它对接收到广播的行为就是打印一句话。

    第二,我们将他注册到Manifest文件中。

            <receiver android:name=".broadcast.MyReceiver">
                <intent-filter>
                    <action android:name="com.demo.recriver"/>
                </intent-filter>
            </receiver>

    最后,在Activity中发送一个广播,intent通过设置Action为com.demo.recriver的形式发送隐式广播。

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Intent intent = Intent intent = new Intent("com.demo.recriver");//隐式intent,发送隐式广播
            sendBroadcast(intent);
        }
    }

    运行这个demo,发现在8.0以下的手机上,会有Toast显示,8.0以上的手机不会弹出,说明没有接收到广播。

    原因在于这个广播 是“隐式” 发送的,8.0中,静态注册的广播接收者无法接受 隐式 广播。

    为了解决这个问题,有两个方法:

    1 在Activity或其他组件中动态注册广播

    2 发送显示广播

    对于1 ,如果想广播让接收者工作,必须要在某个Activity或者其他组件中调用registerReceiver()进行注册,在onDestroy()时还要反注册,代码稍显复杂,而且静态注册的广播接收者仍处于不可用的状态。不合理。

    而后一种方法 ,因为sendBroaccast是自己主动发送的,明显知道要哪个broadcastReceiver来进行处理,直接发送显示广播即可。


    具体的代码如下,将MainActivity做修改:

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Intent intent = new Intent();
            intent.setComponent(new ComponentName(MainActivity.this,MyReceiver.class));//显示指定组件名称
            sendBroadcast(intent);
        }
    }

    实际上,这种写法与更常见的以下写法相同:

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Intent intent = new Intent(MainActivity.this,MyReceiver.class);//显示指定组件名
            sendBroadcast(intent);
        }
    }

    运行,发现可以弹出Toast,静态注册的BroadcastReceiver接收到了广播。证明静态注册是可以接收到广播的。

    顺便插一句:

    Intent指定action, 这个Intent则为隐式Intent,使用它发送的广播则为隐式广播。隐式广播接收者是通过IntentFilter去查找的。
    Intent指定了组件名称,这个Intent为显式Intent,用他发送的广播为显式广播。广播接收者直接就是指定的组件名称对应的广播接收者。

    猜测显式Intent不使用IntentFilter去查找组件(Activtiy,Service,BroadcastReceiver),这点读者有兴趣可以验证是否正确。

    再来看一下Intent的setComponent()方法:

    Intent设置了组件名称(比如 new Intent(MainActivity.this,MyReceiver.class);)则通过IntentFilter匹配所需要的action,data,type,category信息会被忽略。

    如果刚才的例子做如下改动:

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Intent intent = new Intent();
            intent.setAction("com.abcdefg.hijklmn");//指定action--不存在的action
            intent.setComponent(new ComponentName(MainActivity.this,MyReceiver.class));//同时显式指定组件名
            sendBroadcast(intent);
        }
    }

    同时指定了隐式的action 以及显式的组件名称,action是一个不存在的action。这时仍可以接收到广播。
    虽然通过action不可能匹配到一个广播接收者,但显示设置了组件,action就被忽略了。

    扯远了。回到最初的那个话题。8.0以后,静态注册的广播接受者是可以接收到广播的,只要广播是通过显示方式发送的。

  • 相关阅读:
    LiteFlow 按照规则配置进行复杂流转
    ImageCombiner 服务端合图
    forest HTTP调用API框架
    smart-doc API文档生成工具
    YAML语法和用法
    拓展mybatisPlus 支持批量插入
    ModbusRTU控制SV660P说明
    .NET RulesEngine(规则引擎)
    Win10自动更新有效强制永久关闭
    Redis 到底是怎么实现“附近的人”这个功能的?
  • 原文地址:https://www.cnblogs.com/senior-engineer/p/11237518.html
Copyright © 2011-2022 走看看