Usar el servicio para ejecutar el fondo y crear notificaciones

Quiero que mi aplicación inicie el servicio cuando se hace clic en el botón y el servicio se debe ejecutar en segundo plano para mostrar una notificación a una hora determinada del día. Tengo el siguiente código para hacer esto. Pero muestra errores que no entiendo. Soy nuevo en Android y esta es mi primera aplicación que usa el servicio. Cualquier ayuda sería apreciada. Gracias por adelantado.

AndroidManifest.xml

               

CreateNotificationActiviy.java

 package com.example.newtrial; import android.os.Bundle; import android.app.Activity; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Intent; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class CreateNotificationActiviy extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.create_notification_activiy); Button b=(Button)findViewById(R.id.button1); b.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { // TODO Auto-generated method stub startService(new Intent(CreateNotificationActiviy.this, UpdaterServiceManager.class)); } }); } public void createNotification(View view) { // Prepare intent which is triggered if the // notification is selected Intent intent = new Intent(this, ResultActivity.class); PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0); // Build notification // Actions are just fake Notification noti = new Notification.Builder(this) .setContentTitle("Notification Title") .setContentText("Click here to read").setSmallIcon(R.drawable.ic_launcher) .setContentIntent(pIntent) .build(); NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); // hide the notification after its selected noti.flags |= Notification.FLAG_AUTO_CANCEL; notificationManager.notify(0, noti); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.create_notification_activiy, menu); return true; } } 

UpdaterServiceManager.java

 package com.example.newtrial; import java.util.Calendar; import java.util.Timer; import java.util.TimerTask; import android.app.AlertDialog; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.util.Log; import android.view.View; public class UpdaterServiceManager extends Service { private final int UPDATE_INTERVAL = 60 * 1000; private Timer timer = new Timer(); private static final int NOTIFICATION_EX = 1; private NotificationManager notificationManager; CreateNotificationActiviy not; public UpdaterServiceManager() { not=new CreateNotificationActiviy(); } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } @Override public void onCreate() { // code to execute when the service is first created super.onCreate(); Log.i("MyService", "Service Started."); showNotification(); } public void showNotification() { final Calendar cld = Calendar.getInstance(); int time = cld.get(Calendar.HOUR_OF_DAY); if(time>12) { not.createNotification(null); } else { AlertDialog.Builder alert=new AlertDialog.Builder(this); alert.setMessage("Not yet"); alert.setTitle("Error"); alert.setPositiveButton("OK", null); alert.create().show(); } } @Override public void onDestroy() { if (timer != null) { timer.cancel(); } } @Override public int onStartCommand(Intent intent, int flags, int startid) { return START_STICKY; } private void stopService() { if (timer != null) timer.cancel(); } } 

ResultActivity.java

 package com.example.newtrial; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.widget.TextView; public class ResultActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_result); TextView tv=(TextView)findViewById(R.id.textView1); tv.setText("After notification is clicked" ); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.result, menu); return true; } } 

Logcat

 12-10 12:14:04.286: I/Process(872): Sending signal. PID: 872 SIG: 9 12-10 12:14:11.774: I/MyService(893): Service Started. 12-10 12:14:12.094: D/AndroidRuntime(893): Shutting down VM 12-10 12:14:12.094: W/dalvikvm(893): threadid=1: thread exiting with uncaught exception (group=0x414c4700) 12-10 12:14:12.124: E/AndroidRuntime(893): FATAL EXCEPTION: main 12-10 12:14:12.124: E/AndroidRuntime(893): java.lang.RuntimeException: Unable to create service com.example.newtrial.UpdaterServiceManager: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application 12-10 12:14:12.124: E/AndroidRuntime(893): at android.app.ActivityThread.handleCreateService(ActivityThread.java:2587) 12-10 12:14:12.124: E/AndroidRuntime(893): at android.app.ActivityThread.access$1600(ActivityThread.java:141) 12-10 12:14:12.124: E/AndroidRuntime(893): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1338) 12-10 12:14:12.124: E/AndroidRuntime(893): at android.os.Handler.dispatchMessage(Handler.java:99) 12-10 12:14:12.124: E/AndroidRuntime(893): at android.os.Looper.loop(Looper.java:137) 12-10 12:14:12.124: E/AndroidRuntime(893): at android.app.ActivityThread.main(ActivityThread.java:5103) 12-10 12:14:12.124: E/AndroidRuntime(893): at java.lang.reflect.Method.invokeNative(Native Method) 12-10 12:14:12.124: E/AndroidRuntime(893): at java.lang.reflect.Method.invoke(Method.java:525) 12-10 12:14:12.124: E/AndroidRuntime(893): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737) 12-10 12:14:12.124: E/AndroidRuntime(893): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 12-10 12:14:12.124: E/AndroidRuntime(893): at dalvik.system.NativeStart.main(Native Method) 12-10 12:14:12.124: E/AndroidRuntime(893): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application 12-10 12:14:12.124: E/AndroidRuntime(893): at android.view.ViewRootImpl.setView(ViewRootImpl.java:563) 12-10 12:14:12.124: E/AndroidRuntime(893): at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:269) 12-10 12:14:12.124: E/AndroidRuntime(893): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69) 12-10 12:14:12.124: E/AndroidRuntime(893): at android.app.Dialog.show(Dialog.java:281) 12-10 12:14:12.124: E/AndroidRuntime(893): at com.example.newtrial.UpdaterServiceManager.showNotification(UpdaterServiceManager.java:65) 12-10 12:14:12.124: E/AndroidRuntime(893): at com.example.newtrial.UpdaterServiceManager.onCreate(UpdaterServiceManager.java:41) 12-10 12:14:12.124: E/AndroidRuntime(893): at android.app.ActivityThread.handleCreateService(ActivityThread.java:2577) 12-10 12:14:12.124: E/AndroidRuntime(893): ... 10 more 

