Android AlarmManager.setExactAndAllowWhileIdle()和WakefulBroadcastReceiver不适用于一些新的制造和低价格设备

Android AlarmManager.setExactAndAllowWhileIdle()和WakefulBroadcastReceiver不适用于一些新的制造和低价格设备

问题描述:

我认为这个问题很多时候在stackoverflow问,但仍然有这么多人努力解决它。Android AlarmManager.setExactAndAllowWhileIdle()和WakefulBroadcastReceiver不适用于一些新的制造和低价格设备

在我的android应用程序中,我必须唤醒设备每半小时才能获取当前位置并将其发送到服务器。为此,我用AlarmManagersetExactAndAllowWhileIdle()方法和WakefulBroadcastReceiver。它在三星,LG(Nexus),索尼,松下,联想,摩托罗拉,Micro max等几乎所有标准/流行设备上工作良好....但其他一些设备主要是中国设备不支持或不允许设备唤醒从打盹模式与setExactAndAllowWhileIdle()。我已经在leeco letV (Android OS 6.1)设备上测试过它,它不允许警报管理器在特定时间间隔内唤醒。

我的代码部分I已经提到如下:

UserTrackingReceiverIntentService.java 

public class UserTrackingReceiverIntentService extends IntentService { 

    public static final String TAG = "UserTrackingReceiverIntentService"; 
    Context context; 
    public UserTrackingReceiverIntentService() { 
     super("UserTrackingReceiverIntentService"); 
    } 

    @TargetApi(Build.VERSION_CODES.M) 
    @Override 
    protected void onHandleIntent(Intent intent) { 
     this.context = this; 

     if (!Util.isMyServiceRunning(LocationService.class, context)) { 
      context.startService(new Intent(context, LocationService.class)); 
     } 

     Calendar calendar = Calendar.getInstance(); 
     //********************************** SETTING NEXT ALARM ********************************************* 
      Intent intentWakeFullBroacastReceiver = new Intent(context, SimpleWakefulReceiver.class); 
      PendingIntent sender = PendingIntent.getBroadcast(context, 1001, intentWakeFullBroacastReceiver, 0); 
      AlarmManager alarmManager = (AlarmManager) context.getSystemService(context.ALARM_SERVICE); 

     if (calendar.get(Calendar.MINUTE) >= 0 && calendar.get(Calendar.MINUTE) < 30) { 
      calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY)); 
      calendar.set(Calendar.MINUTE, 30); 
      calendar.set(Calendar.SECOND, 0); 
     } else if (calendar.get(Calendar.MINUTE) >= 30) { 
      if (calendar.get(Calendar.HOUR_OF_DAY) == 23) { 
       calendar.set(Calendar.HOUR_OF_DAY, 0); 
       calendar.add(Calendar.DAY_OF_MONTH, 1); 
      } else { 
       calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) + 1); 
      } 
      calendar.set(Calendar.MINUTE, 0); 
      calendar.set(Calendar.SECOND, 0); 
     } else { 
      calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY)); 
      calendar.set(Calendar.MINUTE, 0); 
      calendar.set(Calendar.SECOND, 0); 
     } 

     //MARSHMALLOW OR ABOVE 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
      alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, 
        calendar.getTimeInMillis(), sender); 
     } 
     //LOLLIPOP 21 OR ABOVE 
     else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
      AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(calendar.getTimeInMillis(), sender); 
      alarmManager.setAlarmClock(alarmClockInfo, sender); 
     } 
     //KITKAT 19 OR ABOVE 
     else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 
      alarmManager.setExact(AlarmManager.RTC_WAKEUP, 
        calendar.getTimeInMillis(), sender); 
     } 
     //FOR BELOW KITKAT ALL DEVICES 
     else { 
      alarmManager.set(AlarmManager.RTC_WAKEUP, 
        calendar.getTimeInMillis(), sender); 
     } 


     Util.registerHeartbeatReceiver(context); 
     SimpleWakefulReceiver.completeWakefulIntent(intent); 
    } 
} 

