应用程序关闭后保持广播接收器运行

时间:2013-05-29 21:40:08

标签: java android broadcastreceiver

我需要在应用程序启动后始终保持广播接收器的运行。

以下是在应用程序中注册此接收器的代码

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

接收器的代码

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");
        }
     }
}

6 个答案:

答案 0 :(得分:27)

您可以使用服务

在主应用中启动/停止服务

Intent service = new Intent(context, MyService.class);
context.startService(service);
...
Intent service = new Intent(context, MyService.class);
context.stopService(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);
 }
}

答案 1 :(得分:7)

我认为可接受的答案不是实际答案。我将解释问题所在。我认为您是在 Huawie,Oppo,Vivo,Xiomi,asus ....... 或某些设备上测试您的应用程序。使用这些设备,如果我们关闭应用程序,它们还将关闭我们的广播接收器。这样就可以解决问题。(要检查是否使用带有像素关系的模拟器)。我将解释如何解决此问题.``

  • 我们会将我们的应用添加到受保护的应用列表中。操作系统仅允许他们继续广播接收器活动。(将此数组声明复制到您的代码中)

    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"))};
    
  • 将这些代码放入您的onCreate方法中。在这里,我使用共享首选项仅在应用程序首次打开时对其进行检查。

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;

答案 2 :(得分:4)

如果您在清单中声明BroadcastReceiver,它将始终处于活动状态并即使应用程序已关闭/停止也会被调用

答案 3 :(得分:1)

您可以启动在前台运行的服务。这是确保(大部分)您的应用程序将获得事件的唯一方法。在操作系统出现内存压力的情况下,您的前台服务仍有可能被杀死(因此并非万无一失)。如果您在前台启动服务,用户将看到持续通知,知道它始终在运行。

故事的寓意是,你真的需要随时监控屏幕的开/关事件吗?他们强迫您注册不在清单中的接收器的原因是他们不希望人们总是监视这些事件并减慢设备速度。你想要完成什么?

答案 4 :(得分:1)

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.

答案 5 :(得分:0)

我发现的最好方法是 Foreground Services。我只在 onStartCommand() 下从我的服务注册了我的广播接收器,因为我希望我的服务需要始终运行,我返回了 START_STICKY

这样,即使从堆栈中终止应用程序,我的广播接收器仍然存在。

在我的服务中使用以下代码

    @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);
}

这就是我开始服务的方式

Intent serviceIntent = new Intent(this, SpeechServiceForeground.class);
ContextCompat.startForegroundService(this, serviceIntent);