意图服务无法在打ze模式下工作 [英] Intent Service not working in doze mode

查看:95
本文介绍了意图服务无法在打ze模式下工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的一位对等开发人员编写了intent service,该API进行API调用,然后休眠2分钟.醒来后,它会再次发送.

One of my peer developer has written an intent service that makes an API call and then sleeps for 2 mins. After waking up, it sends again.

下面是代码:

public class GpsTrackingService extends IntentService {

....

@Override
    protected void onHandleIntent(Intent intent) {
      do{
        try{
          //make API call here

           //then go to sleep for 2 mins
          TimeUnit.SECONDS.sleep(120);
       
        } catch(InterruptedException ex){
            ex.printStackTrace();
        }
      } while (preferences.shouldSendGps()); //till the user can send gps.

    }

....

}


Manifest

<service android:name=".commons.GpsTrackingService" />

当电话处于活动状态时,此方法工作正常.但是,无论何时手机进入打ze模式,它都无法唤醒.

This is working fine when the phone is active. However, whenever the phone goes into doze mode it fails to wake.

将警报管理器与WAKE permission一起使用可以解决此问题吗?

Will using alarm manager with WAKE permission solve this?

我刚刚有了代码库,需要在今天内解决此问题.如果有人可以帮助,那就太好了.

I have just got the code base and need to fix this within today. It'll be great if someone can help.

推荐答案

作为

在打ze模式下,系统尝试通过限制 应用访问网络和CPU密集型服务的权限. 它还可以防止 应用访问网络并推迟其工作,同步和 标准警报.

In Doze mode, the system attempts to conserve battery by restricting apps' access to network and CPU-intensive services. It also prevents apps from accessing the network and defers their jobs, syncs, and standard alarms.

系统会暂时退出Doze短暂时间以允许应用 完成他们的延期活动.在此维护时段内, 系统会运行所有待处理的同步,作业和警报,并允许应用 访问网络.

Periodically, the system exits Doze for a brief time to let apps complete their deferred activities. During this maintenance window, the system runs all pending syncs, jobs, and alarms, and lets apps access the network.

简而言之,在打mode"模式下,系统会暂停网络访问,忽略唤醒锁,停止从传感器获取数据,将AlarmManager作业推迟到下一个打ze"维护窗口(其频率逐渐降低),以及WiFi扫描,JobScheduler作业和同步适配器不运行.

每个应用程序每9(?)分钟内setAndAllowWhileIdle()和setExactAndAllowWhileIdle()都不会发出警报.

Neither setAndAllowWhileIdle() nor setExactAndAllowWhileIdle() can fire alarms more than once per 9 (?) minutes, per app.

看来,至少在MarshMellow(M)中,前台服务也参与了此打ze剧".

And it seems that the Foreground Services are also involved into this "Doze Drama", at least in MarshMellow (M).

要在这种情况下生存,至少需要重新整理大量的应用程序.您能想象一个简单的mp3播放器在设备进入打ze模式时停止播放音乐吗?

To survive in this situation, tons of applications need to be at least rewiewed. Can you imagine a simple mp3 player which stops playing music when the device enters in Doze Mode?

当设备从电源上拔下电源并留在桌子上约1小时左右时,打mode模式会自动启动,甚至在用户单击电源按钮关闭屏幕电源时更早,但我认为这可能还要取决于设备制造商.

Doze mode starts automatically, when the device is unplugged from the power supply and left on the table for about 1 hour or so, or even earlier when the user clicks the power button to power down the screen, but I think this could depend by the device manufacturer too.

我尝试了许多对策,其中一些真的很搞笑.

I tried a lot of countermeasures, some of them really hilarious.

在测试结束时,我找到了可能的解决方案:

即使主机设备处于打ze模式,运行应用程序的一种可能(也是唯一的)方法基本上是使用

One possible (and maybe the only) way to have your app running even when the host device is in Doze mode, is basically to have a ForegroundService (even a fake one, doing no jobs at all) running in another process with an acquired partial WakeLock.

基本上,您需要做的是(您可以创建一个简单的项目对其进行测试):

What you need to do is basically the following (you could create a simple project to test it):

  • 1-在新项目中,创建一个扩展Application(myApp)的新类,或使用 新项目的主要活动.
  • 2-在myApp的onCreate()中启动服务(myAntiDozeService)
  • 3-在myAntiDozeService onStartCommand()中,创建通知 需要将该服务作为前台服务启动,请启动 具有startForeground(id,notification)的服务并获取 部分WakeLock.
  • 1 - In your new project, create a new class which extends Application (myApp), or use the main activity of the new project.
  • 2 - In myApp onCreate() start a Service (myAntiDozeService)
  • 3 - In myAntiDozeService onStartCommand(), create the Notification needed to start the service as a foreground service, start the service with startForeground(id, notification) and acquire the partial WakeLock.

记住!这将起作用,但这只是一个起点,因为您必须谨慎使用此方法将产生的副作用":

REMEMBER! This will work, but it is just a starting point, because you have to be careful with the "Side Effects" this approach will generate:

  • 1-电池电量耗尽:如果您持续使用该CPU,则该CPU将永远为您的应用工作 不要使用某种策略,并保持WakeLock始终处于活动状态.

  • 1 - Battery drain: The CPU will work for your app forever if you don't use some strategy and leave the WakeLock always active.

2-即使在锁定屏幕中,也会始终显示一条通知, 而只需将其刷掉就无法删除该通知, 将一直存在,直到您停止前台服务为止.

2 - One notification will be always shown, even in the lockscreen, and this notification cannot be removed by simply swiping it out, it will be always there until you'll stop the foreground service.

好,我们开始吧.

myApp.java

myApp.java

    public class myApp extends Application {
    private static final String STARTFOREGROUND_ACTION = "STARTFOREGROUND_ACTION";
    private static final String STOPFOREGROUND_ACTION = "STOPFOREGROUND_ACTION";

        @Override
        public void onCreate() {

            super.onCreate();            

            // start foreground service
            startForeService();
    }

    private void stopForeService() {
        Intent service = new Intent(this, myAntiDozeService.class);
        service.setAction(STOPFOREGROUND_ACTION);
        stopService(service);
    }

    private void startForeService(){
        Intent service = new Intent(this, myAntiDozeService.class);
        service.setAction(STARTFOREGROUND_ACTION);
        startService(service);
    }

    @Override
    public void onTerminate() {
        stopForeService();
        super.onTerminate();
    }
}

myAntiDozeService.java

myAntiDozeService.java

public class myAntiDozeService extends Service {

    private static final String TAG = myAntiDozeService.class.getName();
    private static boolean is_service_running = false;
    private Context mContext;
    private PowerManager.WakeLock mWakeLock;
    private static final int NOTIFICATION_ID = 12345678;
    private static final String STARTFOREGROUND_ACTION = "STARTFOREGROUND_ACTION";
    private static final String STOPFOREGROUND_ACTION = "STOPFOREGROUND_ACTION";

    @Override
    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        if (!is_service_running && STARTFOREGROUND_ACTION.equals(intent.getAction())) {
            Log.i(TAG, "Received Start Foreground Intent ");
            showNotification();
            is_service_running = true;
            acquireWakeLock();

        } else if (is_service_running && STOPFOREGROUND_ACTION.equals(intent.getAction())) {
            Log.i(TAG, "Received Stop Foreground Intent");
            is_service_running = false; 
            stopForeground(true);
            stopSelf();
        }

        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        releaseWakeLock();
        super.onDestroy();
    }

    private void showNotification(){

        Intent notificationIntent = new Intent(mContext, ActivityMain.class);
        notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, notificationIntent, 0);

        Notification notification = new NotificationCompat.Builder(mContext)
                .setContentTitle("myApp")
                .setTicker("myApp")
                .setContentText("Application is running")
                .setSmallIcon(R.drawable.ic_launcher)
                .setContentIntent(pendingIntent)
                .build();

        // starts this service as foreground
        startForeground(NOTIFICATION_ID, notification);
    }

    public void acquireWakeLock() {
        final PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        releaseWakeLock();
        //Acquire new wake lock
        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG+"PARTIAL_WAKE_LOCK");
        mWakeLock.acquire();
    }

    public void releaseWakeLock() {
        if (mWakeLock != null && mWakeLock.isHeld()) {
            mWakeLock.release();
            mWakeLock = null;
        }
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

AndroidManifest.xml更改.

AndroidManifest.xml changes.

在AndroidManifest.xml中添加此权限:

In the AndroidManifest.xml add this permission:

<uses-permission android:name="android.permission.WAKE_LOCK" />

别忘了在<application>标签中添加应用的名称:

Don't forget to add the name of your app in the <application> tag:

<application
        ....
        android:name=".myApp"
        ....

最后将正在运行的前台服务添加到另一个进程中:

And finally add your foreground service running into another process:

   <service
        android:name=".myAntiDozeService"
        android:process=":MyAntiDozeProcessName">
    </service>


一些注意事项.

  • 在上一个示例中,创建通知时,单击该通知, 打开测试项目的ActivityMain活动.

  • In the previous example, the notification created, when clicked, opens the ActivityMain activity of your test project.

Intent notificationIntent = new Intent(mContext, ActivityMain.class);

但是您也可以使用另一种意图.

but you can use another kind of intent too.

要进入打ze模式,设备必须安静且未插电,因此 您在调试时无法对其进行测试.首先调试您的应用, 检查一切是否正在运行,然后停止它,拔出插头,重新启动 再次使用该应用,然后将设备放置在自己的桌子上,保持安静.

To enter in Doze mode, the device has to be quiet and unplugged, so you can't test it while you are debugging. Debug your app first, check that everything is running then stop it, unplug, restart the app again and leave the device alone and quiet on your desk.

文档建议的adb命令用于

The adb commands suggested by the documentation to simulate Doze and StandBy modes could and could not give you the right results (it depends, I suppose, by the device manufacturer, drivers, bla bla). Please make your tests in the REAL behaviour.

在我的第一个测试中,我使用AlarmManager和声音发生器每10分钟播放一次声音,只是为了了解我的应用程序仍处于活动状态. 而且它仍然运行约18个小时,每隔10分钟就会用响亮的声音折断我的耳朵. :-)

In my first test, I used an AlarmManager and a tone generator to play a tone every 10 minutes just to understand that my app was still active. And it is still running from about 18 hours, breaking my ears with a loud tone exactly every 10 minutes. :-)

祝您编程愉快!

这篇关于意图服务无法在打ze模式下工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