Search code examples
androidbroadcastreceiverobserver-pattern

Android 'Unable to add window — token null is not for an application' exception


I am trying to implement observer pattern for change in network. I have a general idea of how this works, and need some help with fine tuning because while attempting to inform the user that they have lost connection I am receiving the following error:

Android 'Unable to add window — token null is not for an application' exception

Here is my setup. First I have a ConnectionReceiver class that extends BroadcastReceiver.

public class ConnectionReceiver extends BroadcastReceiver {
    private static final String TAG = ConnectionReceiver.class.getSimpleName();

    private final List<NetworkStatusObserver> mObserverList = new ArrayList<NetworkStatusObserver>();
    private static boolean isNetworkConnected = true;

    @Override
    public void onReceive(Context context, Intent intent) {
        Logger.i(TAG, "onReceive() broadcast");
        boolean disconnected = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
        boolean isNetworkConnectedCurrent;

        if (disconnected) {
            isNetworkConnectedCurrent = false;
        } else {
            NetworkInfo networkInfo;

            if (Build.VERSION.SDK_INT < 17) {
                networkInfo = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
            } else {
                ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                int networkType = intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 0);
                networkInfo = cm.getNetworkInfo(networkType);
            }

            if (networkInfo != null && networkInfo.isConnected()) {
                isNetworkConnectedCurrent = true;
            } else {
                isNetworkConnectedCurrent = false;
            }
        }

        if (isNetworkConnectedCurrent != isNetworkConnected) {
            isNetworkConnected = isNetworkConnectedCurrent;
            Logger.d(TAG, "NetworkStatus.onReceive - isNetworkConnected: " + isNetworkConnected);
            notifyObservers(isNetworkConnected);
        }

 if (isNetworkConnected) {
            // already connected
        } else {
            Utils.showDialog(context, "", context.getString(R.string.default_network_error_message), false,
                    context.getString(R.string.retry), new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    // handle click action
                }
            });
        }
    }

    /**
     * Lets all {@link NetworkStatusObserver}s know if the device is connected to a network.
     *
     * @param isNetworkConnectedCurrent
     */
    private void notifyObservers(Boolean isNetworkConnectedCurrent) {
        for (NetworkStatusObserver networkStatusObserver : mObserverList) {
            networkStatusObserver.notifyConnectionChange(isNetworkConnectedCurrent);
        }
    }

    public void addObserver(NetworkStatusObserver observer) {
        mObserverList.add(observer);
    }

    public void removeObserver(NetworkStatusObserver observer) {
        mObserverList.remove(observer);
    }

    /**
     * Interface for monitoring network status change
     */
    public interface NetworkStatusObserver {
        void notifyConnectionChange(boolean isConnected);
    }

The dialog method I am calling in Utils.java is

public static void showDialog(Context context, String title, String message, boolean cancelable, String buttonLabel, DialogInterface.OnClickListener buttonListener) {
    if (isDialogShowing()) {
        return;
    }

    AlertDialog.Builder builder = new AlertDialog.Builder(context);
    builder.setTitle(title)
            .setMessage(message)
            .setCancelable(cancelable)
            .setNeutralButton(buttonLabel, buttonListener);
    mDialog = builder.create();
    mDialog.show(); // <--- the error comes on this line
}

I registered this receiver in my manifest

<receiver android:name=".network.ConnectionReceiver">
    <intent-filter >
        <action android:name="android.net.wifi.STATE_CHANGE"/>
    </intent-filter>
</receiver>

The issue is that I am passing the application context to the dialog and not the Activity dialog. So then I removed the section of code that calls the dialog in the broadcast receiver and tried to add it to my MainActivity.java class. I implemented NetworkStatusObserver, but in doing that I receive the error that

notifyConnectionChange cannot be resolved

I am not sure how the observer is suppose to happen. By the way, MainActivity extends FragmentActivity which makes it difficult for me to add/remove my observer in onPause() and onResume() because I am not sure what to put in replace of "this". What should "this" be instead?

// Note: connectionStatusReceiver is an object of ConnectionReceiver
unregisterReceiver(connectionStatusReceiver );
connectionStatusReceiver.removeObserver(this);

and in my onResume() I am trying to add

connectionStatusReceiver.addObserver(this);
registerReceiver(connectionStatusReceiver , new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));

Solution

  • Pass YourActivity.this object instead Context in showDialog()

    like

    public static void showDialog(Acitivity activity, String title, String message, boolean cancelable, String buttonLabel, DialogInterface.OnClickListener buttonListener) {
        if (isDialogShowing()) {
            return;
        }
    
        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder.setTitle(title)
                .setMessage(message)
                .setCancelable(cancelable)
                .setNeutralButton(buttonLabel, buttonListener);
        mDialog = builder.create();
        mDialog.show(); // <--- the error comes on this line
    }
    

    You can see this Link for Reference: