user7157256
user7157256

Reputation:

Activity has leaked IntentReceiver Error

before marking this post as closed or duplicate i want to say that i have done all the things that are mentioned on similar posts but none of them worked.

I have 2 receivers which i get data from. So i want to register the receivers when the activity starts and unregister them when the activity is not visible.

My Code:

public class MainActivity extends AppCompatActivity {

    private CheckNetworkStatusReceiver checkNetworkStatusReceiver;
    private CheckBatteryStatusReceiver checkBatteryStatusReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        checkConnection();
    }
    public void checkConnection() {
        if(!ConnectionManager.isNetworkAvailable(MainActivity.this)){
           ConnectionManager.wifiSettingsDialog(MainActivity.this).show();
        }else{
            registerReceivers();
        }
    }

    public void registerReceivers() {
        checkNetworkStatusReceiver = new CheckNetworkStatusReceiver();
        checkBatteryStatusReceiver = new CheckBatteryStatusReceiver();
        registerReceiver(checkNetworkStatusReceiver, new IntentFilter(Constants.INTENT_FILTER_CONNECTIVITY_CHANGE));
        registerReceiver(checkBatteryStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        try{
            unregisterReceiver(checkNetworkStatusReceiver);
            unregisterReceiver(checkBatteryStatusReceiver);
        }catch (Exception e){
            e.printStackTrace();
        }

    }


    @Override
    protected void onResume() {
        registerReceivers();
        super.onResume();
    }

    @Override
    protected void onRestart() {
        registerReceivers();
        super.onRestart();
    }

    @Override
    protected void onStop() {
        super.onStop();

        try{
            unregisterReceiver(checkNetworkStatusReceiver);
            unregisterReceiver(checkBatteryStatusReceiver);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

The receiver code:

public class CheckNetworkStatusReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent != null){
            Log.e("Action ",intent.getAction());
            if(intent.getAction().equalsIgnoreCase(Constants.INTENT_FILTER_CONNECTIVITY_CHANGE)) {
                if (!ConnectionManager.isNetworkAvailable(context)){
                    Toast.makeText(context, R.string.no_internet, Toast.LENGTH_SHORT).show();
                }
                if (MobileDataManager.slowInternetConnection(context)){
                    Toast.makeText(context, R.string.slow_internet_delay, Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
}

and the battery receiver:

public class CheckBatteryStatusReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent != null){
            int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
            if (level <= 15){
                Toast.makeText(context, "Batter level " + level + "% is very low. Please connect to a charger.", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

i get the error on the registerReceivers() method. Any ideas?

Upvotes: 2

Views: 9345

Answers (2)

David Wasser
David Wasser

Reputation: 95626

You register the receivers in onCreate() and then again in onResume(). This will leak the receivers that you registered in onCreate(), because you overwrite the variables you are using to hold references to them every time registerReceivers() is called.

This is not very robust code. You don't need to create new instances of the BroadcastReceiver every time. What you should do is to create one instance of each BroadcastReceiver in onCreate(). Then declare a boolean member variable in your class called receiversRegistered. In registerReceivers() you should check this boolean. If it is true, the receivers are already registered and you should do nothing. If not, register the receivers and then set the boolean to true. When you unregister the receivers, set the boolean to false.


EDIT: Here it is all done for you:

public class MainActivity extends AppCompatActivity {

    private CheckNetworkStatusReceiver checkNetworkStatusReceiver;
    private CheckBatteryStatusReceiver checkBatteryStatusReceiver;
    private boolean receiversRegistered;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        checkNetworkStatusReceiver = new CheckNetworkStatusReceiver();
        checkBatteryStatusReceiver = new CheckBatteryStatusReceiver();
        checkConnection();
    }
    public void checkConnection() {
        if(!ConnectionManager.isNetworkAvailable(MainActivity.this)){
           ConnectionManager.wifiSettingsDialog(MainActivity.this).show();
        }else{
            registerReceivers();
        }
    }

    public void registerReceivers() {
        // Only register if not already registered
        if (!receiversRegistered) {
            registerReceiver(checkNetworkStatusReceiver, new IntentFilter(Constants.INTENT_FILTER_CONNECTIVITY_CHANGE));
            registerReceiver(checkBatteryStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
            receiversRegistered = true;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (receiversRegistered) {
            unregisterReceiver(checkNetworkStatusReceiver);
            unregisterReceiver(checkBatteryStatusReceiver);
        }

    }

    @Override
    protected void onResume() {
        registerReceivers();
        super.onResume();
    }

    @Override
    protected void onRestart() {
        registerReceivers();
        super.onRestart();
    }

    @Override
    protected void onStop() {
        super.onStop();

        if (receiversRegistered) {
            unregisterReceiver(checkNetworkStatusReceiver);
            unregisterReceiver(checkBatteryStatusReceiver);
            receiversRegistered = false;
        }
    }
}

Upvotes: 7

parohy
parohy

Reputation: 2180

Move the unregisterReceiver inside onPause not in onDestroy.

When your activity is moved in background onDestroy is not called. The activity is only paused. onDestroy is called when the app is closed manually or by the system.

(onPause is called before onDestroy in above situation)

Upvotes: 0

Related Questions