Frage

I'm working on an Android app that sues a background task to fetch XML from a URL every x seconds (user defined interval, defaulting to 60). My structure is as so:

MainActivity

This schedules an Alarm via AlarmManager:

public static void scheduleAlarm(Context voContext, int viCheckInterval)
{
    try {
        moAlarmManager = (AlarmManager) voContext.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(voContext, AlarmReceiver.class);
        moAlarmIntent = PendingIntent.getBroadcast(voContext, 0, intent,
                                                    PendingIntent.FLAG_CANCEL_CURRENT);
        Calendar time = Calendar.getInstance();
        time.setTimeInMillis(System.currentTimeMillis());
        time.add(Calendar.SECOND, viCheckInterval);
        moAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(),
                                       time.getTimeInMillis(), moAlarmIntent);
    } catch (Exception e) {
        Log.e("MessageCheckAlarmHandler", e.toString());
    }
}

AlarmReceiver

This is a BroadcastReceiver that starts the service:

@Override
public void onReceive(Context context, Intent intent)
{
    Context oAppContext = context.getApplicationContext();

    if (oAppContext == null) {
        oAppContext = context;
    }

    Intent serviceIntent = new Intent(oAppContext, MessagingService.class);
    oAppContext.startService(serviceIntent);
}

MessagingService

This creates our in-house logger (logging over TCP) and starts an AsyncTask called FetchPageTask:

public class MessagingService extends Service
{
    @Override
    public void onCreate()
    {
        super.onCreate();

        ...

        this.acquireLocks();

        try {
            String sCheckerUrl = oPreferences.getString("pref_server", "");
            int sCheckerPort = Integer.parseInt(oPreferences.getString("pref_server_port",
                                                                           "8050"));
            sCheckerUrl = String.format(URL, sCheckerUrl, sCheckerPort);

            this.moFetchInboxTask = new FetchPageTask(this.logger, this);
            this.moFetchInboxTask.execute(sCheckerUrl);
        } finally {
            this.releaseLocks();
            this.stopSelf();
        }
    }

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

        this.logger.close();
    }

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

    /**
     * Acquire a WakeLock and a WifiLock.
     */
    private void acquireLocks()
    {
        try {
            // Acquire a wake lock to prevent the device from entering "deep sleep"
            PowerManager oPowerManager = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
            this.moWakeLock = oPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
            this.moWakeLock.acquire();
            // Acquire a WiFi lock to ensure WiFi is enabled
            WifiManager wm = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
            this.moWifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG);
            this.moWifiLock.acquire();
        } catch (Exception e) {
            this.logger.error(TAG + "->onCreate()", "Error acquiring locks: " + e.toString());
        }
    }

    /**
     * Release our WakeLock and WifiLock.
     */
    private void releaseLocks()
    {
        try {
            this.moWakeLock.release();
            this.moWifiLock.release();
        } catch (Exception e) {
            this.logger.error(TAG + "->releaseLocks()", e.toString());
        }
    }
}

FetchPageTask

This extends AsyncTask and does all the work of fetching the page and parsing the XML. It also then adds notifications and performs actions on the data retreived if need be.


This all works fine once, but does not run subsequently. I know that the AsyncTask works as I was previously doing it using pure Java via ScheduledExecutorService and ScheduledFuture and it worked. The only reason I decided to change to using AlarmManager is for maintainability purposes.

War es hilfreich?

Lösung

First, you are setting up your alarm to occur immediately, and then every ~43 years thereafter. That is unlikely to be what you want. Modify the third parameter of your call to setRepeating() to be the desired period in milliseconds, which right now is set to the number of milliseconds since midnight 1 January 1970.

Second, you are acquiring your WakeLock too late. There is no guarantee that your acquireLocks() will get a chance to run before the device falls asleep. My WakefulIntentService or the new WakefulBroadcastReceiver offer better patterns for passing control to an IntentService.

Andere Tipps

I think you don't need the Calendar here. You just want to run the action every x seconds, so It would be something like this:

 moAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
                                   viCheckInterval, moAlarmIntent); 

//  viCheckInterval should be long miliseconds
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top