【问题标题】:Mobile Backend handle continuous queries in background移动后端在后台处理连续查询
【发布时间】:2013-07-02 17:41:38
【问题描述】:

我在我的应用程序中使用 Mobile Backend Starter,并且我能够使用此代码连续接收数据:

CloudCallbackHandler<List<CloudEntity>> handler = new CloudCallbackHandler<List<CloudEntity>>() {
        @Override
        public void onComplete(List<CloudEntity> results) {
            Logger.log(MainActivity.this, "onComplete");
        }

        @Override
        public void onError(IOException e) {
            Logger.log(MainActivity.this, e);
        }
    };

    CloudQuery cq = new CloudQuery("Test");
    cq.setLimit(50);
    cq.setSort(CloudEntity.PROP_UPDATED_AT, Order.DESC);
    cq.setScope(Scope.FUTURE_AND_PAST);
    getCloudBackend().list(cq, handler);

当我的应用程序处于活动状态时,这一切正常,但我想用它来通知用户新数据可用,当应用程序处于活动状态时。

当我关闭应用程序(通过按返回,而不是按主页)并强制向我的设备发送消息时,我收到以下错误:

07-04 18:30:23.084: I/CloudBackend(31368): error: 
07-04 18:30:23.084: I/CloudBackend(31368): com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException
07-04 18:30:23.084: I/CloudBackend(31368):  at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential$RequestHandler.intercept(GoogleAccountCredential.java:222)
07-04 18:30:23.084: I/CloudBackend(31368):  at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:836)
07-04 18:30:23.084: I/CloudBackend(31368):  at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:412)
07-04 18:30:23.084: I/CloudBackend(31368):  at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:345)
07-04 18:30:23.084: I/CloudBackend(31368):  at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:463)
07-04 18:30:23.084: I/CloudBackend(31368):  at com.myapp.cloudbackend.CloudBackend.list(CloudBackend.java:340)
07-04 18:30:23.084: I/CloudBackend(31368):  at com.myapp.cloudbackend.CloudBackendAsync.access$8(CloudBackendAsync.java:1)
07-04 18:30:23.084: I/CloudBackend(31368):  at com.myapp.cloudbackend.CloudBackendAsync$9.callBackend(CloudBackendAsync.java:283)
07-04 18:30:23.084: I/CloudBackend(31368):  at com.myapp.cloudbackend.CloudBackendAsync$9.callBackend(CloudBackendAsync.java:1)
07-04 18:30:23.084: I/CloudBackend(31368):  at com.myapp.cloudbackend.CloudBackendAsync$BackendCaller.run(CloudBackendAsync.java:429)
07-04 18:30:23.084: I/CloudBackend(31368): Caused by: com.google.android.gms.auth.UserRecoverableAuthException: AppDownloadRequired
07-04 18:30:23.084: I/CloudBackend(31368):  at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source)
07-04 18:30:23.084: I/CloudBackend(31368):  at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source)
07-04 18:30:23.084: I/CloudBackend(31368):  at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential.getToken(GoogleAccountCredential.java:192)
07-04 18:30:23.084: I/CloudBackend(31368):  at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential$RequestHandler.intercept(GoogleAccountCredential.java:217)
07-04 18:30:23.084: I/CloudBackend(31368):  ... 9 more

我怎样才能实现我想要的?

【问题讨论】:

    标签: android google-app-engine google-cloud-messaging google-cloud-endpoints


    【解决方案1】:

    我没有玩过 Mobile Backend Starter,但您的问题听起来像是您想实现 Service 并在服务中使用云后端。因此,您可以在您的应用程序未激活时建立通信。这是good tutorial

    【讨论】:

      【解决方案2】:

      这可能在 Activity 中,因此当您关闭应用程序时,应用程序管理器将销毁它。所以最好的办法是使用服务。您可以在 OnServiceConnected 方法中从 Service 获取数据。您也可以从服务中触发通知!

      【讨论】:

        【解决方案3】:

        可能最好使用的是来自 Google 的 Service http://developer.android.com/reference/android/app/Service.html 或 GCM 库 http://developer.android.com/guide/google/gcm/gs.html。它可以向您的 Android 设备发送推送通知,从而强制您的设备执行某些操作。用于同步数据。

        【讨论】:

          【解决方案4】:

          你有两个明显的问题。

          我们来谈谈如何通知用户有新数据可用,当应用程序不活跃时,实际上,你不必实现另一个意图服务,CloudBackendAndroidClientSample 项目中已经有一个启动并运行,所有你必须做的是在您收到新消息后立即向用户显示通知。这可以通过将以下方法添加到 GCMIntentService 类来轻松完成:

          public class GCMIntentService extends GCMBaseIntentService {
          ...
          //add this method
          public void showNotification(Context context, int id, String title, String message){
              Intent intent = new Intent(context, GuestbookActivity.class);
              intent.setAction(Intent.ACTION_MAIN);
              intent.addCategory(Intent.CATEGORY_LAUNCHER);
          
              PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
              NotificationCompat.Builder mBuilder =
                      new NotificationCompat.Builder(context.getApplicationContext())
                      .setTicker(message)
                      .setSmallIcon(R.drawable.ic_launcher)
                      .setContentTitle(title)
                      .setContentText(message)
                      .setWhen(System.currentTimeMillis())
                      .setContentIntent(pendingIntent)
                      .setDefaults(Notification.DEFAULT_SOUND)
                      .setAutoCancel(true)
                      .setOngoing(false)
                      .setOnlyAlertOnce(true)
                      .setLights(0xFFFF0000, 500, 500); //setLights (int argb, int onMs, int offMs)
              Notification notification = mBuilder.build();
          
              // show it in the notification list
              notification.setLatestEventInfo(context, title, message, pendingIntent);
          
              NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
              notificationManager.notify(id, notification);
              Log.d(TAG, "notification should be shown");
          }
          ...
          //And simply call that function in your onMessage callback
          @Override
          public void onMessage(Context context, Intent intent) {
              // decode subId in the message
              String subId = intent.getStringExtra(GCM_KEY_SUBID);
              Log.i(Consts.TAG, "onMessage: subId: " + subId);
              String[] tokens = subId.split(":");
              String typeId = tokens[1];
          
              // dispatch message
              if (GCM_TYPEID_QUERY.equals(typeId)) {
                  CloudBackendAsync.handleQueryMessage(tokens[2]);
                  Log.e(TAG, "update notif");
                  //call the fonction to show up your notification here
                  showNotification(context, 1, getString(R.string.app_name), "new messages!");
              }
          }
          ...
          }
          

          现在让我们谈谈您遇到的错误,这主要是因为您在 Mobile Backend Starter 服务器配置页面中启用了“由客户端 ID 保护”选项,而没有在服务器配置页面和 android 应用程序 consts 文件中指定 web_client_id。当前的 CloudBackendAndroidClientSample 无法正确处理 Oauth 授权湖因此,每次您再次启动应用程序并且它需要访问服务器时,都会引发 UserRecoverableAuthIOException 但示例应用程序没有向您显示 OAuth 同意对话框,实际上什么都不做。 所以为了解决这个问题,你可以:

          1. (首选)确保您在应用程序和服务器配置中声明并使用相同的 Web 客户端 ID,如 google I/O video around 19' 中所述
          2. (愚蠢)更改示例代码以在发生异常时显示 Oauth 同意对话框,以便用户可以授予对您的应用程序对您的服务器的访问权限,在这种情况下从用户体验的角度来看这是愚蠢的,您可以采取查看github 上的 google drive 教程示例代码。 在 CloudBackendAndroidClientSample 中,CloudBackendAsync 在第 430 行附近捕获了异常

            private abstract class BackendCaller<PARAM, RESULT> extends Thread {  
            ...
            
            @Override
            public void run() {
            ...
            
               try{
                  r = callBackend(param);
               } 
               catch (IOException e) {
                  Log.i(Consts.TAG, "error: ", e);
                  //The UserRecoverableAuthIOException is only logged here, a OAuth Consent Dialog should be opened to grant access to the server.
                  ie = e;
               }
            
               //So you should change this catch by something like the following. 
               //Of course you will need an activity context to be able to call startActivityForResult, that is why I said you will need a little bit of refactoring.
               catch (UserRecoverableAuthIOException e) {
                  startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
               }
            ...
            }
            

          【讨论】:

            猜你喜欢
            • 2023-04-08
            • 2013-01-30
            • 1970-01-01
            • 1970-01-01
            • 2018-03-16
            • 1970-01-01
            • 2017-07-14
            • 2014-07-15
            • 2014-03-16
            相关资源
            最近更新 更多