【问题标题】:Android GCM Intent Service got stuck at Releasing WakelockAndroid GCM Intent 服务卡在释放唤醒锁上
【发布时间】:2015-03-23 08:31:53
【问题描述】:

我正在使用 GCM 为我的项目推送通知,但我无法释放唤醒锁。我正在使用来自 android hive 的 GCM 代码。

下面是我的清单文件。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.estorm.filingotp"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="18" />

<uses-permission android:name="android.permission.INTERNET"/>  
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>  
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.GET_TASKS"/>
 <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<permission
    android:name="com.estorm.filingotp.C2D_MESSAGE"
    android:protectionLevel="signature" />

<uses-permission android:name="com.estorm.filingotp.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<permission
    android:name="com.estorm.filingotp.permission.C2D_MESSAGE"
    android:protectionLevel="signature" />

<uses-permission android:name="com.estorm.filingotp.permission.C2D_MESSAGE" />

 <application
    android:allowBackup="true"
    android:icon="@drawable/otp_appicon"
    android:label="@string/app_name"
    android:theme="@android:style/Theme.Light.NoTitleBar" >

      <receiver
        android:name="com.google.android.gcm.GCMBroadcastReceiver"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

            <category android:name="com.estorm.filingotp" />
        </intent-filter>
    </receiver>

    <service android:name=".GCMIntentService" />

我推得很好,但 logcat 卡在 Releasing Wavelock 上。而且我在应用启动时没有使用 GCM。我在应用程序中间调用 GCM。我调用 GCM 和 GCM Intent Service 的类都在相同的包名下。 我的应用有很多包,比如 Packagename.constants、Packagename.utils 等。

请帮助我。我在这上面卡了 2 天。

这是我的 GCM Intent 服务代码

    package com.estorm.filingotp;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.estorm.filingotp.constants.Globals;
import com.google.android.gcm.GCMBaseIntentService;

public class GCMIntentService extends GCMBaseIntentService {

    private static final String TAG = "Test";
    public static final String SENDER_ID = "401189754081";
    public static final String DISPLAY_MESSAGE_ACTION = "com.estorm.filingotp.OTPLogon";
    public static final String EXTRA_MESSAGE = "message";

    Context ctx;
    public GCMIntentService() {
        super(GCMIntentService.SENDER_ID);
    }

    @Override
    protected void onRegistered(Context context, final String registrationId) {

        Log.v("", "Device registered: PUSHId = " + registrationId);


    }

    @Override
    protected void onUnregistered(Context context, String registrationId) {
        Log.i(TAG, "Device unregistered");
        // CommonUtilities.displayMessage(context,
        // getString(R.string.gcm_unregistered));
        // if (GCMRegistrar.isRegisteredOnServer(context)) {
        // ServerUtilities.unregister(context, registrationId);
        // } else {
        // Log.i(TAG, "Ignoring unregister callback");
        // }
    }

    @Override
    protected void onMessage(Context context, Intent intent) {
        Log.v("", "Received message");
        Log.v("", "message is" + intent.getExtras().getString("message"));
        ctx = context;
        String other_key = intent.getExtras().getString("message");
        Globals.IPtoken=other_key;
        generateNotification(context, other_key);
    }


    @Override
    protected void onDeletedMessages(Context context, int total) {
        Log.i(TAG, "Received deleted messages notification");
        // String message = getString(R.string.gcm_deleted, total);
        // CommonUtilities.displayMessage(context, message);
        // generateNotification(context, message);
    }

    @Override
    public void onError(Context context, String errorId) {
        Log.i(TAG, "Received error: " + errorId);
        // CommonUtilities.displayMessage(context, getString(R.string.gcm_error,
        // errorId));
    }

    @Override
    protected boolean onRecoverableError(Context context, String errorId) {
        Log.i(TAG, "Received recoverable error: " + errorId);
        // CommonUtilities.displayMessage(context,
        // getString(R.string.gcm_recoverable_error, errorId));
        return super.onRecoverableError(context, errorId);
    }

    @SuppressWarnings("deprecation")
    private static void generateNotification(Context context, String message) {
        int icon = R.drawable.otp_appicon;
        long when = System.currentTimeMillis();
        NotificationManager notificationManager = (NotificationManager) context
                .getSystemService(Context.NOTIFICATION_SERVICE);
        Notification notification = new Notification(icon, message, when);
        String title = context.getString(R.string.app_name);
        Intent notificationIntent = new Intent(context, OTPLogon.class);
        notificationIntent.putExtra("message", message);

        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
                | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent intent = PendingIntent.getActivity(context, 0,
                notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        notification.setLatestEventInfo(context, message,
                message, intent);

        notification.defaults = Notification.DEFAULT_ALL;
        notification.flags |= Notification.FLAG_AUTO_CANCEL;
        notificationManager.notify(0, notification);

    }
    }

我使用以下代码在我的 Activity 类中调用 GCM

