【问题标题】:How to solve an IntentReceiverLeaked after pressing the backbutton按下后退按钮后如何解决 IntentReceiverLeaked
【发布时间】:2019-08-07 15:39:44
【问题描述】:

我在使用 WifiDirect 连接时遇到了 Android 6 的问题。直接连接 WIFI 并按下后退按钮到我的应用程序后。应用泄露了intentreceiver

public class WifiDirectController
        extends ServerController
        implements WifiP2pManager.ConnectionInfoListener,
                   WifiP2pManager.ChannelListener,
                   WiFiDirectBroadcastReceiver.WiFiDirectBroadcastListener,
                   WifiDirectServer.WifiDirectServerListener {
  private static final String TAG = "WP2P.Controller";

  private WifiP2pManager mManager;
  private WifiP2pManager.Channel mChannel;
  private WifiP2pDevice mDevice;

  private BroadcastReceiver mReceiver;

  private boolean isWifiP2pEnabled = false;
  private boolean isDiscovering = false;
  private boolean isConnected = false;
  private boolean retryChannel = false;
  //added by Frank
  private boolean isReceiverRegistered = false;

  private final IntentFilter mIntentFilter = new IntentFilter();

  private Handler mHandler;

  private WifiDirectServer serverThread = null;

  public WifiDirectController(ServerListener listener) {
    super(listener);

    //mManager = (WifiP2pManager) mListener.getSystemService(Context.WIFI_P2P_SERVICE);
    mManager = (WifiP2pManager) mListener.getApplicationContext().getSystemService(Context.WIFI_P2P_SERVICE);
    mChannel = mManager.initialize(listener.getApplicationContext(), mListener.getMainLooper(), this);

    //  Indicates a change in the Wi-Fi P2P status.
    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
    // Indicates the state of Wi-Fi P2P connectivity has changed.
    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
    // Indicates this device's details have changed.
    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
    // Indicates that discovery has started or stopped
    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);

    mHandler = new Handler();
  }

  @Override
  public void onStart()
  {
    Log.d(TAG, "onStart() called");

  }

  @Override
  public void onResume() {
    Log.d(TAG, "onResume() called");
    Log.e(TAG, "FRANK onResume() called");
    mReceiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this);
    if (!isReceiverRegistered) {
      mListener.registerReceiver(mReceiver, mIntentFilter);
      isReceiverRegistered = true;
    }
  }

  @Override
  public void onPause()
  {
    Log.d(TAG, "onPause() called");
    mListener.unregisterReceiver(mReceiver);
    isReceiverRegistered = false;
    stopDiscovery();
  }

  @Override
  public void onStop()
  {
    Log.d(TAG, "onStop() called");
    //added frank
    if (isReceiverRegistered) {
        mListener.unregisterReceiver(mReceiver);
        isReceiverRegistered = false;
    }
    //
    cancelDisconnect();
    stopServer();
  }

  @Override
  public void restart()
  {
    Log.d(TAG, "restart() called");
    Log.e(TAG, "FRANK onRestart() called");
    cancelDisconnect();
    stopServer();
    startDiscovery();
  }

  private boolean startServer()
  {
    Log.d(TAG, " = startServer() called");
    Log.e(TAG, "FRANK startServer() called");
    this.serverThread = new WifiDirectServer(this);
    this.serverThread.start();
    return true;
  }

ActivityThread: Activity com.android.settings.SubSettings 泄露了最初在这里注册的 IntentReceiver android.net.wifi.WifiManager$1@61ae52a。您是否错过了对 unregisterReceiver() 的调用? android.app.IntentReceiverLeaked: Activity com.android.settings.SubSettings 已经泄露了最初在这里注册的 IntentReceiver android.net.wifi.WifiManager$1@61ae52a。您是否错过了对 unregisterReceiver() 的调用?

【问题讨论】:

    标签: android android-activity memory-leaks wifi-direct


    【解决方案1】:

    你必须使用一个方法来检查接收者是否注册,这是因为当你按下返回按钮时,活动被破坏,所以变量恢复到原来的值,因此在 Resume 方法中变量 isReceiverRegistered总是假的,它会再次尝试注册接收者。

    • 您可以在 OnPause 方法中取消注册接收器,而不是 OnStop 方法。
    • 或者您可以存储变量覆盖的值 onSaveInstanceState 方法和在 onRestoreInstanceState 中恢复 方法。
    • 或者您可以使用 ViewModel 来保存变量的值。
    • 或者您可以尝试使用一个类来管理您的接收器。 slinden77 在这个thread中给出了一个可能的解决方案
        public class ReceiverManager {
    
            private static List<BroadcastReceiver> receivers = new ArrayList<BroadcastReceiver>();  
            private static ReceiverManager ref;
            private Context context;
    
            private ReceiverManager(Context context){
                this.context = context;
            }
    
            public static synchronized ReceiverManager init(Context context) {      
                if (ref == null) ref = new ReceiverManager(context);
                return ref;
            }
    
            public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter intentFilter){
                receivers.add(receiver);
                Intent intent = context.registerReceiver(receiver, intentFilter);
                Log.i(getClass().getSimpleName(), "registered receiver: "+receiver+"  with filter: "+intentFilter);
                Log.i(getClass().getSimpleName(), "receiver Intent: "+intent);
                return intent;
            }
    
            public boolean isReceiverRegistered(BroadcastReceiver receiver){
                boolean registered = receivers.contains(receiver);
                Log.i(getClass().getSimpleName(), "is receiver "+receiver+" registered? "+registered);
                return registered;
            }
    
            public void unregisterReceiver(BroadcastReceiver receiver){
                if (isReceiverRegistered(receiver)){
                    receivers.remove(receiver);
                    context.unregisterReceiver(receiver);
                    Log.i(getClass().getSimpleName(), "unregistered receiver: "+receiver);
                }
            }
        }
    

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 2011-01-22
      • 2019-08-28
      • 2018-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-19
      • 1970-01-01
      相关资源
      最近更新 更多