为什么我无法收到 POWER_CONNECTED 操作?

Wht can't I receive POWER_CONNECTED action?

我在学习Android。我使用以下代码在 MainActivity.java 中动态注册我的自定义广播接收器 CustomBroadcastreceiver

package com.example.bob.broadcastcounterback;

import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private PackageManager packageManager;
    private ComponentName componentName;
    private CustomBroadcastreceiver customReceiver;
    private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        packageManager = getPackageManager();
        componentName = new ComponentName(this,CustomBroadcastreceiver.class);

        textView = findViewById(R.id.countText);

        customReceiver = new CustomBroadcastreceiver(textView);

        IntentFilter mIntentFilter = new IntentFilter();
        mIntentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
        mIntentFilter.addAction("com.example.bob.broadcastcounter");

        LocalBroadcastManager.getInstance(this).
                registerReceiver(customReceiver,mIntentFilter);

//        LocalBroadcastManager.getInstance(this).registerReceiver(customReceiver,new IntentFilter(Intent.ACTION_POWER_CONNECTED));

    }

    @Override
    protected void onStart() {
        super.onStart();

//        packageManager.setComponentEnabledSetting(
//                componentName,
//                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
//                PackageManager.DONT_KILL_APP);
    }

    @Override
    protected void onStop() {
        super.onStop();
//        packageManager.setComponentEnabledSetting(
//                componentName,
//                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
//                PackageManager.DONT_KILL_APP);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("DESTORY CALLED:","destroy");
        LocalBroadcastManager.getInstance(this).unregisterReceiver(customReceiver);
    }

    public void sendBroadcast(View view) {
        Intent intent = new Intent("com.example.bob.broadcastcounter");

        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }
}

CustomBroadcastreceiver.java:

package com.example.bob.broadcastcounterback;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.TextView;

public class CustomBroadcastreceiver extends BroadcastReceiver {

    private TextView mTextView;
    private int count = 0;

    private static final String ACTION_MY_BRODACAST = "com.example.bob.broadcastcounter";

    public CustomBroadcastreceiver(){
        super();
    }

    public CustomBroadcastreceiver(TextView mTextView){
        this();
        this.mTextView = mTextView;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        String intentString = intent.getAction();


        switch (intentString){
            case Intent.ACTION_POWER_CONNECTED:
                Log.d("BroadcastReceiver:",mTextView.toString());
                mTextView.setText("power connected!");
//                mTextView.setText(++count);
                break;
            case ACTION_MY_BRODACAST :
                mTextView.setText("Custombroadcast Received!");
                break;
        }
    }
}

这样我每次按onClicksendBroadcast(View view)的按钮时都能收到ACTION_MY_BRODACAST广播。但是当我插入或拔出 USB 数据线时,什么也不会发生。然后我选择在AndroidManinfest.xml:

中注册broadcastreceiver
<receiver
        android:name=".CustomBroadcastreceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
        </intent-filter>
    </receiver>

这次我不知道发生了什么:每次我插入充电线时,应用程序都会立即崩溃并且 returns。我什至在 Android Studio 中看不到 logcat。为了知道到底发生了什么,我将 Thread.sleep(5000) 添加到 onReceive() 方法中:

@Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        String intentString = intent.getAction();

        try {
            Thread.sleep(5000);
        }catch (InterruptedException e){
            Log.e("Broadcastcounterback:",e.toString());
        }



        switch (intentString){
            case Intent.ACTION_POWER_CONNECTED:
                Log.d("BroadcastReceiver:",mTextView.toString());
                mTextView.setText("power connected!");
//                mTextView.setText(++count);
                break;
            case ACTION_MY_BRODACAST :
                mTextView.setText("Custombroadcast Received!");
                break;
        }
    }

这次当我点击发送自定义广播的按钮时,mTextView 将在 5 秒中断后显示 Custombroadcast Received!。当我插入充电线时,5 秒后出现错误:

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.view.View.toString()' on a null object reference
                                                                                    at com.example.bob.broadcastcounterback.CustomBroadcastreceiver.onReceive(CustomBroadcastreceiver.java:41)

这表明当我收到 POWER_CONNECTED 动作时 mTextView 为空。为什么?我用 customReceiver = new CustomBroadcastreceiver(textView); 实例化了 customReceiver,因此 mTextView 不应为空,实际上 ACTION_MY_BRODACAST 操作将触发 mTextView 显示正确的文本而不会出现任何错误。 最后,我的两个问题:

1 我们只能通过广播接收器静态注册来接收 POWER_CONNECTED 动作?

2 为什么会出现这个错误?

  1. ACTION_POWER_CONNECTED广播为系统广播。 LocalBroadcastManager 仅处理使用 LocalBroadcastManager 发送的广播,因此您注册的 Receiver 实例不会获得 ACTION_POWER_CONNECTED 广播。您需要在 Context 上注册您的 Receiver 实例,例如您的 Activity.

  2. 清单中的<receiver>元素静态注册接收器class,而不是任何现有的实例。 class 然后由系统根据需要实例化,并且这些实例中的 none 将设置 TextView 字段。如果您想从静态注册的 Receiver class 更新 Activity,您需要使用其他机制;例如,Intents、LocalBroadcastManager、一些其他事件总线等


我还要提到 ACTION_POWER_CONNECTED 广播不在 the list of implicit broadcast exemptions for Android 8.0 and above 上,所以如果你的 targetSdkVersion 是 26+,你不能用静态注册的接收器接收那个广播,开始用奥利奥。