Mobile Backend在后台处理连续查询

时间:2013-07-04 16:38:41

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

我在我的应用中使用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

我如何实现我的目标?

4 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

你有两个不同的问题。

让我们来谈谈如何通知用户新数据可用,当应用程序未处于活动状态时,实际上,您不必实现其他意图服务,已经在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 app consts文件中指定web_client_id。当前的CloudBackendAndroidClientSample无法正确处理Oauth授权湖。因此,每次再次启动应用程序并且需要访问服务器时,都会抛出UserRecoverableAuthIOException,但样本应用程序实际上并没有显示OAuth同意对话框。 所以为了解决这个问题,你可以:

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

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