La pregunta es relativamente antigua, pero espero que esta publicación todavía sea relevante para otros.

TL; DR: use AlarmManager para progtwigr una tarea, use IntentService, vea el código de ejemplo aquí ;

De qué se trata esta aplicación de prueba (e instrucción):

Aplicación sencilla helloworld, que le envía notificaciones cada 2 horas. Al hacer clic en notificación, se abre la actividad secundaria en la aplicación; eliminando pistas de notificación.

Cuándo deberías usarlo:

Una vez que necesita ejecutar alguna tarea de forma progtwigda. Mi propio caso: una vez al día, quiero buscar nuevo contenido del servidor, redactar una notificación basada en el contenido que tengo y mostrarlo al usuario.

Qué hacer:

  1. Primero, creemos 2 actividades: MainActivity, que inicia el servicio de notificación y NotificationActivity, que se iniciará al hacer clic en notificación:

    activity_main.xml

     < ?xml version="1.0" encoding="utf-8"?>    

    MainActivity.java

     public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void onSendNotificationsButtonClick(View view) { NotificationEventReceiver.setupAlarm(getApplicationContext()); } } 

    y NotificationActivity es cualquier actividad aleatoria que se te ocurra. ¡NÓTESE BIEN! No olvides agregar ambas actividades en AndroidManifest.

  2. Luego, WakefulBroadcastReceiver receptor de transmisión WakefulBroadcastReceiver . Llamé a NotificationEventReceiver en el código anterior.

    Aquí, configuraremos AlarmManager para disparar PendingIntent cada 2 horas (o con cualquier otra frecuencia), y especificaremos las acciones manejadas para este bash en el método onReceive() . En nuestro caso, inicie IntentService , que especificaremos en los pasos posteriores. Este IntentService generaría notificaciones para nosotros.

    Además, este receptor contendría algunos métodos auxiliares como la creación de PendintIntents, que usaremos más adelante.

    NB1! Como estoy usando WakefulBroadcastReceiver , necesito agregar permisos adicionales en mi manifiesto:

    NB2! Utilizo la versión inactiva del receptor de difusión, ya que quiero asegurarme de que el dispositivo no vuelva a dormirse durante el IntentService mi IntentService . En el mundo hello no es tan importante (no tenemos una operación de larga ejecución en nuestro servicio, pero imagine, si tiene que buscar algunos archivos relativamente grandes del servidor durante esta operación). Lea más acerca de Device Awake aquí .

    NotificationEventReceiver.java

     public class NotificationEventReceiver extends WakefulBroadcastReceiver { private static final String ACTION_START_NOTIFICATION_SERVICE = "ACTION_START_NOTIFICATION_SERVICE"; private static final String ACTION_DELETE_NOTIFICATION = "ACTION_DELETE_NOTIFICATION"; private static final int NOTIFICATIONS_INTERVAL_IN_HOURS = 2; public static void setupAlarm(Context context) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent alarmIntent = getStartPendingIntent(context); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, getTriggerAt(new Date()), NOTIFICATIONS_INTERVAL_IN_HOURS * AlarmManager.INTERVAL_HOUR, alarmIntent); } @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Intent serviceIntent = null; if (ACTION_START_NOTIFICATION_SERVICE.equals(action)) { Log.i(getClass().getSimpleName(), "onReceive from alarm, starting notification service"); serviceIntent = NotificationIntentService.createIntentStartNotificationService(context); } else if (ACTION_DELETE_NOTIFICATION.equals(action)) { Log.i(getClass().getSimpleName(), "onReceive delete notification action, starting notification service to handle delete"); serviceIntent = NotificationIntentService.createIntentDeleteNotification(context); } if (serviceIntent != null) { startWakefulService(context, serviceIntent); } } private static long getTriggerAt(Date now) { Calendar calendar = Calendar.getInstance(); calendar.setTime(now); //calendar.add(Calendar.HOUR, NOTIFICATIONS_INTERVAL_IN_HOURS); return calendar.getTimeInMillis(); } private static PendingIntent getStartPendingIntent(Context context) { Intent intent = new Intent(context, NotificationEventReceiver.class); intent.setAction(ACTION_START_NOTIFICATION_SERVICE); return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } public static PendingIntent getDeleteIntent(Context context) { Intent intent = new Intent(context, NotificationEventReceiver.class); intent.setAction(ACTION_DELETE_NOTIFICATION); return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } } 
  3. Ahora, IntentService un IntentService para realmente crear notificaciones.

    Allí, especificamos onHandleIntent() que son las respuestas en la intención de NotificationEventReceiver que startWakefulService en el método startWakefulService .

    Si se trata de la acción Eliminar, podemos iniciar sesión en nuestro análisis, por ejemplo. Si se trata de la intención de notificación de inicio, entonces al usar NotificationCompat.Builder estamos redactando una nueva notificación y mostrándola por NotificationManager.notify . Al redactar la notificación, también estamos configurando bashs pendientes para hacer clic y eliminar acciones. Bastante fácil.

    NotificationIntentService.java

     public class NotificationIntentService extends IntentService { private static final int NOTIFICATION_ID = 1; private static final String ACTION_START = "ACTION_START"; private static final String ACTION_DELETE = "ACTION_DELETE"; public NotificationIntentService() { super(NotificationIntentService.class.getSimpleName()); } public static Intent createIntentStartNotificationService(Context context) { Intent intent = new Intent(context, NotificationIntentService.class); intent.setAction(ACTION_START); return intent; } public static Intent createIntentDeleteNotification(Context context) { Intent intent = new Intent(context, NotificationIntentService.class); intent.setAction(ACTION_DELETE); return intent; } @Override protected void onHandleIntent(Intent intent) { Log.d(getClass().getSimpleName(), "onHandleIntent, started handling a notification event"); try { String action = intent.getAction(); if (ACTION_START.equals(action)) { processStartNotification(); } if (ACTION_DELETE.equals(action)) { processDeleteNotification(intent); } } finally { WakefulBroadcastReceiver.completeWakefulIntent(intent); } } private void processDeleteNotification(Intent intent) { // Log something? } private void processStartNotification() { // Do something. For example, fetch fresh data from backend to create a rich notification? final NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setContentTitle("Scheduled Notification") .setAutoCancel(true) .setColor(getResources().getColor(R.color.colorAccent)) .setContentText("This notification has been triggered by Notification Service") .setSmallIcon(R.drawable.notification_icon); PendingIntent pendingIntent = PendingIntent.getActivity(this, NOTIFICATION_ID, new Intent(this, NotificationActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); builder.setContentIntent(pendingIntent); builder.setDeleteIntent(NotificationEventReceiver.getDeleteIntent(this)); final NotificationManager manager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE); manager.notify(NOTIFICATION_ID, builder.build()); } } 
  4. Casi termino. Ahora también agrego receptor de difusión para eventos BOOT_COMPLETED, TIMEZONE_CHANGED y TIME_SET para volver a configurar mi AlarmManager, una vez que el dispositivo ha sido reiniciado o la zona horaria ha cambiado (por ejemplo, el usuario volaba de EE. UU. A Europa y no desea que aparezca una notificación) en el medio de la noche, pero estaba pegajosa a la hora local :-)).

    NotificationServiceStarterReceiver.java

     public final class NotificationServiceStarterReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { NotificationEventReceiver.setupAlarm(context); } } 
  5. Necesitamos también registrar todos nuestros servicios, receptores de difusión en AndroidManifest:

     < ?xml version="1.0" encoding="utf-8"?>                         

¡Eso es!

El código fuente de este proyecto puede encontrarlo aquí . Espero que encuentres útil esta publicación.

Su error está en UpdaterServiceManager en el método onCreate y showNotification.

Está intentando mostrar la notification del Service using Activity Context . Mientras que Every Service has its own Context, simplemente use eso. No necesita pass a Service an Activity's Context. No veo por qué necesita un contexto de Activity's Context to show Notification. específico Activity's Context to show Notification.

Ponga su método createNotification en UpdateServiceManager.class . Y elimine CreateNotificationActivity not from Service.

No puede mostrar una ventana / diálogo de aplicación a través de un Contexto que no sea una Actividad. Intente pasar una referencia de actividad válida