android - leakcanary stacktrace 难以理解

标签 android leakcanary

我有来自泄漏金丝雀的以下堆栈跟踪,我不确定我的 Activity 是如何泄漏的

static LGCobtextHelper.mLGContext
references LGContext.mContext
references
ResourcesContextWrapperFactory$WebViewContextWrapper.mBase
references
com.*.*.activity.MyActivity.networkMonitor
references
com.*.*.NetworkMonitor.mPendingResult
references
android.app.LoadedApk$ReceiverDispatcher$Args.this$0
references
LoadedAok$ReceiverDispathcer.mContext
leaks MyActivity instance

MyActivity 扩展了 BaseActivity,它注册了 onResume() 并注销了 onPause(),所以不确定哪个泄露 Activity

网络监控.java

     public class NetworkMonitor extends BroadcastReceiver {
    private final WebSocketClient webSocketClient;
    private final ArmingHelper armingHelper;
    private final ShutdownManager shutdownManager;
    private final CameraThumbnailCache cameraThumbnailCache;
    private final CameraAccessManager cameraAccessManager;
    private final JoustLogger joustLogger;

    private Activity registeredActivity;
    private String currentNetworkName;
    private List<NetworkStatusChangeListener> networkChangeListeners;

    public interface NetworkStatusChangeListener {
        void onNetworkUp();
        void onNetworkDown();
    }

    public NetworkMonitor(WebSocketClient webSocketClient, ArmingHelper armingHelper, ShutdownManager shutdownManager, CameraThumbnailCache cameraThumbnailCache, CameraAccessManager cameraAccessManager, JoustLogger joustLogger) {
        this.webSocketClient = webSocketClient;
        this.armingHelper = armingHelper;
        this.shutdownManager = shutdownManager;
        this.cameraThumbnailCache = cameraThumbnailCache;
        this.cameraAccessManager = cameraAccessManager;
        this.joustLogger = joustLogger;
        networkChangeListeners = new ArrayList<>();
    }

    // Activities *must* call this method in onResume() in order for
    // the app to watch for network changes
    public void startListeningForNetworkChanges(Activity registeringActivity) {
        if (!(registeringActivity instanceof NetworkStatusChangeListener)) {
            throw new IllegalArgumentException("Registering Activity must implement NetworkStatusChangeListener");
        }

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        intentFilter.addAction(GlobalConstants.ANDROID_NET_WIFI_WIFI_STATE_CHANGED);
        registeringActivity.registerReceiver(this, intentFilter);
        this.registeredActivity = registeringActivity;
        registerListenerForNetworkChanges((NetworkStatusChangeListener)registeringActivity);
    }

    // Activities *must* call this method in onPause() in order to properly
    // unregister the receiver that was set in onResume()
    public void stopListeningForNetworkChanges(Activity registeringActivity) {
        registeringActivity.unregisterReceiver(this);
        unregisterListenerForNetworkChanges((NetworkStatusChangeListener)registeringActivity);
        registeredActivity = null;
    }

    // Fragments can use this method to register for Network change updates, call in onResume()
    public void registerListenerForNetworkChanges(NetworkStatusChangeListener listener) {
        networkChangeListeners.add(listener);
    }

    // Fragments need to unregister in onPause()
    public void unregisterListenerForNetworkChanges(NetworkStatusChangeListener listener) {
        networkChangeListeners.remove(listener);
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        checkNetworkConnection();
    }

    public void checkNetworkConnection() {
        if (registeredActivity != null) {
            final ConnectivityManager connectivityManager = (ConnectivityManager) registeredActivity.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            if (networkInfo != null && networkInfo.isConnectedOrConnecting()) {
                String newNetworkName = networkInfo.getTypeName();
                if (currentNetworkName == null || !currentNetworkName.equals(newNetworkName)) {
                    Timber.d("Network(%s) Connected", newNetworkName);
                    // Our network was down, but now it's up.  Validate the Websocket
                    currentNetworkName = newNetworkName;
                    cameraThumbnailCache.clearInternalURLPreferences();
                    webSocketClient.reopenWebsocketIfPossible();
                    cameraAccessManager.onNetworkUp();
                    if (ActivityBehaviorHelper.needsSecurityCountdown(registeredActivity)) {
                        armingHelper.startTimerIfReady();
                    }
                    for (NetworkStatusChangeListener listener : networkChangeListeners) {
                        listener.onNetworkUp();
                    }
                    joustLogger.onNetworkUp();
                }
            } else {
                Timber.w("Network Down");
                currentNetworkName = null;
                cameraAccessManager.onNetworkDown();
                joustLogger.onNetworkDown();
                shutdownManager.onNetworkDown();
                for (NetworkStatusChangeListener listener : networkChangeListeners) {
                    listener.onNetworkDown();
                }
            }
        }
    }
}


BaseActivity.java

   @Override
    protected void onResume() {
        super.onResume();
        networkMonitor.startListeningForNetworkChanges(this);
    }

    @Override
    protected void onPause() {
        networkMonitor.stopListeningForNetworkChanges(this);
        super.onPause();
    }

最佳答案

看起来您可能不需要在该 NetworkMonitor 类中保留对 Activity 的引用。这可能是您的内存泄漏的根源 - Activity 引用可能在 Activity 被销毁后被保留。看起来您可以将上下文作为参数传递给需要它的方法。

此外,对于此处使用 Activity 上下文的一些地方,例如 context.getSystemService(Context.CONNECTIVITY_SERVICE),您可以改用 Application 上下文,并且可能完全避免需要 Activity 引用。

关于android - leakcanary stacktrace 难以理解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37148889/

相关文章:

javascript - Android 下的 Firefox/Chrome 在键入字母时不会触发 OnKeyPress、onKeyDown、onKeyUp 事件

android - 获取随机图像

android - shouldOverrideUrl 是如何调用的

java - 通过 Intent 和以编程方式意味着什么?

android - LeakCanary 发现 Android WebView 内存泄漏

android - MapView v2 保持上下文

Android uper.android.view.inflate 异常

android - 泄漏金丝雀2 : Does one manually have to watch objects?

leakcanary - LeakActivity 泄漏显示在 Leak Canary 上

android - SharedElement 和自定义 EnterTransition 导致内存泄漏