27

我认为这个问题被问了很多次,stackoverflow但仍然有很多人在努力解决它。

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

我在下面提到的代码部分:

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. 在某些设备中,例如 Gionee 的 plus 警报延迟 2-3 分钟...为什么?

  3. android.net.conn.CONNECTIVITY_CHANGE广播接收器在网络连接发生变化时收听......当它在某些设备(如 Gionee s plus)中不工作时该怎么办?

  4. 不同制造商的电池优化设置有很多变化......如果是这样的话,它会损害我们应用程序的后台服务吗?然后是什么解决方案。

4

4 回答 4

3

在我的 android 应用程序中,我必须每 15 分钟唤醒一次设备以获取当前位置并将其发送到服务器。 应用流程图 我已经在小米 5s (Android 6.0.1) 上测试过了。当我关闭应用程序时,应用程序进入睡眠状态:(AlarmManagersetExactAndAllowWhileIdle()工作¯\_(ツ)_/¯

是的,它在三星、LG (Nexus 5X)、索尼、摩托罗拉、Pixel 等几乎所有标准/流行设备上都能正常工作...

我的解决方案

<activity>每种类型的组件元素( 、<service><receiver>和)的清单条目都<provider>支持一个android:process属性,该属性可以指定该组件应在其中运行的进程。

您需要android:process=":service"在您的AndroidManifest.xml

像这样:

... 

<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 上测试过这个解决方案。这是工作 !!!

恕我直言,小米固件似乎会在用户退出应用程序时杀死主进程......

于 2017-09-04T19:28:29.010 回答
3

嗨,我在小米 phone.leeco 中测试时遇到了同样的问题,我不太清楚。小米手机有自己的操作系统,即 MIUI。当我们清除 RAM 时,它会清除所有应用程序,除了一些应用程序在操作系统中注册。像 Whatsapp 和 facebook 等一些其他著名的应用程序。

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

他们提供了一些手动特定的方式来运行服务。我已经检查过 Leeco 它使用的是 Android 操作系统。

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

MIUI 4.0 设置

MIUI AutoStart 详细说明

根据我的说法,您可以尝试使用服务,然后检查它是否有效。

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

于 2016-12-12T13:53:27.967 回答
2

可能这些中国手机已禁用应用程序唤醒以接收警报事件以节省电池寿命。我知道一些中国制造商如果提前关闭以节省电池电量,则不会唤醒应用程序以接收推送通知。因此,在再次手动打开应用程序之前,它不会被操作系统唤醒以进行任何事件处理。

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

于 2016-12-12T18:53:54.867 回答
1

我同意你的看法。但我认为你应该尝试一次 JobScheduler。您会找到官方文档 https://developer.android.com/reference/android/app/job/JobScheduler.html 我找到的最佳示例 https://github.com/googlesamples/android-JobScheduler 我没有测试它.according to me 你必须试试这个。

编辑

如果您想在 6.0 或更高版本中以打盹模式运行您的应用程序,您必须将您的应用程序列入白名单 check out

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

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

伊姆蒂亚兹

于 2016-12-13T05:09:32.813 回答