在onReceive()回调

时间:2018-02-25 10:39:18

标签: java android thread-safety broadcastreceiver android-broadcastreceiver

我正在阅读有关如何编程Android与USB配件通信的this page。其中一个步骤涉及注册BroadcastReceiver以获取用户的许可:

IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);

其中mUsbReceiver定义为:

private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (ACTION_USB_PERMISSION.equals(action)) {
            synchronized (this) {
                UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);

                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    if(accessory != null){
                        //call method to set up accessory communication
                    }
                }
                else {
                    Log.d(TAG, "permission denied for accessory " + accessory);
                }
            }
        }
    }
};

令我困惑的是为什么使用synchronized (this)?将在UI线程上调用onReceive()并将其调用。这段代码似乎没有触及其他线程可以访问的任何数据,除非对象accessory计数(并且页面上没有任何暗示它的内容)。

我在网上搜索过,似乎没有太多强调onReceive()中的线程安全性(毕竟它是由非常具体的线程调用的)。我错过了什么吗?

更新:我想强调我知道synchronized (this)的作用,因为下面的一些评论似乎暗示我不会。我不明白为什么在上面的代码片段中使用了它,这似乎是不必要的。

1 个答案:

答案 0 :(得分:0)

不会在UI线程上始终调用

onReceive()。如果BroadcastReceiver使用接受registerReceiver()参数的Handler scheduler重载进行注册,则会在一个线程上执行onReceive()回调,该处理程序已附加到该线程。来自docs

  

Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)

     

注册以接收意图广播,以在调度程序的上下文中运行。 scheduler 是一个标识将接收Intent的线程的处理程序。如果为null,则将使用该进程的主线程。

尽管如此,特别是在文档中概述的情况下,不需要将任何代码包装到synchronized块中,因为BroadcastReceiver是使用标准registerReceiver(BroadcastReceiver, IntentFilter)重载注册的,这是保证在UI线程上触发onReceive()回调。

我认为这只是一个展示代码,它演示了如何正确编写onReceive()实现,处理所有边缘情况。如果该文档的作者没有编写synchronized块我不知道,可以使onReceive()在UI线程以外的线程上执行。