为什么我无法收到 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;
}
}
}
这样我每次按onClick
为sendBroadcast(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 为什么会出现这个错误?
ACTION_POWER_CONNECTED
广播为系统广播。 LocalBroadcastManager
仅处理使用 LocalBroadcastManager
发送的广播,因此您注册的 Receiver 实例不会获得 ACTION_POWER_CONNECTED
广播。您需要在 Context
上注册您的 Receiver 实例,例如您的 Activity
.
清单中的<receiver>
元素静态注册接收器class,而不是任何现有的实例。 class 然后由系统根据需要实例化,并且这些实例中的 none 将设置 TextView
字段。如果您想从静态注册的 Receiver class 更新 Activity
,您需要使用其他机制;例如,Intent
s、LocalBroadcastManager
、一些其他事件总线等
我还要提到 ACTION_POWER_CONNECTED
广播不在 the list of implicit broadcast exemptions for Android 8.0 and above 上,所以如果你的 targetSdkVersion
是 26+,你不能用静态注册的接收器接收那个广播,开始用奥利奥。
我在学习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;
}
}
}
这样我每次按onClick
为sendBroadcast(View view)
的按钮时都能收到ACTION_MY_BRODACAST
广播。但是当我插入或拔出 USB 数据线时,什么也不会发生。然后我选择在AndroidManinfest.xml
:
<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 为什么会出现这个错误?
ACTION_POWER_CONNECTED
广播为系统广播。LocalBroadcastManager
仅处理使用LocalBroadcastManager
发送的广播,因此您注册的 Receiver 实例不会获得ACTION_POWER_CONNECTED
广播。您需要在Context
上注册您的 Receiver 实例,例如您的Activity
.清单中的
<receiver>
元素静态注册接收器class,而不是任何现有的实例。 class 然后由系统根据需要实例化,并且这些实例中的 none 将设置TextView
字段。如果您想从静态注册的 Receiver class 更新Activity
,您需要使用其他机制;例如,Intent
s、LocalBroadcastManager
、一些其他事件总线等
我还要提到 ACTION_POWER_CONNECTED
广播不在 the list of implicit broadcast exemptions for Android 8.0 and above 上,所以如果你的 targetSdkVersion
是 26+,你不能用静态注册的接收器接收那个广播,开始用奥利奥。