当singleton Application对象有时为null时

时间:2017-05-21 09:16:29

标签: android

目前,我有一个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());

但是,在非常罕见的情况下,MyApplication.instance()在连接更改广播接收器中返回null。

ConnectivityChangeBroadcastReceiver.java

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

    }

我如何注册网络回调

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);
    }
}

您是否知道为什么在ConnectivityChangeBroadcastReceiver中触发onReceive时,单身MyApplication.instance()返回null时会出现罕见的可能性?

1 个答案:

答案 0 :(得分:0)

我意识到很高的可能性,就是我泄漏了应用程序上下文,这使得OS没有机会垃圾收集它

应用程序上下文泄漏!

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);

不再有应用程序上下文泄漏!

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());