I have extended a Broadcastreceiver so that my app knows whenever the online state has been changed. The thing is: whenever the online state changes, my broadcastreceiver seems to get reconstructed. Because I add a listener on a later moment than the constructor, my listener is empty and I get a NullPointerException:
02-07 11:11:45.804: E/AndroidRuntime(21416): FATAL EXCEPTION: main
02-07 11:11:45.804: E/AndroidRuntime(21416): java.lang.RuntimeException: Unable to start receiver nl.raakict.android.dnd.util.NetworkStateReceiver: java.lang.NullPointerException
02-07 11:11:45.804: E/AndroidRuntime(21416): at android.app.ActivityThread.handleReceiver(ActivityThread.java:2699)
02-07 11:11:45.804: E/AndroidRuntime(21416): at android.app.ActivityThread.access$1500(ActivityThread.java:162)
02-07 11:11:45.804: E/AndroidRuntime(21416): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1453)
02-07 11:11:45.804: E/AndroidRuntime(21416): at android.os.Handler.dispatchMessage(Handler.java:99)
02-07 11:11:45.804: E/AndroidRuntime(21416): at android.os.Looper.loop(Looper.java:158)
02-07 11:11:45.804: E/AndroidRuntime(21416): at android.app.ActivityThread.main(ActivityThread.java:5751)
02-07 11:11:45.804: E/AndroidRuntime(21416): at java.lang.reflect.Method.invokeNative(Native Method)
02-07 11:11:45.804: E/AndroidRuntime(21416): at java.lang.reflect.Method.invoke(Method.java:511)
02-07 11:11:45.804: E/AndroidRuntime(21416): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1083)
02-07 11:11:45.804: E/AndroidRuntime(21416): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:850)
02-07 11:11:45.804: E/AndroidRuntime(21416): at dalvik.system.NativeStart.main(Native Method)
02-07 11:11:45.804: E/AndroidRuntime(21416): Caused by: java.lang.NullPointerException
02-07 11:11:45.804: E/AndroidRuntime(21416): at nl.raakict.android.dnd.util.NetworkStateReceiver.onReceive(NetworkStateReceiver.java:38)
02-07 11:11:45.804: E/AndroidRuntime(21416): at android.app.ActivityThread.handleReceiver(ActivityThread.java:2687)
02-07 11:11:45.804: E/AndroidRuntime(21416): ... 10 more
My custom broadcastreceiver looks like this:
package nl.raakict.android.dnd.util;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
public class NetworkStateReceiver extends BroadcastReceiver{
private Listener mListener = null;
private static NetworkStateReceiver _instance;
public static NetworkStateReceiver getInstance()
{
if (_instance == null)
{
_instance = new NetworkStateReceiver();
}
return _instance;
}
public NetworkStateReceiver(){
}
@Override
public void onReceive(Context context, Intent intent) {
Log.d("app","Network connectivity change");
if(intent.getExtras()!=null) {
NetworkInfo ni=(NetworkInfo) intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO);
if(ni!=null && ni.getState()==NetworkInfo.State.CONNECTED) {
Log.i("app","Network "+ni.getTypeName()+" connected");
mListener.onStateChange(true);
}
}
if(intent.getExtras().getBoolean(ConnectivityManager.EXTRA_NO_CONNECTIVITY,Boolean.FALSE)) {
Log.d("app","There's no network connectivity");
mListener.onStateChange(false);
}
}
public interface Listener {
public void onStateChange(boolean state);
}
public void registerListener (Listener listener) {
mListener = listener;
}
public boolean isOnline(Context context) {
ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
}
return false;
}
}
and my manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="nl.raakict.android.dnd"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="nl.raakict.android.dnd.HomeActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/app_name"
android:theme="@style/FullscreenTheme" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="nl.raakict.android.dnd.util.NetworkStateReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
</application>
</manifest>
And this is my listener class:
public class RequestHandler implements NetworkStateReceiver.Listener {
private static RequestHandler _instance;
private NetworkStateReceiver networkStateReveiver;
private ArrayList<CustomJsonRequest> delayedRequestQueue;
private boolean currentlyOnline;
private Context applicationContext;
public static RequestHandler getInstance(Context applicationContext)
{
if (_instance == null)
{
_instance = new RequestHandler(applicationContext);
}
return _instance;
}
private RequestHandler(Context applicationContext){
delayedRequestQueue= new ArrayList<CustomJsonRequest>();
this.applicationContext = applicationContext;
networkStateReveiver = NetworkStateReceiver.getInstance();
networkStateReveiver.registerListener(this);
currentlyOnline = networkStateReveiver.isOnline(applicationContext);
}
@Override
public void onStateChange(boolean online) {
// TODO Auto-generated method stub
currentlyOnline = online;
if(online){
sendRequestQueue();
}
}
public void newPostRequest(CustomJsonRequest request) {
delayedRequestQueue.add(request);
if(currentlyOnline)
sendRequestQueue();
}
public void sendRequestQueue(){
//code logic here
}
}
What did I do wrong?
The problem is that when Network State is being done, Android will create your NetworkStateReceiver class instance, call its onReceive
and then destroy your receiver instance. So that is why your listener is always null, if you want to inform some other components of network change then you should for example send local broadcast in your application.
You might alswo register local BroadcastReceiver:
"Register your BroadcastReceiver programmatically": http://www.grokkingandroid.com/android-tutorial-broadcastreceiver/