Keep broadcast receiver running after application is closed

38,085

Solution 1

You can use a service

In main app start/stop the service

Intent service = new Intent(context, MyService.class);
context.startService(service);
...
Intent service = new Intent(context, MyService.class);
context.stopService(service);

service

public class MyService extends Service
{
 private static BroadcastReceiver m_ScreenOffReceiver;

 @Override
 public IBinder onBind(Intent arg0)
 {
  return null;
 }

 @Override
 public void onCreate()
 {
  registerScreenOffReceiver();
 }

 @Override
 public void onDestroy()
 {
  unregisterReceiver(m_ScreenOffReceiver);
  m_ScreenOffReceiver = null;
 }

 private void registerScreenOffReceiver()
 {
  m_ScreenOffReceiver = new BroadcastReceiver()
  {
   @Override
   public void onReceive(Context context, Intent intent)
   {
     Log.d(TAG, "ACTION_SCREEN_OFF");
     // do something, e.g. send Intent to main app
   }
  };
  IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
  registerReceiver(m_ScreenOffReceiver, filter);
 }
}

Solution 2

Accepted answer is not an actual answer i think. I will explain what the issue. I think you are testing your app in the Huawie, Oppo, Vivo, Xiomi,asus....... or some devices. With that devices if we close the application they will also close our broadcast receivers. So thats the problem.(To check that use a with pixel nexus emulator). I will explain how to resolve this.``

  • we would add our app to the protected app list. OS only allow to them to continue broadcast receiver activities.(Copy this array declaration to your code)

    private static final Intent[] POWERMANAGER_INTENTS = {
        new Intent().setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")),
        new Intent().setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")),
        new Intent().setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")),
        new Intent().setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity")),
        new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")),
        new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.startupapp.StartupAppListActivity")),
        new Intent().setComponent(new ComponentName("com.oppo.safe", "com.oppo.safe.permission.startup.StartupAppListActivity")),
        new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity")),
        new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.BgStartUpManager")),
        new Intent().setComponent(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")),
        new Intent().setComponent(new ComponentName("com.samsung.android.lool", "com.samsung.android.sm.ui.battery.BatteryActivity")),
        new Intent().setComponent(new ComponentName("com.htc.pitroad", "com.htc.pitroad.landingpage.activity.LandingPageActivity")),
        new Intent().setComponent(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.MainActivity"))};
    
  • Put these code to your onCreate Method. Here i used shared preference for check it only first time of the app open.

`

final SharedPreferences.Editor pref =    getSharedPreferences("allow_notify", MODE_PRIVATE).edit();    pref.apply(); final SharedPreferences sp =    getSharedPreferences("allow_notify", MODE_PRIVATE)`;


    if(!sp.getBoolean("protected",false)) {
        for (final Intent intent : POWERMANAGER_INTENTS)
            if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {

            AlertDialog.Builder builder  = new AlertDialog.Builder(this);
            builder.setTitle("Alert Title").setMessage("Alert Body")
                    .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            startActivity(intent);
                            sp.edit().putBoolean("protected",true).apply();

                        }
                    })
                    .setCancelable(false)
                    .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                        }
                    })
                    .create().show();
            break;

Solution 3

If you declare BroadcastReceiver in the Manifest, it will always be active and be called even if the application is closed/stopped

Solution 4

Be careful if you are using Android 4.4.x as there is a bug which kills background services when closing the app. I was testing my app in Android 4.4.2 and I had the same problem. Here there is a detailed explanation:

http://www.androidpolice.com/2014/03/07/bug-watch-stopping-apps-on-android-4-4-2-can-silently-kill-related-background-services-a-fix-is-on-the-way/

Solution 5

You cannot receive some broadcast events through components declared in manifest.

These events are

  • ACTION_BATTERY_CHANGED
  • ACTION_CONFIGURATION_CHANGED
  • ACTION_SCREEN_OFF (You are playing with this event)
  • ACTION_SCREEN_ON (You are playing with this event)
  • ACTION_TIME_TICK

Reference https://developer.android.com/reference/android/content/Intent.html#ACTION_SCREEN_ON

So in your specific events, you will have to create a Service & you will have to register your event explicitly in service onCreate() with with Context.registerReceiver().

For other events, entry in manifest is sufficient.

Share:
38,085
Sergey  Pekar
Author by

Sergey Pekar

Updated on February 19, 2021

Comments

  • Sergey  Pekar
    Sergey Pekar about 3 years

    I need to keep broadcast receiver running all the time after app has been started.

    Here is the code that registers this receiver in the application

        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        BroadcastReceiver mReceiver = new ScreenEventsReceiver();
        registerReceiver(mReceiver, filter);
    

    And code for receiver

    public class ScreenEventsReceiver extends BroadcastReceiver {
         public static boolean wasScreenOn = true;
    
         @Override
         public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
                wasScreenOn = false;
                Log.d("ScreenEventReceiver", "ON");
            } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
                wasScreenOn = true;
                Log.d("ScreenEventReceiver", "ON");
            }
         }
    }