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消息是下載一個圖像的代碼做什麼,那麼就說明該用戶的通知(這類似於一個正常的聊天應用程序)。

一個測試人員告訴我,一旦他收到一張圖片,但沒有收到通知,這意味着服務本身已經開始並完成部分工作,但並未完成。

通知代碼在processNewWallpaper()中運行,以及圖像的下載和處理。下面的代碼:

... 

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(intent)釋放喚醒鎖定;? –

回答

1

您是否在GcmIntentService類中調用OnCreate()

一些示例代碼如下:

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(); 
      } 
     }); 
    } 
} 

編輯:添加有用的YouTube教程GCMhere

+0

我不這樣做,但它只包含'super.onCreate();'。它仍然需要嗎? – Sandy

+0

我添加了以下內容,但我仍然收到相同的消息。 '@Override public void onCreate() { super.onCreate(); }' – Sandy

+0

我沒有初始化mHandler = new Handler();謝謝 – saqibahmad

0

對不起,我正在使用答案(我還不能評論)。

我會嘗試從processNewWallpaper提取調用sendNotification到processNewWallpaper()之後。如果這不起作用,你應該在processNewWallpaper()中發佈你的代碼。我的猜測是,在某些情況下,你的代碼會在processNewWallpaper中崩潰,並跳過sendNotification,但是由於它的處理不會拋出任何東西。

另外我注意到,如果應用程序在後臺打開或完全關閉(使用正在運行的應用程序密鑰並關閉應用程序),則應用程序的行爲會有所不同。如果您始終能夠重現問題,那麼解決問題將更容易。

+0

Hi @kayvan。 「自處理以來」是什麼意思?在try {} catch'結構中有部分代碼,但是如果遇到異常,我將它記錄到logcat輸出中。沒有顯示這些警告。 – Sandy

+0

通過被處理,我的意思與嘗試和捕捉相同,我想到因爲你的代碼的一部分工作,其他部分不是。嘗試移動你的代碼有點像先推送通知,然後嘗試處理圖像。 –

+0

我記錄任何時候遇到和捕獲到的異常,廣告日誌中沒有消息。我可以移動通知,但是我可能會遇到通知發生但圖像處理失敗的問題。我寧願保存圖像,而不是通知其他方式。 – Sandy

0

這是你所有的logcat嗎?來自「崩潰」服務的任何異常或堆棧跟蹤?

然而,一個想法,你是否異步下載圖像,並在創建通知回調?

您正在釋放在onHandleIntent末尾的喚醒鎖,它將在任何異步代碼執行之前調用。如果屏幕關閉,則釋放喚醒鎖將終止服務。

您需要做的僅僅是在沒有異步工作需要完成時有條件地釋放onHandleIntent中的喚醒鎖。並且在任何異步工作的回調中釋放喚醒鎖。只要確保沒有執行路徑不會釋放喚醒鎖!

希望就是這樣!

+0

Hi @darnmason。是的,這就是logcat上顯示的全部內容。沒有例外通知或類似的通知。由於onHandleIntent()不在UI線程中運行,因此我不會創建任何其他線程來下載或解析圖像,因此應該按順序執行所有操作,並在最後釋放喚醒鎖。 – Sandy

+0

很酷,奇怪的一個,所以,必須有某種方式來解決導致服務中斷的異常。您是否嘗試過調試並打破異常? – darnmason