【问题标题】:Google IO 2010 Virgil Dobjanschi pattern C exampleGoogle IO 2010 Virgil Dobjanschi 模式 C 示例
【发布时间】:2015-06-26 16:11:55
【问题描述】:

我已经尝试过 Virgil Dobjanschi 模式 A 和 B 并得出我想使用模式 C 的结论,因为在这种情况下,我可以使用基于谷歌的代码,如果我有非稳定的网络连接等等... 但我没有找到如何以正确的方式实现这一点。 尤其是当您考虑到数据库足够大,可以每次都进行同步时。

我做了这样的事情

当 CursorLoader 执行查询以显示 BizInbox 查询返回游标并启动 SyncAdapter 它应该获取数据并停止其活动

但我的问题是 SyncAdatert 的 onPerformSync 再次启动。它看起来像无尽的循环 当光标重新加载其数据并启动 onPerformSync 等等... 并且 SyncAdapter 像我希望的那样在没有任何队列的情况下并行执行。

我应该注意到 REST 后端处理数据正确,并且执行 onPerformSync 的第二个请求没有数据,因为它使用了 If-Modified-Since http 标头。

很明显我做错了什么,因为我的 SyncAdapter 没有做同步退避并且没有结束地发出请求。

当我这样做的时候 if (!ContentResolver.isSyncActive(mConnectedAccount, Scheme.AUTHORITY)) { ContentResolver.requestSync( mConnectedAccount, // 同步账户 Scheme.AUTHORITY, // 内容权限 b); // 额外内容 } 别的 { Log.d(TAG, "> runSyncAdaterForClaimBizInbox 跳过启动适配器它已经处于活动状态"); }

我能够赢得问题,但问题仍然存在 如果需要同步部分数据 - 不是所有数据,如何执行此同步 ContentResolver.isSyncActive(mConnectedAccount, Scheme.AUTHORITY) - 此方法无法提供信息它正在同步的数据的哪一部分,并且由于某些原因我在这里没有队列。如何解决这个问题?

请帮我找出错误,或者可能有人有模式 C 可编译代码来找出如何正确实现这个模式。

提前致谢。

以下代码:

公共类 ContentProvider {

 @Override
 public Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder) {

     final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
     final String orderBy = prepareQuery(uri, sortOrder, qb);

     final SQLiteDatabase db = databaseHelper.getReadableDatabase();
     final Cursor cursor = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);

     runSyncAdapterForQuery(uri);

     cursor.setNotificationUri(getContext().getContentResolver(), uri);

     return cursor;
 }

void runSyncAdapterForQuery(Uri uri) {
    switch (uriMatcher.match(uri)) {
        case BIZ_INBOX:
            runSyncAdaterForBizInbox(METHOD_GET);
            break;
    }
}

void runSyncAdaterForBizInbox(String method) {

    Bundle b = new Bundle();

    b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
    b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);

    b.putString(METHOD_EXTRA, method);
    b.putInt(RESOURCE_TYPE_EXTRA, RESOURCE_TYPE_BIZ_INBOX);

    Account mConnectedAccount = new Account(BPalAccountGeneral.ACCOUNT_NAME, BPalAccountGeneral.ACCOUNT_TYPE);
   //if (!ContentResolver.isSyncActive(mConnectedAccount, Scheme.AUTHORITY)) { Do i need this ? Where is Sync Adapters queue ?
     ContentResolver.requestSync(
            mConnectedAccount, // Sync account
            Scheme.AUTHORITY, // Content authority
            b);               // Extras
   //}
}

}

SyncAdapter

@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {


    String accessToken = "some_token";

    switch (resourceType) {
        case UNKNOWN_RESOURCE_TYPE:
            //do update all ...
            break;
        case RESOURCE_TYPE_BIZ_INBOX:
            if (method.equals(METHOD_GET)) {

                String url = "some_inbox_url"

                GetBizInboxRequest request = new GetBizInboxRequest();

                BizInboxDAO BizInboxDAO = new BizInboxDAO();
                String lastModified = BizInboxDAO.getLastModified(getContext().getContentResolver());

                RestMethodResult<RestListEntityContainer<BizInboxEntity>> restMethodResult =
                        request.getBizInboxItems(
                                url,
                                null,
                                lastModified,
                                accessToken);

                int statusCode = restMethodResult.getStatusCode();

                if (statusCode == MobileConstant.HTTP_OK) {
                    List<BizInboxEntity> serverBizInboxEntities = restMethodResult.getResource().getList();

                    for (BizInboxEntity entity : serverBizInboxEntities) {
                        BizInboxDAO.insertyData(getContext().getContentResolver(), entity);
                        syncResult.stats.numInserts++;
                    }

                    if(syncResult.stats.numInserts > 0) {
                        Log.d(TAG, "> onPerformSync  BizInboxDAO.sendNotification ");
                        BizInboxDAO.sendNotification(getContext().getContentResolver());
                    }
                } else {
                    syncResult.stats.numIoExceptions++;
                    syncResult.databaseError = true;
                }
            }
            break;
        default:
            break;
    }
}

【问题讨论】:

  • 谢尔盖,很难读懂你的问题,也不清楚你在问什么。此外,在引用某些内容时(Google IO 上的一次演讲),最好添加一个链接。如果您的问题一开始很难阅读,人们不太可能去寻找该链接。
  • 对不起,我写的有点情绪化:-)。主要问题是:什么是使用模式 C 的好例子。同时使用 Sync Adapter 和 Content Provider 的正确方法是什么。感谢您的有用评论。

标签: java android-syncadapter


【解决方案1】:

我使用上面的代码犯了一个大错误。

  1. 根据模式 C,同步适配器应检查当前数据状态。我不应该直接从内容提供商调用请求同步。 Android 文档中描述了能够使用的方法 https://developer.android.com/training/sync-adapters/running-sync-adapter.html

  2. 如果我如下调用同步 // 禁用同步退避并忽略同步首选项。换句话说...立即执行同步! b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);

    Account mConnectedAccount = new Account(AccountGeneral.ACCOUNT_NAME, AccountGeneral.ACCOUNT_TYPE);
    
        ContentResolver.requestSync(
                mConnectedAccount, // Sync account
                Scheme.AUTHORITY, // Content authority
                b);               // Extras
    

你应该记住我给 cmets 的内容:
禁用同步退避并忽略同步首选项。换句话说...立即执行同步!

这意味着如果请求失败,请求不会尝试重复自己。并且此代码并行运行其操作。例如,如果您运行此 requestSync 两个磁贴,您将有两个同步线程,正如我发现的那样。

最后一个主要说明: 当我从查询运行 requestSync 时,它会导致类似无休止的循环,因为在 requestSync 之后我做 Cursot 通知哪个调用重新查询哪个再次运行 requestSync 等等......

  1. 我找到了使用模式 C 的优秀示例应用程序 - 这是链接: https://github.com/taoliuh/v2ex

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-08
    • 1970-01-01
    相关资源
    最近更新 更多