Android AlarmManager.setExactAndAllowWhileIdle() и WakefulBroadcastReceiver Не работает на некоторых новых и недорогих устройствах

Я думаю, что этот вопрос задают много раз в stackoverflow, но все еще так много людей пытаются его решить.

В моем приложении для Android я должен разбудить устройство каждые полчаса, чтобы получить текущее местоположение и отправить его на сервер. Для этого я использовал AlarmManager с методом setExactAndAllowWhileIdle() и WakefulBroadcastReceiver. Его работа прекрасна практически во всех стандартных/популярных устройствах, таких как samsung, LG (Nexus), Sony, Panasonic, Lenovo, Motorola, 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, например "Настройки" > "Аккумулятор" > "Выполнить пробуждение" > "Отключить обе опции". Если он включен, аккумулятор может игнорировать силовые пробуждения из приложений.

Мои вопросы:

  • Что случилось с такими устройствами? Почему они не позволяют тревогу срабатывать в определенный промежуток времени?

  • В некоторых устройствах, таких как Gionee s plus, срабатывание сигнализации на 2-3 минуты позже... почему?

  • android.net.conn.CONNECTIVITY_CHANGE широковещательный приемник для прослушивания при изменении сетевого подключения..... Что делать, если он не работает на некоторых устройствах, таких как Gionee s plus?

  • Существует множество вариантов настройки батареи для разных производителей. Может ли это повредить нашим фоновым службам приложений, если это то, что для решения.

Ответ 1

Привет, у меня такая же проблема при тестировании в Xiomi phone.leeco. У меня мало идей. У телефона Xiomi есть своя ОС, которая является MIUI. Когда мы очистили ОЗУ, ясность всех приложений отменила некоторые регистрации приложений в ОС. Как Whatsapp и facebook некоторые другие известные приложения.

Я пробовал Service, Alarm Manager и Scheduler, но не добился успеха.

Они предоставляют некоторый рутинный specfic способ запуска services.I проверили Leeco он использовал ОС Android.

Решение для MIUI 7.0 = > Безопасность = > Автозапуск = > выберите Приложения, которые вы хотите запустить в фоновом режиме = > Перезагрузка После перезагрузки ваше устройство должно запускать службы приложений в фоновом режиме, как это делают другие устройства для Android.

Настройки MIUI 4.0

Подробное описание MIUI AutoStart

По мне, вы можете попробовать с Сервисами, а затем проверить, работает ли это.

Спасибо, надеюсь, вам поможет немного.

Ответ 2

Возможно, эти китайские телефоны отключили приложение для получения тревожных событий для экономии времени автономной работы. Я знаю, что некоторые китайские производители не пробуждают приложение, чтобы получать push-уведомления, если они закрыты для сохранения батареи раньше. Таким образом, пока приложение не будет открыто вручную, оно не будет разбужено ОС для любой обработки событий.

Однако это поведение можно изменить. Проверьте настройки управления питанием и измените их, чтобы разрешить разбудить приложения через определенные промежутки времени или при необходимости. Я думаю, что это может быть Ограниченный режим или что-то подобное.

Ответ 3

Я согласен с тобой. Но я думаю, что вы должны попробовать с JobScheduler один раз. Вы найдете официальную документацию https://developer.android.com/reference/android/app/job/JobScheduler.html Лучший пример, который я нахожу https://github.com/googlesamples/android-JobScheduler У меня нет теста. Согласно мне, вы должны попробовать это.

ИЗМЕНИТЬ

Если вы хотите запустить приложение в режиме доз в 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

Ответ 4

В моем приложении Android я должен разбудить устройство каждые 15 минут, чтобы получить текущее местоположение и отправить его на сервер. Схема последовательности операций Я тестировал его на Xiaomi Mi 5s (Android 6.0.1). Когда я закрываю приложение, приложение переходит в спящий режим:(AlarmManager с setExactAndAllowWhileIdle() не работает ¯\_(ツ)_/¯

Да, он отлично работает практически во всех стандартных/популярных устройствах, таких как Samsung, LG (Nexus 5X), Sony, Motorola, 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" />

...

Я тестировал это решение на Xiaomi Mi 5s. Это работает!!!

IMHO кажется, что прошивка Xiaomi убивает основной процесс, когда пользователь выходит из приложения...