简体   繁体   中英

Adding a custom listener inside a broadcast receiver gives NPE in Android

I have been stuck with a problem here.I am trying to listen to connectivity changes by implementing a broadcast receiver.Also I have initialised a custom listener within the broadcast receiver so as to communicate to the activity about the connectivity changes to show a Crouton Toast.The code for the various classes as below :

The broadcast receiver :

public class NetworkStateReceiver extends BroadcastReceiver {

    private NetworkStateListener networkStateListener;

    public NetworkStateReceiver() {
    }

    public NetworkStateReceiver(NetworkStateListener networkStateListener) {
        this.networkStateListener = networkStateListener;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("test", "Network connectivity change ::: " + this.networkStateListener);
        if (intent.getExtras() != null) {

            NetworkInfo ni = (NetworkInfo) intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO);
            if (ni != null && ni.getState() == NetworkInfo.State.CONNECTED) {
                Log.i("test", "Network " + ni.getTypeName() + " connected");
                networkStateListener.onConnected();
            }
        }
        if (intent.getExtras().getBoolean(ConnectivityManager.EXTRA_NO_CONNECTIVITY, Boolean.FALSE)) {
            Log.d("test", "There's no network connectivity");
            networkStateListener.onDisconnected();
        }
    }
}

The custom listener interface :

public interface NetworkStateListener {

    public void onConnected();

    public void onDisconnected();
}

The activity in which the listener is implemented and receiver is registered for connectivity changes :

    public class HomeActivity extends AppCompatActivity implements NetworkStateListener {
     private NetworkStateReceiver mReceiver;
     private LocalBroadcastManager mBroadcastManager;
    @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_home);
      mBroadcastManager =    LocalBroadcastManager.getInstance(HomeActivity.this);
        mReceiver = new NetworkStateReceiver(HomeActivity.this);
    }

@Override
    protected void onResume() {
        super.onResume();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(android.net.ConnectivityManager.CONNECTIVITY_ACTION);
        mBroadcastManager.registerReceiver(mReceiver, intentFilter);
    }

    @Override
    protected void onPause() {
        super.onPause();
        mBroadcastManager.unregisterReceiver(mReceiver);
    }
    }

And this is the manifest entry :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test">

<uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />

 <application
        android:name=".TestApplication"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"

<receiver android:name=".shared.receivers.NetworkStateReceiver">
            <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

I have no idea why the networkstateListener is not getting initialised.It gives a null pointer denoting that NetWorkStateListener may not be initialised.Can someone please help me out with this ? I have achieved this in the past, but with a custom broadcast and not with these kind of system broadcasts.

The CONNECTIVITY_CHANGE broadcast is sent by the system. This means a couple of things for your current setup.

  1. The instance of your BroadcastReceiver that you're registering with LocalBroadcastManager will never receive that broadcast, as LocalBroadcastManager only handles broadcasts originating from within your app.

  2. Registering your Receiver class in the manifest means that the system will instantiate a new instance of the Receiver to handle each broadcast. Since those instances will not have been passed an instance of your Activity as a listener, networkStateListener will be null in onReceive() , which is most likely where your current NullPointerException is coming from.

Depending on what your desired behavior is, you have a few options to choose from.

If you just want to be notified of connectivity changes while the Activity is running:

  1. Register an instance of the Receiver with the Context#registerReceiver() method instead, and remove the <receiver> entry from the manifest. If you make NetworkStateReceiver an inner class of HomeActivity , you won't need the interface.

  2. Use LocalBroadcastManager to communicate between NetworkStateReceiver and your Activity , instead of your listener interface . You could use an extra on the Intent to indicate connectivity state, or alternatively use different actions to distinguish.

  3. Use some other event bus implementation to communicate between the Receiver and the Activity .

If you want to be notified of changes even when your app isn't running:

  1. Start your Activity from the Receiver with an extra attached to the Intent to indicate connectivity state. This could also handle the case of your Activity already running, if you set the Activity 's launchMode to singleTask or singleTop , and override its onNewIntent() method.

In any case, passing your Activity as a listener to your BroadcastReceiver isn't really necessary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM