Android - AlarmManager устанавливает случайные задержки между сигналами тревоги

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

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

Любые идеи о том, как я могу это сделать?


person João Cartucho    schedule 20.04.2017    source источник


Ответы (2)


Добавьте это в свой manifest.xml

<receiver android:name=".BroadcastReceiverAux" />

Согласно разработчику.android

   Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. 
There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). 
Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.

из https://developer.android.com/reference/android/app/AlarmManager.html#setExact(int, long, android.app.PendingIntent )

person Lcukerd    schedule 20.04.2017
comment
Я отредактировал вопрос, чтобы показать и мой приемник. Спасибо - person João Cartucho; 20.04.2017
comment
Добавить . перед именем андроида. Это может быть проблемой. Кстати, что вы пытаетесь сделать с намерением? - person Lcukerd; 20.04.2017
comment
. Я думаю, это не имеет никакого значения. Намерение — это описание операции, которая должна быть выполнена. - person João Cartucho; 20.04.2017
comment
Я никогда не использовал явные действия для вызова получателя широковещательной рассылки. Intent alarmclass = new Intent (контекст, BroadcastReceiverAux.class); Попробуйте установить намерение таким образом. - person Lcukerd; 20.04.2017
comment
Кстати, вы знаете, что метод set на самом деле устанавливает неточные сигналы тревоги, верно? Вы устанавливаете 3 секунды позже, но он может позвонить через несколько минут, чтобы сэкономить заряд батареи. Попробуйте установить setexact, чтобы проверить, все ли в вашем приложении правильно. - person Lcukerd; 20.04.2017
comment
В самом деле? Итак, если я просто использую setRepeating, он автоматически добавит эти случайные задержки, которые я хочу, для экономии заряда батареи? это было бы здорово для меня - person João Cartucho; 20.04.2017
comment
Мне удалось найти способ заставить время задержки. Я поделился кодом. Спасибо за вашу помощь! - person João Cartucho; 21.04.2017

Мне удалось найти способ сделать это. Я делюсь кодом на случай, если он вам тоже понадобится.

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tribta.test">

    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.VIBRATE"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="test"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:process=":remote" android:name=".Alarm"></receiver>
        <service
            android:name=".MyService"
            android:enabled="true"
            android:process=":my_service" >
        </service>
    </application>
</manifest>

MainActivity.java:

package com.tribta.test;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState){

        super.onCreate(savedInstanceState);
        Intent serviceIntent = new Intent(this,MyService.class);
        this.startService(serviceIntent);
    }

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

MyService.java:

package com.tribta.test;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class MyService extends Service
{
    Alarm alarm = new Alarm();
    public void onCreate()
    {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        alarm.setAlarm(this);
        return START_STICKY;
    }

    @Override
    public void onStart(Intent intent, int startId)
    {
        alarm.setAlarm(this);
    }

    @Override
    public IBinder onBind(Intent intent)
    {
        return null;
    }
}

Alarm.java, куда вы можете поместить СВОЙ код:

package com.tribta.test;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.os.Vibrator;
import android.widget.Toast;

import java.util.Random;

public class Alarm extends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
        wl.acquire();

        // Put here YOUR code.
        Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show(); // For example

        Vibrator v = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
        v.vibrate(300); // Vibrate for 300 milliseconds

        cancelAlarm(context);
        setAlarm(context);

        wl.release();
    }

    public void setAlarm(Context context)
    {
        AlarmManager am =( AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        Intent i = new Intent(context, Alarm.class);
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);

        Random r = new Random();
        int ri = r.nextInt(7 - 1) + 1; // random integer between 7 (inclusive) and 1 (exclusive),
        int delay = 1000 * 60 * 60 * ri; // Millisec * Second * Minute * hours

        am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + delay, pi);
    }

    public void cancelAlarm(Context context)
    {
        Intent intent = new Intent(context, Alarm.class);
        PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(sender);
    }
}
person João Cartucho    schedule 21.04.2017