C2DM广播意图提供ANR。怎么避免呢?

时间:2011-06-22 22:46:51

标签: android android-c2dm

我正在使用C2DM Tutorial中的教程,当我在我的应用程序中运行此代码时(我的应用程序有很多线程,我也运行此C2DMessaging.register(getApplicationContext(),SENDERS_EMAIL_ID);在另一个线程中

但是即使我在一个单独的线程上运行它之后我得到以下错误消息并且弹出一个ANR,我以为在我的背景中我看到我的应用程序开始完美!!!!

我启动C2DM.register(...)的方式是

            new Thread() {
                public void run() {
                    try{
                        C2DMessaging.register(getApplicationContext(), SENDERS_EMAIL_ID);

                    } catch (Exception e) {
                        Log.e(TAG, e.getMessage());
                    }
                }
            }.start();

我这样做的错误日志是

E/ActivityManager(  162): ANR in com.example.myapp
E/ActivityManager(  162): Reason: Broadcast of Intent { act=com.google.android.c2dm.intent.REGISTRATION cat=[com.example.myapp] flg=0x10 cmp=com.example.myapp/.c2dm.C2DMBroadcastReceiver (has extras) }
E/ActivityManager(  162): Load: 0.63 / 0.24 / 0.32
E/ActivityManager(  162): CPU usage from 5001ms to 0ms ago:
E/ActivityManager(  162):   98% 29787/com.example.myapp: 98% user + 0.4% kernel / faults: 2 minor
E/ActivityManager(  162):   1% 162/system_server: 0.4% user + 0.6% kernel / faults: 93 minor
E/ActivityManager(  162):   0.8% 127/sdcard: 0% user + 0.8% kernel
E/ActivityManager(  162):   0.6% 128/adbd: 0% user + 0.6% kernel / faults: 182 minor
E/ActivityManager(  162):   0.6% 224/dhd_dpc: 0% user + 0.6% kernel
E/ActivityManager(  162):   0.2% 240/com.android.phone: 0.2% user + 0% kernel
E/ActivityManager(  162):   0.2% 29429/kworker/u:3: 0% user + 0.2% kernel
E/ActivityManager(  162): 54% TOTAL: 49% user + 1.9% kernel + 2.1% iowait + 0.1% softirq
E/ActivityManager(  162): CPU usage from 525ms to 1057ms later with 99% awake:
E/ActivityManager(  162):   98% 29787/com.example.myapp: 96% user + 1.8% kernel
E/ActivityManager(  162):     96% 29787/com.example.myapp: 96% user + 0% kernel
E/ActivityManager(  162):   5.6% 162/system_server: 0% user + 5.6% kernel
E/ActivityManager(  162):     5.6% 172/ActivityManager: 1.8% user + 3.7% kernel
E/ActivityManager(  162):     1.8% 170/SensorService: 1.8% user + 0% kernel
E/ActivityManager(  162):   2.7% 127/sdcard: 0% user + 2.7% kernel
E/ActivityManager(  162):   2.7% 128/adbd: 0% user + 2.7% kernel / faults: 156 minor
E/ActivityManager(  162):     2.7% 128/adbd: 0% user + 2.7% kernel
E/ActivityManager(  162):     1.3% 11683/adbd: 0% user + 1.3% kernel
E/ActivityManager(  162):   1.3% 224/dhd_dpc: 0% user + 1.3% kernel

任何指针都会非常感激!

感谢。

C2DMBroadcastReceiver的代码是

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

/**
 * Helper class to handle BroadcastReciver behavior.
 * - can only run for a limited amount of time - it must start a real service 
 * for longer activity
 * - must get the power lock, must make sure it's released when all done.
 * 
 */
public class C2DMBroadcastReceiver extends BroadcastReceiver {

    @Override
    public final void onReceive(Context context, Intent intent) {
        // To keep things in one place.
        C2DMBaseReceiver.runIntentInService(context, intent);
        setResult(Activity.RESULT_OK, null /* data */, null /* extra */);        
    }
}

对于C2DMBaseReceiver来说是

import java.io.IOException;

import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.util.Log;

/**
 * Base class for C2D message receiver. Includes constants for the strings used
 * in the protocol.
 */
public abstract class C2DMBaseReceiver extends IntentService {
    private static final String C2DM_RETRY                  = "com.google.android.c2dm.intent.RETRY";
    public static final String REGISTRATION_CALLBACK_INTENT = "com.google.android.c2dm.intent.REGISTRATION";
    private static final String C2DM_INTENT                 = "com.google.android.c2dm.intent.RECEIVE";
    private static final String TAG                         = "MyApp";
    // Extras in the registration callback intents.
    public static final String EXTRA_UNREGISTERED           = "unregistered";
    public static final String EXTRA_ERROR                  = "error";
    public static final String EXTRA_REGISTRATION_ID        = "registration_id";

    public static final String ERR_SERVICE_NOT_AVAILABLE    = "SERVICE_NOT_AVAILABLE";
    public static final String ERR_ACCOUNT_MISSING          = "ACCOUNT_MISSING";
    public static final String ERR_AUTHENTICATION_FAILED    = "AUTHENTICATION_FAILED";
    public static final String ERR_TOO_MANY_REGISTRATIONS   = "TOO_MANY_REGISTRATIONS";
    public static final String ERR_INVALID_PARAMETERS       = "INVALID_PARAMETERS";
    public static final String ERR_INVALID_SENDER           = "INVALID_SENDER";
    public static final String ERR_PHONE_REGISTRATION_ERROR = "PHONE_REGISTRATION_ERROR";

    private static final String WAKELOCK_KEY                = "MyApp";

    private static PowerManager.WakeLock mWakeLock;
    private final String senderId;

    /**
     * The C2DMReceiver class must create a no-arg constructor and pass the
     * sender id to be used for registration.
     */
    public C2DMBaseReceiver(String senderId) {
        // senderId is used as base name for threads, etc.
        super(senderId);
        this.senderId = senderId;
    }

    /**
     * Called when a cloud message has been received.
     */
    protected abstract void onMessage(Context context, Intent intent);

    /**
     * Called on registration error. Override to provide better error messages.
     * 
     * This is called in the context of a Service - no dialog or UI.
     */
    public abstract void onError(Context context, String errorId);

    /**
     * Called when a registration token has been received.
     */
    public void onRegistered(Context context, String registrationId)
            throws IOException {
        // registrationId will also be saved
    }

    /**
     * Called when the device has been unregistered.
     */
    public void onUnregistered(Context context) {
    }

    @Override
    public final void onHandleIntent(Intent intent) {
        try {
            Context context = getApplicationContext();
            if (intent.getAction().equals(REGISTRATION_CALLBACK_INTENT)) {
                handleRegistration(context, intent);
            } else if (intent.getAction().equals(C2DM_INTENT)) {
                onMessage(context, intent);
            } else if (intent.getAction().equals(C2DM_RETRY)) {
                C2DMessaging.register(context, senderId);
            }
        } finally {
            // Release the power lock, so phone can get back to sleep.
            // The lock is reference counted by default, so multiple
            // messages are ok.

            // If the onMessage() needs to spawn a thread or do something else,
            // it should use it's own lock.
            mWakeLock.release();
        }
    }

    /**
     * Called from the broadcast receiver. Will process the received intent,
     * call handleMessage(), registered(), etc. in background threads, with a
     * wake lock, while keeping the service alive.
     */
    static void runIntentInService(Context context, Intent intent) {
        if (mWakeLock == null) {
            // This is called from BroadcastReceiver, there is no init.
            PowerManager pm = (PowerManager) context
                    .getSystemService(Context.POWER_SERVICE);
            mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                    WAKELOCK_KEY);
        }
        mWakeLock.acquire();

        // Use a naming convention, similar with how permissions and intents are
        // used. Alternatives are introspection or an ugly use of statics.
        String receiver = context.getPackageName() + ".c2dm.MyC2dmReceiver";
        intent.setClassName(context, receiver);

        context.startService(intent);

    }

    private void handleRegistration(final Context context, Intent intent) {
        final String registrationId = intent.getStringExtra(EXTRA_REGISTRATION_ID);
        String error = intent.getStringExtra(EXTRA_ERROR);
        String removed = intent.getStringExtra(EXTRA_UNREGISTERED);

        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "dmControl: registrationId = " + registrationId
                    + ", error = " + error + ", removed = " + removed);
        }

        if (removed != null) {
            // Remember we are unregistered
            C2DMessaging.clearRegistrationId(context);
            onUnregistered(context);
            return;
        } else if (error != null) {
            // we are not registered, can try again
            C2DMessaging.clearRegistrationId(context);
            // Registration failed
            Log.e(TAG, "Registration error " + error);
            onError(context, error);
            if ("SERVICE_NOT_AVAILABLE".equals(error)) {
                long backoffTimeMs = C2DMessaging.getBackoff(context);

                Log.d(TAG, "Scheduling registration retry, backoff = "
                        + backoffTimeMs);
                Intent retryIntent = new Intent(C2DM_RETRY);
                PendingIntent retryPIntent = PendingIntent
                        .getBroadcast(context, 0 /* requestCode */, retryIntent,
                                0 /* flags */);

                AlarmManager am = (AlarmManager) context
                        .getSystemService(Context.ALARM_SERVICE);
                am.set(AlarmManager.ELAPSED_REALTIME, backoffTimeMs,
                        retryPIntent);

                // Next retry should wait longer.
                backoffTimeMs *= 2;
                C2DMessaging.setBackoff(context, backoffTimeMs);
            }
        } else {
            try {
                onRegistered(context, registrationId);
                C2DMessaging.setRegistrationId(context, registrationId);
            } catch (IOException ex) {
                Log.e(TAG, "Registration error " + ex.getMessage());
            }
        }
    }
}

2 个答案:

答案 0 :(得分:0)

我认为问题不在于向谷歌发送注册信息,而是在C2DMBroadcastReceiver中从谷歌接收registration_id。 您是否在BroadcastReceiver中启动服务以进行注册处理? 请添加C2DMBroadcastReceiver的代码。

答案 1 :(得分:0)

您不应该使用C2DMessaging类,当然也不应该使用某个线程(顺便说一下,不要使用线程,使用带有回调或意图服务的异步任务)。

无论如何,由于C2DM已被弃用,您应该查看http://developer.android.com/guide/google/gcm/index.html

玩得开心:)