3

Я использую GCM, чтобы получить уведомление, когда изображение опубликовано, а затем загрузить и обработать его:GcmBroadcastReceiver/GcmIntentService умирает

public class GcmBroadcastReceiver extends WakefulBroadcastReceiver 
{ 
    @Override 
    public void onReceive(Context context, Intent intent) 
    { 
     DataUtils.log("In GcmBroadcastReceiver! threadname is " + Thread.currentThread().getName()); 

     // Explicitly specify that GcmIntentService will handle the intent. 
     ComponentName comp = new ComponentName(context.getPackageName(), GcmIntentService.class.getName()); 
     // Start the service, keeping the device awake while it is launching. 
     startWakefulService(context, (intent.setComponent(comp))); 
     setResultCode(Activity.RESULT_OK); 
    } 
} 

Это начало моего GcmIntentService:

public class GcmIntentService extends IntentService 
{ 
    public static final int NOTIFICATION_ID = 1; 

    public GcmIntentService() 
    { 
     super("GcmIntentService"); 
    } 


    @Override 
    protected void onHandleIntent(Intent intent) 
    { 

     DataUtils.log("In GcmIntentService onHandleIntent(), threadname is " + Thread.currentThread().getName()); 

     Bundle extras = intent.getExtras(); 
     GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this); 
     // The getMessageType() intent parameter must be the intent you received in your BroadcastReceiver. 
     String messageType = gcm.getMessageType(intent); 

     if (!extras.isEmpty()) // has effect of unparcelling Bundle 
     { 
      /* 
      * Filter messages based on message type. Since it is likely that GCM will be 
      * extended in the future with new message types, just ignore any message types you're 
      * not interested in, or that you don't recognize. 
      */ 
      if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) 
      { 
       DataUtils.log("In GcmIntentService - Send error: " + extras.toString()); 
      } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) 
      { 
       DataUtils.log("In GcmIntentService - Deleted messages on server: " + extras.toString()); 
      // If it's a regular GCM message, do some work. 
      } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) 
      { 

       String notificationType = extras.getString(MyAppApi.GCM_MSG_TYPE_KEY); 

       if(DataUtils.isEmpty(notificationType)) { 

        DataUtils.log("In GcmIntentService - notificationType is empty!"); 

       } else if(notificationType.equalsIgnoreCase(MyAppApi.GCM_IS_NEW_WALLPAPER)) { 

        //We're about to receive a new image! 
        DataUtils.log("In GcmIntentService - Receiving a new image!"); 
        processNewWallpaper(); 

       } else if(notificationType.equalsIgnoreCase(MyAppApi.GCM_IS_FRIEND_NOTIFICATION)) { 

        //We're about to receive a friend notification 
        DataUtils.log("In GcmIntentService - Receiving a friend notification!"); 
        processFriendNotification(); 

       } else { 
        //Unknown 
        DataUtils.log("In GcmIntentService - Receiving unknown message type! " + notificationType); 
       } 

      } else { 

       DataUtils.log("In GcmIntentService - Unknown GCM message: " + extras.toString()); 
      } 
     } 

     //Release the wake lock provided by the WakefulBroadcastReceiver. 
     GcmBroadcastReceiver.completeWakefulIntent(intent); 

    } 
} 

Кажется, что в случайном порядке служба умрет. Из журнала:

01-13 20:00:44.436: I/ActivityManager(375): Process com.grakk.android (pid 23227) has died. 
01-13 20:00:44.444: W/ActivityManager(375): Scheduling restart of crashed service com.grakk.android/.GcmIntentService in 11426ms 

Что делает этот код, когда он получает сообщение GCM, чтобы загрузить изображение, то это показывает пользователю уведомление (это похоже на нормальное приложение чата).

Тестер сказал мне, что как только он получил изображение, но не получил уведомление, а это означает, что сама служба запускается и выполняет часть работы, но не завершает ее.

Код уведомления запускается в процессеNewWallpaper() вместе с загрузкой и обработкой изображения. Вот код: метод

... 

if(senderContact == null) { 
    sendNotification(null, message, true); 
} else { 
    sendNotification(senderContact.getName(), message.trim(), false); 
} 

... 

Извещение:

... 

// Put the message into a notification and post it. This is just one simple example 
// of what you might choose to do with a GCM message. 
@SuppressWarnings("deprecation") 
@TargetApi(16) 
private void sendNotification(String name, String message, boolean isAnonymous) 
{ 
    Context context = GcmIntentService.this; 
    NotificationManager mNotificationManager = (NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE); 

    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, ContactsActivity.class), 0); 

    Notification.Builder mBuilder = new Notification.Builder(this) 
     .setSmallIcon(R.drawable.ic_launcher) 
     .setContentTitle(context.getString(R.string.app_name)); 

    String textToShow = null; 
    if(DataUtils.isEmpty(message)) 
    { 
     if(isAnonymous) { 
      textToShow = context.getString(R.string.notification_text_anonymous); 
     } else { 
      textToShow = String.format(getResources().getString(R.string.notification_text_friend), name); 
     } 
    } else { 
     textToShow = message; 
    } 

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 
     mBuilder.setStyle(new Notification.BigTextStyle().bigText(textToShow)); 
    } 

    mBuilder.setContentText(textToShow); 
    mBuilder.setAutoCancel(true); 

    Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); 
    mBuilder.setSound(alarmSound); 
    mBuilder.setContentIntent(contentIntent); 

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 
     mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build()); 
    } else { 
     mNotificationManager.notify(NOTIFICATION_ID, mBuilder.getNotification()); 
    } 
} 

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