    private void gcm(final Context context) {
        GCMRegistrar.checkDevice(context);
        GCMRegistrar.checkManifest(context);

    registerReceiver(mHandleMessageReceiver, new IntentFilter(
            GCMIntentService.DISPLAY_MESSAGE_ACTION));
    Globals.RegistrationId = GCMRegistrar.getRegistrationId(context);
    Log.v("","reg uid is"+Globals.RegistrationId);

    if (Globals.RegistrationId.equals("")) {

        GCMRegistrar.register(context, GCMIntentService.SENDER_ID);

    } else {
        if (GCMRegistrar.isRegisteredOnServer(context)) {
            Log.v("", "GCM Display Message : "
                    + "Already registered");
        }
    }

}
private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
//      String newMessage = intent.getExtras().getString(
//              GCMIntentService.EXTRA_MESSAGE);
        Log.v("", "broadcast done");
        new Apiconnector().execute();
    }
};

【问题讨论】:

  • 当 LogCat 发现您的错误时,您能否发布处理传入意图的代码以及堆栈跟踪?
  • 你所有的 GCM 类都在主包里吗??
  • 是的,都在主包@sur007
  • 您能发布您的 GCM 课程代码吗?
  • 您正在使用已弃用的 API (GCMBaseIntentService)。尝试按照本教程进行操作,一切都应该按照您的预期工作developer.android.com/google/gcm/client.html

标签: android google-cloud-messaging


【解决方案1】:

你可以这样做: 通过 Intent 服务扩展 GCMIntentService

public class GcmIntentService extends IntentService{
Context context;
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
public static final String TAG = "GCM Demo";

public GcmIntentService() {
    super("GcmIntentService");
    // TODO Auto-generated constructor stub
}

@Override
protected void onHandleIntent(Intent intent) {
    // TODO Auto-generated method stub
    Bundle extras = intent.getExtras();
    String msg = intent.getStringExtra("message");
    GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
    String messageType = gcm.getMessageType(intent);

     if (!extras.isEmpty()) {

         if (GoogleCloudMessaging.
                    MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
                sendNotification("Send error: " + extras.toString());
            } else if (GoogleCloudMessaging.
                    MESSAGE_TYPE_DELETED.equals(messageType)) {
                sendNotification("Deleted messages on server: " +
                        extras.toString());
            // If it's a regular GCM message, do some work.
            } else if (GoogleCloudMessaging.
                    MESSAGE_TYPE_MESSAGE.equals(messageType)) {
                // This loop represents the service doing some work.
                for (int i=0; i<5; i++) {
                    Log.i(TAG, "Working... " + (i+1)
                            + "/5 @ " + SystemClock.elapsedRealtime());
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                    }
                }
                Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());
                // Post notification of received message.
                //sendNotification("Received: " + extras.toString());
                sendNotification(msg);
                Log.i(TAG, "Received: " + extras.toString());
            }
        }
     GcmBroadcastReceiver.completeWakefulIntent(intent);
}
private void sendNotification(String msg) {
    mNotificationManager = (NotificationManager)
            this.getSystemService(Context.NOTIFICATION_SERVICE);

    Intent myintent = new Intent(this, ReceiveActivity.class);
    myintent.putExtra("message", msg);
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
            myintent, PendingIntent.FLAG_UPDATE_CURRENT);

    NotificationCompat.Builder mBuilder =
            new NotificationCompat.Builder(this)
    .setSmallIcon(R.drawable.ic_stat_gcm)
    .setContentTitle("GCM Notification")
    .setStyle(new NotificationCompat.BigTextStyle()
    .bigText(msg))
    .setContentText(msg);

    mBuilder.setContentIntent(contentIntent);
    mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    mNotificationManager.cancel(NOTIFICATION_ID);
}

}

GCMBroadCastReceiver 看起来像

public class GcmBroadcastReceiver extends WakefulBroadcastReceiver{

@Override
public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub

    // 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);


}

}

我查看了这个tutorial。希望对你有帮助

【讨论】:

    【解决方案2】:

    您必须使用 completeWakefulIntent(intent) 来释放唤醒锁。您必须将意图作为参数传递,这与 WakefulBroadcastReceiver 最初传入的意图相同。

    这里是示例代码:

    import android.app.IntentService;
    import android.content.Intent;
    import android.os.SystemClock;
    import android.util.Log;
    
    public class SimpleWakefulService extends IntentService {
        public SimpleWakefulService() {
            super("SimpleWakefulService");
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            // At this point SimpleWakefulReceiver is still holding a wake lock
            // for us.  We can do whatever we need to here and then tell it that
            // it can release the wakelock.  This sample just does some slow work,
            // but more complicated implementations could take their own wake
            // lock here before releasing the receiver's.
            //
            // Note that when using this approach you should be aware that if your
            // service gets killed and restarted while in the middle of such work
            // (so the Intent gets re-delivered to perform the work again), it will
            // at that point no longer be holding a wake lock since we are depending
            // on SimpleWakefulReceiver to that for us.  If this is a concern, you can
            // acquire a separate wake lock here.
            for (int i=0; i<5; i++) {
                Log.i("SimpleWakefulReceiver", "Running service " + (i+1)
                        + "/5 @ " + SystemClock.elapsedRealtime());
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                }
            }
            Log.i("SimpleWakefulReceiver", "Completed service @ " + SystemClock.elapsedRealtime());
            SimpleWakefulReceiver.completeWakefulIntent(intent);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-16
      • 1970-01-01
      相关资源
      最近更新 更多