我的一位同行开发人员编写了intent service
来进行API调用,然后睡了2分钟。醒来后,它再次发送。
以下是代码:
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" />
手机处于活动状态时,此功能正常。但是,每当手机进入打盹模式时,它都无法唤醒。
使用WAKE permission
警报管理器解决此问题吗?
我刚刚获得了代码库,需要在今天解决这个问题。如果有人可以提供帮助,那就太棒了。
答案 0 :(得分:3)
正如documentation所说:
在打盹模式下,系统会尝试通过限制来节省电池电量 应用&#39;访问网络和CPU密集型服务。 它也会阻止 应用程序访问网络并推迟他们的工作,同步和 标准报警。
系统会定期退出Doze一段时间以便让应用程序使用 完成他们的延期活动。在此维护窗口期间, 系统运行所有待处理的同步,作业和警报,并允许应用程序 访问网络。
简而言之,在打盹模式下,系统暂停网络访问,忽略唤醒锁定,停止从传感器获取数据,将AlarmManager作业推迟到下一个打盹维护窗口(逐渐减少调用),还有WiFi扫描,JobScheduler作业和同步适配器无法运行。
setAndAllowWhileIdle()和setExactAndAllowWhileIdle()都不能每个应用每9(?)分钟多次触发警报。
前景服务似乎也参与了这个&#34; Doze Drama&#34;,至少在MarshMellow(M)中。
为了在这种情况下生存,需要至少重新审视大量应用程序。你能想象一个简单的MP3播放器在设备进入打盹模式时停止播放音乐吗?
当设备从电源上拔下并在桌面上放置约1小时左右时,甚至更早,当用户点击电源按钮关闭屏幕电源时,打盹模式会自动启动,但我认为这可能也取决于设备制造商。
我尝试了很多对策,其中一些非常有趣。
在测试结束时,我找到了一个可能的解决方案:
即使主机设备处于打盹模式,一种可能(也许是唯一)让您的应用运行的方式基本上是ForegroundService(即使是假的,也不做任何工作)全部)使用获得的another process {/ 3}}在partial WakeLock中投放。
您需要做的基本上是以下(您可以创建一个简单的项目来测试它):
记住!这会有效,但这只是一个起点,因为你必须小心使用&#34;副作用&#34;这种方法会产生:
1 - 电池耗尽:如果您,CPU将永远适用于您的应用 不要使用某种策略并让WakeLock始终处于活动状态。
2 - 即使在锁屏中,也会始终显示一个通知, 只需将其滑出即可删除此通知 将一直存在,直到您停止前台服务。
好的,让我们这样做。
<强> 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 强>
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中添加此权限:
<uses-permission android:name="android.permission.WAKE_LOCK" />
请勿忘记在<application>
标记中添加应用名称:
<application
....
android:name=".myApp"
....
最后将您的前台服务运行到另一个进程:
<service
android:name=".myAntiDozeService"
android:process=":MyAntiDozeProcessName">
</service>
一些笔记。
在上一个示例中,单击时创建了通知, 打开测试项目的ActivityMain活动。
Intent notificationIntent = new Intent(mContext, ActivityMain.class)
;
但你也可以使用另一种意图。
要进入打盹模式,设备必须安静并拔下电源插头 在调试时你无法测试它。首先调试您的应用, 检查一切是否正在运行然后停止,拔掉,重新启动 再次使用应用程序,让设备独立,安静地放在桌面上。
文档向simulate Doze
and StandBy modes建议的adb
命令可能也无法为您提供正确的结果
(我想,这取决于设备制造商,驱动程序,bla
BLA)。请在REAL行为中进行测试。
在我的第一次测试中,我使用AlarmManager和音频发生器每隔10分钟播放一次音调,以便了解我的应用仍处于活动状态。 它仍然在大约18个小时的时间内运行,每隔10分钟就用一声响亮的声音打断我的耳朵。 : - )
快乐的编码!
答案 1 :(得分:0)
我的一位同行开发人员编写了一个意图服务,进行API调用,然后睡2分钟。醒来后,它再次发送。
Only have a service running while it is actively delivering value to the user。坐着两分钟,观看时钟滴答,并没有积极地为用户提供价值。
使用具有WAKE权限的警报管理器会解决这个问题吗?
这取决于“解决这个问题”的含义。您可以使用AlarmManager
请求每两分钟获得一次控制权,以便您可以开展工作。当设备处于打盹模式时,您实际上不会每两分钟控制一次,而是每个维护窗口一次。