Это не всегда происходит. Иногда отображается уведомление, иногда это не так.

Я не уверен, что является вероятными причинами, и как отлаживать это. Какие-нибудь советы?

+0

Вы пытались создать отдельный, новый экземпляр «Intent», чтобы вызвать службу вместо того, чтобы изменять значение, переданное в «GcmBroadcastReceiver»? – matiash

+0

Можете ли вы подробно рассказать о том, что происходит в '// много работы здесь ', например, часть создателя уведомлений – user2450263

+0

После того, как вы сделали много работы, вы освобождаете блокировку следа GcmReceiver.completeWakefulIntent (намерение) ;? –

ответ

1

Вы вызвали OnCreate() в классе GcmIntentService?

Некоторые примеры кода ниже:

public class GcmIntentService extends IntentService { 

    String mes; 
    private Handler mHandler; 

    public GcmIntentService() { 
     super("GcmIntentService"); 
    } 

    @Override 
    public void onCreate() { 
     super.onCreate(); 
     mHandler = new Handler(); 
    } 

    @Override 
    protected void onHandleIntent(Intent intent) { 
     Bundle extras = intent.getExtras(); 

     GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this); 

     String messageType = gcm.getMessageType(intent); 
     mes = extras.getString("title"); 
     showToast(); 
     Log.i("GCM", "Recevied: (" + messageType + ") " + extras.getString("title")); 

     GcmReceiver.completeWakefulIntent(intent); 
    } 

    public void showToast() { 
     mHandler.post(new Runnable() { 
      @Override 
      public void run() { 
       Toast.makeText(getApplicationContext(), mes, Toast.LENGTH_LONG).show(); 
      } 
     }); 
    } 
} 

EDIT: Добавить полезный учебник для юность GCMhere.

+0

У меня нет, однако он будет содержать только 'super.onCreate();'. Это все еще необходимо? – Sandy

+0

Я добавил следующее, но я все равно получаю то же сообщение. '@Override public void onCreate() { super.onCreate(); } ' – Sandy

+0

Я не инициализировал mHandler = new Handler() ;, спасибо – saqibahmad

0

Извините, что я использую ответ (я еще не могу прокомментировать).

Я бы попытался извлечь вызов для отправкиNotification из processNewWallpaper вправо после processNewWallpaper(). Если это не сработало, вы должны отправить свой код в processNewWallpaper(). Я предполагаю, что в некоторых случаях ваш код врезается в processNewWallpaper и пропускает sendNotification, но поскольку его обрабатывают, он ничего не будет бросать.

Также я заметил, что приложения действуют по-другому, если они открыты в фоновом режиме или полностью закрыты (используйте приложение для запуска приложений и закройте приложение). Если вы можете последовательно воспроизвести проблему, ее будет легче решить.

+0

Привет @kayvan. Что вы подразумеваете под «с момента его обработки»? Есть части кода внутри 'try {} catch' структур, однако, если встречается исключение, я записываю это в вывод logcat. Ни одно из этих предупреждений не отображается. – Sandy

+0

Посредством обработки я имел в виду то же самое, что и try и catch, и я думал, потому что одна часть вашего кода работает, а другая часть - нет. Попытайтесь немного изменить код, например, сначала нажмите уведомление, а затем попробуйте обработать изображение. –

+0

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

0

Это все, что у вас есть? Любые исключения или трассировки стека из «аварийного» сервиса?

Однако идея заключается в том, что вы загружаете изображения асинхронно и в обратном вызове, создавая уведомление?

Вы освобождаете замок в конце onHandleIntent, который вызывается до того, как будет выполнен любой асинхронный код. Освобождение блокировки бодрствования приведет к увольнению службы, если экран выключен.

Что вам нужно сделать, это условно освободить блокировку от следа в onHandleIntent, только если нет работы async. И в обратном вызове для любой асинхронной работы отпустите блокировку слежения. Просто убедитесь, что нет пути выполнения, который не освобождает блокировку слежения!

Надеюсь, что все!

+0

Привет @darnmason. Да, это все, что показано на логарифме. Никаких исключений и т.п. Поскольку onHandleIntent() не запускается в потоке пользовательского интерфейса, я не создаю никаких дополнительных потоков для загрузки или анализа изображения, поэтому все должно выполняться последовательно, а блокировка слежения - в конце. – Sandy

+0

Ах круто, странно, так что должен быть какой-то способ получить исключение, убивающее службу. Вы пробовали отлаживать и прерывать исключения? – darnmason

Смежные вопросы