Pregunta

I'm trying to create a reminder application that pops up a reminder in the status bar. As I understand, the Android NotificationManager is the standard tool to use to schedule notifications however a BootService is needed in order to re-schedule notifications as scheduled events do not survive across boots.

I've pieced together an application below which schedules a single reminder at boot time, and pops up a notification in the status bar. If you click the notification, it launches MainActivity which, in the future, will have options to add more reminders, delete them, or whatever.

The problem I'm having is that the reminder works correctly the first time however it seems to be re-scheduling itself and popping up again at random times for some reason. Should I be launching another activity rather than the one which installs the BootAlarmService?

UPDATE: So I think I found some clues with logcat. Apparently the Service is crashing and being restarted which is resetting the Notification. Any ideas why this is?

UPDATE II : code changed to working model

ActivityManager   I  No longer want com.example.alarm_boot_test (pid 1428): hidden #16
ActivityManager   W  Scheduling restart of crashed service com.example.alarm_boot_test/.BootAlarmService in 5000ms
ActivityManager   W  Scheduling restart of crashed service com.example.alarm_boot_test/.NotificationAlarmService in 15000ms
ActivityManager   I  Start proc com.example.alarm_boot_test for service com.example.alarm_boot_test/.BootAlarmService: pid=2321 uid=10069 gids={}
       dalvikvm   D  Debugger has detached; object registry had 1 entries
        szipinf   D  Initializing inflate state
BootAlarmService  D  oncreate()
BootAlarmService  D  alarm set for Thu Jan 17 08:03:00 CST 2013

MainActivity.java

package com.example.alarm_boot_test;

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

public class MainActivity extends Activity
{

    @Override
    protected void onCreate (Bundle savedInstanceState)
    {
        super.onCreate (savedInstanceState);
        setContentView (R.layout.activity_main);
    }


}

BootAlarmService.java

package com.example.alarm_boot_test;

import java.util.Calendar;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class BootAlarmService extends Service
{
    private final String TAG = this.getClass ().getName ();

    @Override
    public void onCreate ()
    {
        Log.d (TAG, "oncreate()");
        super.onCreate ();
    }


   @Override
   public int onStartCommand (Intent intent, int flags, int startId)
   {
       Log.d (TAG, "alarm_test: BootAlarmService.onStartCommand() Received start id " + startId + ": " + intent);

       // if intent == null, service has been killed/restarted by system
       if (intent != null)
        createNotificationOnBoot();
       else
        Toast.makeText (getBaseContext (), "Intent was null in BootAlarmService.", Toast.LENGTH_LONG).show();


       return START_STICKY;
    }


    private void createNotificationOnBoot ()
    {
        Intent inotify = new Intent(this , NotificationAlarmService.class);
        inotify.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
        AlarmManager amgr = (AlarmManager)getSystemService(ALARM_SERVICE);
        PendingIntent pendingIntent = PendingIntent.getService(this, 0, inotify, 0);

        // go off two mins from now
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, calendar.get (Calendar.MINUTE) + 2);

        amgr.set (AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis (), pendingIntent);


        Log.d (TAG, "alarm set for " + calendar.getTime ().toString ());
    }


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


}

BootReceiver.java

package com.example.alarm_boot_test;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class BootReceiver extends BroadcastReceiver
{

    @Override
    public void onReceive (final Context context, final Intent bootintent)
    {
        Intent i = new Intent ();
        i.setAction ("com.example.alarm_boot_test.BootAlarmService");
        context.startService (i);
    }

}

NotificationAlarmService.java

package com.example.alarm_boot_test;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class NotificationAlarmService extends Service
{
    private final String TAG = this.getClass().getName ();


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


    @Override
    public int onStartCommand (Intent intent, int flags, int startId)
    {
       Log.d (TAG, "alarm_test: NotificationAlarmService.onStartCommand()");
       if (intent != null)
          createNotification ();
       else
          Toast.makeText (getBaseContext (), "Intent was null in NotificationAlarmService.", Toast.LENGTH_LONG).show();

       return super.onStartCommand (intent, flags, startId);
     }



    private void createNotification()
    {
      NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
      Notification notification = new Notification(android.R.drawable.stat_sys_warning, "Note from AlarmService", System.currentTimeMillis());
      Intent i = new Intent(this, ViewReminder.class);
      PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, i, 0);

      notification.setLatestEventInfo(this, "New Notification", "You have been notified by AlarmService", pendingIntent);
      notificationManager.notify(10001, notification);

   }




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

*activity_main.xml*

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="Service started! Reboot!" />

</RelativeLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.alarm_boot_test"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <uses-sdk
        android:minSdkVersion="9"
        android:targetSdkVersion="9" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <service android:name="com.example.alarm_boot_test.BootAlarmService" >
            <intent-filter>
                <action android:name="com.example.alarm_boot_test.BootAlarmService" >
                </action>
            </intent-filter>
        </service>

        <receiver android:name="com.example.alarm_boot_test.BootReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" >
                </action>
            </intent-filter>
        </receiver>

        <service android:name="com.example.alarm_boot_test.NotificationAlarmService" >
        </service>

        <activity
            android:name="com.example.alarm_boot_test.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
¿Fue útil?

Solución

In case it helps someone else, I think I needed to check the passed Intent for NULL in the onStartCommand() method both in BootAlarmService.java as well as NotificationAlarmService.java. Only been testing it a couple days but it looks like the Intent is NULL if the system kills/restarts the service. Simply testing for this allowed me to create the notification only when the service is started at Boot-time (when the passed Intent is NOT null).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top