When singleton Application object is sometimes null

I currently have a class Application

that I expect to see throughout the entire lifecycle of the application.

MyApplication.java

public class MyApplication extends android.support.multidex.MultiDexApplication  {
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }

    public static MyApplication instance() {
        return me;
    }

    @SuppressLint("NewApi")
    @Override
    public void onCreate(){
        super.onCreate();

        me = this;

        registerNetworkCallback(MyApplication.instance());

      

However, in a very rare situation, it MyApplication.instance()

returns zero at the link change broadcast receiver.

ConnectivityChangeBroadcastReceiver.java

public class ConnectivityChangeBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // MyApplication.instance() is returning null?!?!

    }

      

How to register a network callback

public static void registerNetworkCallback(final Context context) {
    /*
    Apps targeting Android 7.0 (API level 24) do not receive CONNECTIVITY_ACTION broadcasts if
    they register to receive them in their manifest. Apps that are running can still listen for
    CONNECTIVITY_CHANGE on their main thread by registering a BroadcastReceiver with
    Context.registerReceiver().
     */
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
        return;
    }

    try {
        if (!connectivityChangeBroadcastReceiverDisabled) {
            // Although ConnectivityChangeBroadcastReceiver will not be triggered, just to be extra
            // caution...
            PackageManager pm = context.getPackageManager();
            ComponentName compName = new ComponentName(context, ConnectivityChangeBroadcastReceiver.class);
            pm.setComponentEnabledSetting(
                    compName,
                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                    PackageManager.DONT_KILL_APP);
            connectivityChangeBroadcastReceiverDisabled = true;
        }

        if (networkCallback == null) {
            networkCallback = new ConnectivityManager.NetworkCallback() {
                /**
                 * @param network
                 */
                @Override
                public void onAvailable(Network network) {
                    Handler handler = new Handler(Looper.getMainLooper());
                    Runnable runnable = new Runnable() {
                        @Override
                        public void run() {
                            ConnectivityChangeBroadcastReceiver.onReceive(context);
                        }
                    };
                    handler.post(runnable);
                }
            };
        }

        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkRequest.Builder builder = new NetworkRequest.Builder();
        NetworkRequest networkRequest = builder.build();
        connectivityManager.registerNetworkCallback(networkRequest, networkCallback);
    } catch (Exception e) {
        Log.e(TAG, "", e);
    }
}

      


Do you have an idea why there is a rare possibility, when ConnectivityChangeBroadcastReceiver

run in onReceive

, singleton MyApplication.instance()

returns null?

+3


source to share


1 answer


I understand the high probability that I am leaking the application context, making the OS have no chance of garbage collection

Malfunctioning application context!

registerNetworkCallback(MyApplication.instance());

public static void registerNetworkCallback(final Context context) {
            ...
            networkCallback = new ConnectivityManager.NetworkCallback() {
                /**
                 * @param network
                 */
                @Override
                public void onAvailable(Network network) {
                    Handler handler = new Handler(Looper.getMainLooper());
                    Runnable runnable = new Runnable() {
                        @Override
                        public void run() {
                            ConnectivityChangeBroadcastReceiver.onReceive(context);

      



No application context leak!

registerNetworkCallback(MyApplication.instance());

// No more final on context, to avoid it is being used in anonymous class.
public static void registerNetworkCallback(Context context) {
            ...
            networkCallback = new ConnectivityManager.NetworkCallback() {
                /**
                 * @param network
                 */
                @Override
                public void onAvailable(Network network) {
                    Handler handler = new Handler(Looper.getMainLooper());
                    Runnable runnable = new Runnable() {
                        @Override
                        public void run() {
                            ConnectivityChangeBroadcastReceiver.onReceive(MyApplication.instance());

      

0


source







All Articles