Android AlarmManager stops when activity die

2019-02-04 07:40发布

问题:

I start AlarmManager with PendingIntent and on few phones Alarm is not responding. On some devices is working ok on others it fails. I have made a few tests on different phones.

Nexus works ok, also Samsung Galaxy S4 zoom (4.2) works ok.

Samsung note 2 (4.3) works ok.

OPPO (4.4.4) alarm dies.

I have also implemented broadcast receivers which are working as they should on all devices.

    Log.v(TAG, "START ALARM");

    Intent intentAlarm = new Intent(context, AlarmReceiver.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, intentAlarm, PendingIntent.FLAG_UPDATE_CURRENT);

    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, 1000, 5000, pendingIntent);

回答1:

Check whether the app is in stopped state.When the app is in stopped state it wont receive any alarm or events.

Also, I guess it might be OEM/manufacturer specific firmware/OS issue.To check whether the alarm has being actually schedule use adb shell dumpsys alarm and check whether your app alarm has being actually scheduled.

To check whether it is in stopped state use the following command:

adb shell dumpsys package "com.package.name" and check "stopped=true"

To know more about stopped state refer:

Launch controls on stopped applications

Starting from Android 3.1, the system's package manager keeps track of applications that are in a stopped state and provides a means of controlling their launch from background processes and other applications.

Note that an application's stopped state is not the same as an Activity's stopped state. The system manages those two stopped states separately.

The platform defines two new intent flags that let a sender specify whether the Intent should be allowed to activate components in stopped application.

FLAG_INCLUDE_STOPPED_PACKAGES — Include intent filters of stopped applications in the list of potential targets to resolve against.
FLAG_EXCLUDE_STOPPED_PACKAGES — Exclude intent filters of stopped applications from the list of potential targets.
When neither or both of these flags is defined in an intent, the default behavior is to include filters of stopped applications in the list of potential targets.

Note that the system adds FLAG_EXCLUDE_STOPPED_PACKAGES to all broadcast intents. It does this to prevent broadcasts from background services from inadvertently or unnecessarily launching components of stoppped applications. A background service or application can override this behavior by adding the FLAG_INCLUDE_STOPPED_PACKAGES flag to broadcast intents that should be allowed to activate stopped applications.

Applications are in a stopped state when they are first installed but are not yet launched and when they are manually stopped by the user (in Manage Applications).

Please note stopped state is different from app process not running.



回答2:

There could be a couple of different issues at work here:

  • The type of alarm you are requesting (ELAPSED_REALTIME) will not wake up the device to deliver the alarm. Instead, if it expires while the device is sleeping it will be delivered the next time the device wakes.
  • The triggerAtMillis value of 1000 is requesting the first alarm at 1 second after boot of the device. If the device has already been up and running and you request this alarm, the first alarm may not fire and could cause the subsequent ones to not get scheduled. This is just a guess, I've not verified by looking at the 4.4.4 AOSP sources

The alarm handling was changed in API 19 (Android 4.4) to handle collating of alarm timers (all are inexact by default) and this change could have affected things for the 2nd bullet. You might try changing the triggerAtMillis value to be (SystemClock.elapsedRealtime() + 1000)

Note that if you need the device to wake from sleep, you'll need to use a _WAKEUP alarm variant and also have your BroadcastReceiver take a wake lock which your Service or Activity releases when it is done handling the alarm.



回答3:

This is only a guess but I think the issue has to do with the API. Starting with KitKat, the system messes up the AlarmManager. Perhaps consider trying using something else for systems at abd above kitkat.

"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. "

Taken from http://developer.android.com/reference/android/app/AlarmManager.html



回答4:

Try the following:

1) Add teh Wake_lock permission to your manifest.

<uses-permission android:name="android.permission.WAKE_LOCK">

2) Change

alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, 1000, 5000, pendingIntent);

with

alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000, 5000, pendingIntent);


回答5:

Could you show us the AlarmReceiver.class code? Maybe you need to use return START_STICKY; on your onStartCommand method?



回答6:

Try to place AlarmManager into background service.



回答7:

Your alarms will continue to exist after your app is closed normally. If it is force stopped, or your device restarted, or an update for your app is installed, or your app is uninstalled, they will be lost. You can create BroadcastReceivers for some of those situations to recreate your alarms.

Also, setInexactRepeating is exactly that: inexact. When that alarm fires is implementation dependent and can not be precisely predicted.



回答8:

Try this it works when activity is not running..

        Calendar calendar = Calendar.getInstance();

        long timemills = calendar.getTimeInMillis();
        Intent myIntent = new Intent(this, TimeChangeReceiver.class);
        pendingIntent = PendingIntent.getBroadcast(this, 0, myIntent, 0);

        AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

            alarmManager.set(AlarmManager.RTC, timemills, pendingIntent);
            alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, timemills,
                    10000, pendingIntent);


回答9:

i have also used Alarm Service in my project for preparative task in very 6 or 7 minutes. And it is running fine in all phone.

i have make a alarm Service like this:

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import android.util.Log;

public class MyAlarmService {
    private static PendingIntent resetAlarm;
    private static String TAG="CellPoliceChildGPSAlarmService";
    private static AlarmManager am;
    public static void start(Context context) {
        try {
            // We want the alarm to go off 30 seconds from now.
            long firstTime = SystemClock.elapsedRealtime();

            // Create an IntentSender that will launch our service, to     be scheduled with the alarm manager.
            //resetAlarm = PendingIntent.getService(context, 0, new     Intent(context, Get_NonRootDetails.class), 0);
            resetAlarm = PendingIntent.getService(context, 0, new     Intent(context, CallNonRBackgroundService.class), 0);
            // Schedule the alarm!
            am = (AlarmManager)     context.getSystemService(Context.ALARM_SERVICE);
            Log.i(TAG, firstTime+"");
            am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,     firstTime, 10*1000*60, resetAlarm);
        } 
        catch (Exception e) {
            Log.v("CellInfo", "Exception while start the     MyAlarmService at: " + e.getMessage());
        } 
    }

    public static void stop(Context context) {
        try {
            // When interval going to change from web services
            am.cancel(resetAlarm);
        } 
        catch (Exception e) {
            Log.v("CellInfo", "Exception while start the     MyAlarmService at: " + e.getMessage());
        }
    }


}

I have called or start like this;

MyAlarmService.start(SplashActivity.this);

Given permission in Manifest:

<uses-permission android:name="android.permission.WAKE_LOCK">

    <service
            android:name="com.secure.DataCountService"
            android:enabled="true" >
            <intent-filter>
                <action     android:name="com.secure.MyService" />
            </intent-filter>
        </service>

For notifications i also used pending intents like;

    Intent notificationIntent = new Intent(context, DashBoardActivity.class);

        PendingIntent pendingIntent = PendingIntent.getActivity(context,     0, notificationIntent, 0);

        notification.setLatestEventInfo(context, contentTitle,     PushNotificationUtils.notiMsg, pendingIntent);
        notification.flags  |=  notification.FLAG_AUTO_CANCEL;