Android 提供ANR的C2DM广播意图。如何避免呢?

Android 提供ANR的C2DM广播意图。如何避免呢?,android,android-c2dm,Android,Android C2dm,当我在我的应用程序中运行此代码时(我的应用程序有许多线程,并且我在另一个线程中运行此C2DMessaging.register(getApplicationContext(),SENDERS\u EMAIL\u ID)),我正在使用教程 但即使在我在一个单独的线程上运行了这个程序,我仍然会收到下面的错误消息,并弹出一个ANR,我想我在后台看到我的应用程序启动得非常完美 我启动C2DM.register(…)的方法是 我执行此操作时得到的错误日志是 E/ActivityManager( 162)

当我在我的应用程序中运行此代码时(我的应用程序有许多线程,并且我在另一个线程中运行此C2DMessaging.register(getApplicationContext(),SENDERS\u EMAIL\u ID)),我正在使用教程

但即使在我在一个单独的线程上运行了这个程序,我仍然会收到下面的错误消息,并弹出一个ANR,我想我在后台看到我的应用程序启动得非常完美

我启动C2DM.register(…)的方法是

我执行此操作时得到的错误日志是

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

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

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

不管怎样,既然C2DM已经被弃用,您应该看看


玩得开心:)

另外,我想指出的是,我确实成功地收到了id,并将regId发布到了服务器上。很遗憾,在这里遇到了同样的问题,它没有停止。
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());
            }
        }
    }
}