1

I'm having problems with android 6, with my WifiDirect connection. After connecting WIFI direct and pushing the backbutton to my app. The app leaks the 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 has leaked IntentReceiver android.net.wifi.WifiManager$1@61ae52a that was originally registered here. Are you missing a call to unregisterReceiver()? android.app.IntentReceiverLeaked: Activity com.android.settings.SubSettings has leaked IntentReceiver android.net.wifi.WifiManager$1@61ae52a that was originally registered here. Are you missing a call to unregisterReceiver()?

1 Answers1

1

You must use a method to check if the receiver is registered, this is because when you press back button, the activity is destroyed, so the variables come back to it's original values, for that reason in the Resume method the variable isReceiverRegistered is always false, and it tries to register the receiver again.

  • You could unregister the receiver in the OnPause method instead of OnStop method.
  • Or you can store the value of the variable overriding onSaveInstanceState method and recoverit in onRestoreInstanceState method.
  • Or you can use a ViewModel to persist the variable's values.
  • Or you can try using a class to manage your receivers. slinden77 gave a possible solution to this, in this 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);
            }
        }
    }

I hope it helps you