每次上述服务设置一个报警,30分钟后,一旦它被调用。

public class SimpleWakefulReceiver extends WakefulBroadcastReceiver { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
     // This is the Intent to deliver to our service. 
     Calendar calendar = Calendar.getInstance(); 
     Intent service = new Intent(context, UserTrackingReceiverIntentService.class); 
     Date date = new Date(); 

     SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 
     String DateTime = sdf.format(date); 
     DateTime = Util.locatToUTC(DateTime); 
     service.putExtra("date", String.valueOf(DateTime)); 

     String latitude = Util.ReadSharePrefrence(context, "track_lat"); 
     String longitude = Util.ReadSharePrefrence(context, "track_lng"); 

     service.putExtra("lat", latitude); 
     service.putExtra("lon", longitude); 

     Log.i("SimpleWakefulReceiver", "Starting service @ " + calendar.get(Calendar.HOUR_OF_DAY) + " : " + calendar.get(Calendar.MINUTE) + " : " + calendar.get(Calendar.SECOND)); 

     // Start the service, keeping the device awake while it is launching. 
     startWakefulService(context, service); 
    } 
} 

正如我从leeco letV装置手动改变一些设置等设置>电池>对齐唤醒>禁用这两个选项。如果启用了电池,可以忽略强制从应用中唤醒。

我的问题:

  1. 什么在这类设备发生了什么?为什么他们不允许闹钟在特定时间间隔内触发?

  2. 在一些设备,如金立s加警报发射晚了2-3分钟......为什么?

  3. android.net.conn.CONNECTIVITY_CHANGE广播接收器监听网络连接变化.....当它不适用于某些设备,如金立s plus plus时,该怎么办?

  4. 各种制造商的电池优化设置有很多变化....是否可以伤害我们的应用程序的后台服务,如果是那么这是什么解决方案。

+0

你能看看我的问题在这里http://stackoverflow.com/q/41032943/6852390。如果可以,请帮助我 –

+0

例如,在华为设备上,您需要启用AutoStart,否则无法发送广播。在HuaweiAscend Mate 7上,有一个TelephonyManager,其中列出了所有应用的Auto Start选项。也许在你的一些测试设备上有一个类似的经理。 – Opiatefuchs

+0

@himCream我目前正在使用这个库检查https://github.com/evernote/android-job,希望它能帮助某种程度。让我们来看看。 – MKJParekh

嗨我在Xiomi phone.leeco测试时遇到同样的问题我没什么想法。 Xiomi手机有自己的操作系统是MIUI。当我们清除RAM时清除所有的应用程序执行一些应用程序注册在操作系统。像Whatsapp和Facebook一些其他着名的应用程序。

我试过服务,报警管理器和调度程序,但没有得到任何成功。

它们提供了一些手动指定方式来运行services.I已检查Leeco它使用Android操作系统。

解决方案MIUI 7.0 =>安全性=>自动启动=>选择您要在后台运行=>重启 重启设备要能够在后台运行的应用程序服务,如其他Android设备做后应用。

MIUI 4.0 settings

MIUI AutoStart Detailed Description

据我可以用服务尝试然后检查其是否工作或没有。

谢谢,希望你能从中得到一点帮助。

+0

我在Xiomi手机中发现了这个设置,但我不知道Leeco的设置是否相同..... Leeco手机是否具有这些设置? – himCream

+0

@himCream我也不确定。你可以尝试使用服务。它可能会帮助你。 – Saveen

+0

从这里看看https://blog.hypertrack.io/2016/12/01/scheduling-tasks-in-android-made-easy/ – Saveen

也许这些中国手机已禁用应用程序唤醒接收报警事件,以节省电池寿命。我知道,一些中国制造商如果早些时候关闭电池保护,就不会唤醒应用程序接收推送通知。因此,在应用程序再次手动打开之前,操作系统不会唤醒任何事件处理。

