Keep broadcast receiver running after application is closed
Asked Answered
B

7

32

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");
        }
     }
}
Boggs answered 29/5, 2013 at 21:40 Comment(3)
You might want to create a serviceXylia
But what about receiving events?Boggs
Do you really need to monitor screen on/off events? The reason that they force you to register a receiver not in the manifest is that they don't want people to always be monitoring these events and slowing down the device.Violone
X
30

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);
 }
}
Xylia answered 29/5, 2013 at 22:5 Comment(5)
so when the app is force closed the service is still running ? I didn't think so.Jamilla
I don't think this is compatible with Android "O"Jamilla
Is it possible to register a broadcast receiver from a foreground service, which runs even after app is closed ??Pleistocene
this doesn't work when the application is removed from recent screenTsarina
@Bhavesh, Do you mean broadcast receiver will not work when the app is closed ?Pleistocene
H
17

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;
Horseradish answered 18/9, 2018 at 2:14 Comment(4)
Actually when the app's service is running it is considered as running. And this particular receiver ACTION_SCREEN_ON is one which can not receive events when the app does not running even if it is declared in manifest and it must be created in permanently running service. So your answer is good addition to accepted answer but not a complete answer itself.Boggs
Tried in Xiaomi Redmi 6A. App is checked as "autostart" but the service keep killing when I close my app. My service works perfectly in "common" devices, but it cant work in xiaomi devicesExercitation
At this time they changed their mechanism. I will update my answer for suite your needs.Horseradish
Can you please explain the code/solution which you have provided? Really difficult to understand why exactly dialog is shown and how things will work.Allo
O
2

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

Opportuna answered 27/1, 2014 at 22:38 Comment(5)
SCREEN_ON and SCREEN_OFF can't be declared in the Manifest file.Desireedesiri
@Desireedesiri : why SCREEN_ON and SCREEN_OFF can not be declared in AndroidManifest? Can you explainPoppas
@Poppas It is just how they chose to implement it. I don't remember the justification behind this.Desireedesiri
@Poppas because its on the documentation :)Snare
I am declaring it in the manifest but that does not work if I do not dynamically create the receiver as well. I am trying to receive ACTION_POWER_CONNECTED, ACTION_POWER_DISCONNECTED.Synapsis
C
2

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/

Callender answered 12/5, 2016 at 12:19 Comment(0)
A
2

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.

Admonition answered 3/2, 2018 at 10:54 Comment(0)
V
1

You could start a service that is running in the foreground. That's the only way to ensure (mostly) that your app will get the events. There is still a chance that your foreground service could get killed in times of crazy memory pressure from the OS (so it's not foolproof). If you start a service in the foreground, the user will see a persistent notification to know that it is always running, though.

So the moral of the story is, do you really need to monitor the screen off/on events at all times? The reason that they force you to register a receiver not in the manifest is that they don't want people to always be monitoring these events and slowing down the device. What are you trying to accomplish?

Violone answered 29/5, 2013 at 22:16 Comment(0)
P
0

The best way I found is the Foreground Services. I registered my BroadcastReceiver from my Service only under the onStartCommand() as I want my service needs to run always, I returned START_STICKY

This way, my broadcast receiver survives even after terminating the app from stack.

Used below code in my service

    @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.i("rht", "Received start id " + startId + ": " + intent);
    
            String input = intent.getStringExtra("inputExtra");
            createNotificationChannel();
            Intent notificationIntent = new Intent(this, MainActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(this,
                    0, notificationIntent, 0);
            Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                    .setContentTitle("Foreground Service")
                    .setContentText(input)
                    .setSmallIcon(R.drawable.ic_launcher_background)
                    .setContentIntent(pendingIntent)
                    .build();
            startForeground(1, notification);
}

This is how I started my service

Intent serviceIntent = new Intent(this, SpeechServiceForeground.class);
ContextCompat.startForegroundService(this, serviceIntent);
Prana answered 19/2, 2021 at 2:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.