3

我正在使用 GCM 在发布图像时收到通知,然后我下载并处理它:

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 后退按钮,直到我不再在应用程序中。我可以按照显示图像已下载的日志消息进行操作,但是在显示通知之前它就死了。

这并不总是发生。有时会显示通知,有时不会。

我不确定可能的原因是什么,也不知道如何调试。有小费吗?

4

3 回答 3

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

编辑:在GCM 这里添加有用的 youtube 教程。

于 2015-01-15T23:59:04.207 回答
0

抱歉,我正在使用答案(我还不能发表评论)。

我会尝试在 processNewWallpaper() 之后提取从 processNewWallpaper 对 sendNotification 的调用。如果这不起作用,您应该在 processNewWallpaper() 中发布您的代码。我的猜测是,在某些情况下,您的代码在 processNewWallpaper 内崩溃并跳过 sendNotification 但由于它正在处理它不会抛出任何东西。

我还注意到,如果应用程序在后台打开或完全关闭(使用正在运行的应用程序键并在那里关闭您的应用程序),它们的行为会有所不同。如果您可以始终如一地重现该问题,则解决该问题将更容易。

于 2015-01-23T01:23:35.667 回答
0

这就是你所有的logcat吗?“崩溃”服务的任何异常或堆栈跟踪?

但是,一个想法,您是在异步下载图像并在回调中创建通知吗?

您正在释放唤醒锁,在onHandleIntent执行任何异步代码之前将调用该唤醒锁。如果屏幕关闭,释放唤醒锁将终止服务。

您需要做的是onHandleIntent仅在不需要执行异步工作时有条件地释放唤醒锁。并在任何异步工作的回调中释放唤醒锁。只要确保没有不释放唤醒锁的执行路径!

希望就是这样!

于 2015-01-23T01:41:47.273 回答