但是,这种行为可以改变。检查电源管理设置并相应更改以允许应用程序定期或在需要时唤醒。我认为它可能是受限模式或类似的东西。

+0

....你最近是正确的我已经检查了一个MI手机他们正在使用MIUI,我必须手动提供自动启动权限在后台运行我的应用程序.....但我已经看到WhatsApp和Facebook和其他品牌的应用程序已经在那里,没有手动输入他们进入自动运行权限.....他们正在做什么来添加应用程序的自动启动权限? – himCream

我同意你的意见。 但我认为你应该尝试一次JobScheduler。 你会发现官方文档 https://developer.android.com/reference/android/app/job/JobScheduler.html 我发现最好的例子 https://github.com/googlesamples/android-JobScheduler 我没有测试it.according你必须试试这个。

编辑

如果你想在6.0运行在休眠模式应用程序或更高版本,你要白名单应用程序 退房

https://www.bignerdranch.com/blog/diving-into-doze-mode-for-developers/

https://developer.android.com/training/monitoring-device-state/doze-standby.html

Imtiyaz

+0

谢谢你给我一个方法....我真的退出实施作业调度程序,但可以在Android OS 6和7中工作调度程序运行在打盹模式或深度打盹模式? – himCream

+0

@himCream我有更新我的答案。 –

+0

@Imtiyaz ...谢谢你的回答.....但我已经看到了上面两个链接,它们让我们对打瞌睡有了很好的理解。我已经使用方法setExactAndAllowWhileIdle()为marshmellow和以上.....但我的问题仍然在一些设备警报失踪......和在金立设备警报火灾晚2至3分钟比特定时间间隔.....请检查我的问题和上面的代码....如果你想我可以给你进一步的信息根据我的功能和代码.... – himCream

在我的android应用程序中,我必须每15分钟唤醒设备以获取当前位置并将其发送到服务器。 Application flow diagram 我已经测试了小蜜米5s(Android 6.0.1)。当我关闭应用程序,该应用程序就会用setExactAndAllowWhileIdle()不工作¯\_(ツ)_/¯

是的,它的正常工作在几乎所有标准睡觉:(AlarmManager /流行的设备,如三星,LG(的Nexus 5X),索尼,摩托罗拉,像素。 ..

我的解决办法

对于每种类型的构成要素的清单条目 - <activity><service><receiver>,和<provider> - 支持一个android:process属性,该属性可以指定一个过程,其中COMPONE nt应该运行。

你需要在你AndroidManifest.xml

像这样添加此字符串android:process=":service"

... 

<receiver 
    android:name="your.full.packagename.MyWakefulReceiver" 
    android:process=":service" 
    android:enabled="true"/> 

<service 
    android:name="your.full.packagename.MyLocationService" 
    android:process=":service"/> 

<service 
    android:name="your.full.packagename.MySendService" 
    android:process=":service" 
    android:exported="false" /> 

... 

我已经测试过的小蜜弥5S此解决方案。是工作 !!!

恕我直言,似乎每当用户退出应用程序的小蜜固件杀死的主要工艺...

+0

谢谢你以上答...小米,OPPO和vivo手机拥有自己的ROM,在这些设备中,一旦你从前台离开你的应用程序,它会杀死所有后台服务和应用程序。为了解决这个问题暂时我找到了一个解决方案--->你需要锁定你的应用程序在后台,我搜索了很多时间,但我发现了什么,如果你不想保持锁定,你有没有其他的解决方案在小米专用的背景应用程序,oppo和vivo .............. – himCream

+0

1)当我不使用'android:process =“:service”' 小米离开MainActivity后立即杀死我的AlarmManager。 2)当我使用'android:process =“:service”'如上图所示 小米在一段时间后杀死了我的AlarmManager。 “你需要在后台锁定你的应用程序”? @himCream你是什么意思? –

+0

“您需要在后台锁定您的应用”,这意味着在“最近的应用列表”中您必须锁定您的应用。像这样https://www.softwarert.com/lock-background-apps-xiaomi-redmi-phones/ ............... – himCream