BroadcastReceiver 试图 return 在无序广播期间产生奇怪的错误
BroadcastReceiver trying to return result during a non-ordered broadcast Weird Error
即使我没有发送推送通知,首次启动应用程序时也会出现此错误:
BroadcastReceiver trying to return result during a non-ordered broadcast
java.lang.RuntimeException: BroadcastReceiver trying to return result during a non-ordered broadcast
at android.content.BroadcastReceiver.checkSynchronousHint(BroadcastReceiver.java:799)
at android.content.BroadcastReceiver.setResultCode(BroadcastReceiver.java:565)
at com.pushnotification.GcmBroadcastReceiver.onReceive(GcmBroadcastReceiver.java:17)
at android.app.ActivityThread.handleReceiver(ActivityThread.java:2712)
at android.app.ActivityThread.access00(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1449)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5696)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
BroadcastReceiver 的代码:
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 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)));
/* the crash is pointing to this line */
setResultCode(Activity.RESULT_OK);
}
}
在 IntentService 中实现以下代码后,错误开始出现(也没有在应用程序启动时调用)。但也不是每次,I.E.卸载 运行 来自 Android Studio 的应用程序后,有时会出现错误,有时不会。
BroadcastReceiver receiver;
public void DownloadListener(final String ZipFile) {
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(downloadReference);
Cursor c = downloadManager.query(query);
if (c.moveToFirst()) {
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {
DismissProgressDialog();
ShowProgress("Almost Done", "Unzipping And Installing Database", pd.STYLE_SPINNER);
}
}
}
}
};
context.registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
清单中:
<receiver
android:name="com.pushnotification.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.geovision.ffmsnativeprototype" />
</intent-filter>
</receiver>
<service android:name=".WebServiceCommunication.SystemDatabaseService" />
按照 another question 的答案的建议注释掉 setResultCode(Activity.RESULT_OK);
行后,推送通知的 IntentService 收到了包含此内容的通知
From-google.com/iid-Title-null-Message-null-ExtraData-null
我的情况和
一样
根据回答
这是一个 google 相关的功能,没什么大不了的,可以通过编程方式进行过滤。
@Override
protected void onHandleIntent(Intent intent) //RECEIVE THE PUSHNOTIFICATION
{
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)) {
// 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)) {
Log.i(TAG, "PUSHNOTIFICATION RECEIVED @ " + SystemClock.elapsedRealtime());
extraData=extras.getString("extraData");
from=extras.getString("from");
title=extras.getString("title");
message=extras.getString("message");
Log.i(TAG, "Received: " + extras.toString()+" M"+messageType);
if(title!=null) {
if(from.equals("google.com/iid"))
{
//related to google ... DO NOT PERFORM ANY ACTION
}
else {
//HANDLE THE RECEIVED NOTIFICATION
}
这里的根本问题是 GCM API 已经改变。如 OP 所示,您 可以 简单地过滤掉这个新意图,但这样做 您将错过令牌刷新通知 。
来自更新后的 GCM sample code。
AndroidManifest.xml
<service
android:name=".MyInstanceIdListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID"/>
</intent-filter>
</service>
MyInstanceIdListenerService.java
public class MyInstanceIDListenerService extends InstanceIDListenerService {
private static final String TAG = "MyInstanceIDLS";
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. This call is initiated by the
* InstanceID provider.
*/
// [START refresh_token]
@Override
public void onTokenRefresh() {
// Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
// [END refresh_token]
}
解决此问题的正确方法是针对新的 API 更新您的实现,如更新的 GCM API docs 中所述。
For existing apps that extend a WakefulBroadcastReceiver, Google
recommends migrating to GCMReceiver and GcmListenerService. To
migrate:
In the app manifest, replace your GcmBroadcastReceiver with
"com.google.android.gms.gcm.GcmReceiver", and replace the current
service declaration that extends IntentService to the new
GcmListenerService
Remove the BroadcastReceiver implementation from your client code
Refactor the current IntentService service implementation to use
GcmListenerService
For details, see the example manifest and code samples in this page.
我已经发布了一个相关问题的答案,其中提取了从旧实现中更新所需的所有相关代码 。
即使我没有发送推送通知,首次启动应用程序时也会出现此错误:
BroadcastReceiver trying to return result during a non-ordered broadcast
java.lang.RuntimeException: BroadcastReceiver trying to return result during a non-ordered broadcast
at android.content.BroadcastReceiver.checkSynchronousHint(BroadcastReceiver.java:799)
at android.content.BroadcastReceiver.setResultCode(BroadcastReceiver.java:565)
at com.pushnotification.GcmBroadcastReceiver.onReceive(GcmBroadcastReceiver.java:17)
at android.app.ActivityThread.handleReceiver(ActivityThread.java:2712)
at android.app.ActivityThread.access00(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1449)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5696)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
BroadcastReceiver 的代码:
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 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)));
/* the crash is pointing to this line */
setResultCode(Activity.RESULT_OK);
}
}
在 IntentService 中实现以下代码后,错误开始出现(也没有在应用程序启动时调用)。但也不是每次,I.E.卸载 运行 来自 Android Studio 的应用程序后,有时会出现错误,有时不会。
BroadcastReceiver receiver;
public void DownloadListener(final String ZipFile) {
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(downloadReference);
Cursor c = downloadManager.query(query);
if (c.moveToFirst()) {
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {
DismissProgressDialog();
ShowProgress("Almost Done", "Unzipping And Installing Database", pd.STYLE_SPINNER);
}
}
}
}
};
context.registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
清单中:
<receiver
android:name="com.pushnotification.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.geovision.ffmsnativeprototype" />
</intent-filter>
</receiver>
<service android:name=".WebServiceCommunication.SystemDatabaseService" />
按照 another question 的答案的建议注释掉 setResultCode(Activity.RESULT_OK);
行后,推送通知的 IntentService 收到了包含此内容的通知
From-google.com/iid-Title-null-Message-null-ExtraData-null
我的情况和
根据回答
这是一个 google 相关的功能,没什么大不了的,可以通过编程方式进行过滤。
@Override
protected void onHandleIntent(Intent intent) //RECEIVE THE PUSHNOTIFICATION
{
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)) {
// 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)) {
Log.i(TAG, "PUSHNOTIFICATION RECEIVED @ " + SystemClock.elapsedRealtime());
extraData=extras.getString("extraData");
from=extras.getString("from");
title=extras.getString("title");
message=extras.getString("message");
Log.i(TAG, "Received: " + extras.toString()+" M"+messageType);
if(title!=null) {
if(from.equals("google.com/iid")) { //related to google ... DO NOT PERFORM ANY ACTION } else { //HANDLE THE RECEIVED NOTIFICATION }
这里的根本问题是 GCM API 已经改变。如 OP 所示,您 可以 简单地过滤掉这个新意图,但这样做 您将错过令牌刷新通知 。
来自更新后的 GCM sample code。
AndroidManifest.xml
<service
android:name=".MyInstanceIdListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID"/>
</intent-filter>
</service>
MyInstanceIdListenerService.java
public class MyInstanceIDListenerService extends InstanceIDListenerService {
private static final String TAG = "MyInstanceIDLS";
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. This call is initiated by the
* InstanceID provider.
*/
// [START refresh_token]
@Override
public void onTokenRefresh() {
// Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
// [END refresh_token]
}
解决此问题的正确方法是针对新的 API 更新您的实现,如更新的 GCM API docs 中所述。
For existing apps that extend a WakefulBroadcastReceiver, Google recommends migrating to GCMReceiver and GcmListenerService. To migrate:
In the app manifest, replace your GcmBroadcastReceiver with "com.google.android.gms.gcm.GcmReceiver", and replace the current service declaration that extends IntentService to the new GcmListenerService
Remove the BroadcastReceiver implementation from your client code
Refactor the current IntentService service implementation to use GcmListenerService
For details, see the example manifest and code samples in this page.
我已经发布了一个相关问题的答案,其中提取了从旧实现中更新所需的所有相关代码