但是,当您卸载应用程序时,该应用程序的本地存储将从您的设备中删除,因此新安装将导致PushService.subscribe重新注册到Google Cloud Messaging.如果新注册返回一个新的注册ID,则Parse将具有两个注册ID,可用于向您的应用发送推送通知,并且这两个注册ID都将链接到您提供的用于订阅的同一用户名.因此,向该用户名发送通知会将其发送到两个注册ID,导致其到达两次. 当Parse为您发送通知时,他们应该从Google收到带有canonical_registration_id的响应,这将使他们知道与您设备上的应用相关联的注册ID较旧,因此不应再使用.因此(假设Parse在GCM上有不错的实现),下次您将通知发送到设备时,您应该只收到一次通知."这是我的安装源代码:String androidId = Secure.getString(getApplicationContext().getContentResolver(),Secure.ANDROID_ID);Parse.initialize(this, "KEY1", "KEY2");PushService.setDefaultPushCallback(this, ParseActivity.class);ParseInstallation installation = ParseInstallation.getCurrentInstallation();installation.put("UniqueId",androidId);installation.setObjectId(null);installation.saveInBackground();我的堆栈跟踪记录(像所有人一样):05-20 19:47:35.630: E/ParseCommandCache(6497): com.parse.ParseException: at least one ID field (installationId,deviceToken) must be specified in this operation05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.ParseCommand.onPostExecute(ParseCommand.java:334)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.ParseRequest$5.then(ParseRequest.java:321)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.ParseRequest$5.then(ParseRequest.java:318)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11.run(Task.java:481)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$ImmediateExecutor.execute(Task.java:673)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.completeAfterTask(Task.java:477)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.continueWithTask(Task.java:353)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.continueWithTask(Task.java:364)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$9.then(Task.java:410)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$9.then(Task.java:402)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11.run(Task.java:481)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$ImmediateExecutor.execute(Task.java:673)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.completeAfterTask(Task.java:477)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$400(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$7.then(Task.java:346)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$7.then(Task.java:343)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.runContinuations(Task.java:510)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$800(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.trySetResult(Task.java:565)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.setResult(Task.java:599)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:493)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:485)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$10.run(Task.java:448)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$ImmediateExecutor.execute(Task.java:673)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.completeImmediately(Task.java:444)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$300(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$6.then(Task.java:311)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$6.then(Task.java:308)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.runContinuations(Task.java:510)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$800(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.trySetResult(Task.java:565)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.setResult(Task.java:599)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:493)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:485)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$10.run(Task.java:448)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$ImmediateExecutor.execute(Task.java:673)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.completeImmediately(Task.java:444)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$300(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$6.then(Task.java:311)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$6.then(Task.java:308)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.runContinuations(Task.java:510)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$800(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.trySetResult(Task.java:565)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.setResult(Task.java:599)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:493)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:485)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$10.run(Task.java:448)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$ImmediateExecutor.execute(Task.java:673)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.completeImmediately(Task.java:444)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.continueWith(Task.java:318)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.continueWith(Task.java:329)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11.run(Task.java:485)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$ImmediateExecutor.execute(Task.java:673)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.completeAfterTask(Task.java:477)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$400(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$7.then(Task.java:346)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$7.then(Task.java:343)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.runContinuations(Task.java:510)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$800(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.trySetResult(Task.java:565)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.setResult(Task.java:599)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:493)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:485)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$10.run(Task.java:448)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$ImmediateExecutor.execute(Task.java:673)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.completeImmediately(Task.java:444)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.continueWith(Task.java:318)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.continueWith(Task.java:329)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11.run(Task.java:485)05-20 19:47:35.630: E/ParseCommandCache(6497): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)05-20 19:47:35.630: E/ParseCommandCache(6497): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)05-20 19:47:35.630: E/ParseCommandCache(6497): at java.lang.Thread.run(Thread.java:841)05-20 19:48:32.615: D/Request(6497): Warning: Sessionless Request needs token but missing either application ID or client token.由于我没有找到任何真正的解决方案,所以我在这里问.谢谢.解决方案出现了完全相同的问题.我通过转到手机上的设置->应用程序-> 您的应用程序名称->强制关机->卸载来解决它.然后在Android Studio中,我去了->文件->使缓存无效/重新启动->等待gradle再次生成,然后在手机上运行该应用程序.像魅力一样工作. It's simple, when you use parse for the first time on your mobile it works like a charm.When you reinstall your application, it screws everything.As stated on stackoverflow by Eran:"PushService.subscribe seems to cache the subscription in local storage, to avoid re-subscribing when you launch the app multiple times.This is what the first parameter of that method is used for :context - This is used to access local storage to cache the subscription, so it must currently be a viable context.(quote from here).However, when you uninstall the app, local storage for that app is wiped from your device, so the new installation will cause PushService.subscribe to re-register to Google Cloud Messaging. If the new registration returns a new registration ID, Parse would have two registration IDs that can be used to send push notifications to your app, and both of them would be linked to the same userName you supplied to subscribe. Therefore sending a notification to that userName will send it to both registration IDs, causing it to arrive twice.When Parse send the notifications for you, they should get from Google a response with canonical_registration_id, which will let them know one of the registration IDs associated with your app on your device is old, and should not be used anymore. Therefore (assuming Parse have a decent implementation of GCM) the next time you send a notification to your device, you should receive it only once."Here is my source code for the installation:String androidId = Secure.getString(getApplicationContext().getContentResolver(),Secure.ANDROID_ID);Parse.initialize(this, "KEY1", "KEY2");PushService.setDefaultPushCallback(this, ParseActivity.class);ParseInstallation installation = ParseInstallation.getCurrentInstallation();installation.put("UniqueId",androidId);installation.setObjectId(null);installation.saveInBackground();My stacktrace (like everyones):05-20 19:47:35.630: E/ParseCommandCache(6497): com.parse.ParseException: at least one ID field (installationId,deviceToken) must be specified in this operation05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.ParseCommand.onPostExecute(ParseCommand.java:334)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.ParseRequest$5.then(ParseRequest.java:321)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.ParseRequest$5.then(ParseRequest.java:318)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11.run(Task.java:481)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$ImmediateExecutor.execute(Task.java:673)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.completeAfterTask(Task.java:477)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.continueWithTask(Task.java:353)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.continueWithTask(Task.java:364)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$9.then(Task.java:410)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$9.then(Task.java:402)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11.run(Task.java:481)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$ImmediateExecutor.execute(Task.java:673)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.completeAfterTask(Task.java:477)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$400(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$7.then(Task.java:346)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$7.then(Task.java:343)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.runContinuations(Task.java:510)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$800(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.trySetResult(Task.java:565)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.setResult(Task.java:599)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:493)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:485)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$10.run(Task.java:448)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$ImmediateExecutor.execute(Task.java:673)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.completeImmediately(Task.java:444)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$300(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$6.then(Task.java:311)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$6.then(Task.java:308)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.runContinuations(Task.java:510)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$800(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.trySetResult(Task.java:565)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.setResult(Task.java:599)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:493)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:485)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$10.run(Task.java:448)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$ImmediateExecutor.execute(Task.java:673)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.completeImmediately(Task.java:444)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$300(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$6.then(Task.java:311)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$6.then(Task.java:308)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.runContinuations(Task.java:510)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$800(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.trySetResult(Task.java:565)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.setResult(Task.java:599)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:493)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:485)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$10.run(Task.java:448)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$ImmediateExecutor.execute(Task.java:673)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.completeImmediately(Task.java:444)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.continueWith(Task.java:318)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.continueWith(Task.java:329)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11.run(Task.java:485)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$ImmediateExecutor.execute(Task.java:673)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.completeAfterTask(Task.java:477)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$400(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$7.then(Task.java:346)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$7.then(Task.java:343)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.runContinuations(Task.java:510)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.access$800(Task.java:22)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.trySetResult(Task.java:565)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$TaskCompletionSource.setResult(Task.java:599)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:493)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11$1.then(Task.java:485)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$10.run(Task.java:448)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$ImmediateExecutor.execute(Task.java:673)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.completeImmediately(Task.java:444)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.continueWith(Task.java:318)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task.continueWith(Task.java:329)05-20 19:47:35.630: E/ParseCommandCache(6497): at com.parse.Task$11.run(Task.java:485)05-20 19:47:35.630: E/ParseCommandCache(6497): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)05-20 19:47:35.630: E/ParseCommandCache(6497): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)05-20 19:47:35.630: E/ParseCommandCache(6497): at java.lang.Thread.run(Thread.java:841)05-20 19:48:32.615: D/Request(6497): Warning: Sessionless Request needs token but missing either application ID or client token.Since I've not found any real solution, I'm asking here.Thanks. 解决方案 Had the exact same problem. I solved it by going to settings on my phone -> Apps -> your application name -> Force shutdown -> Uninstall.Then in Android studio I went -> File -> Invalidate Caches / Restart -> Wait for the gradle to build again and then run the Application on my phone. Worked like a charm. 这篇关于“必须在此操作中指定至少一个ID字段(installationId,deviceToken)".解析的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
08-05 11:58
查看更多