【问题标题】:Updating DB from onLoadFinished calls onLoadFinished again and again从 onLoadFinished 更新数据库一次又一次调用 onLoadFinished
【发布时间】:2015-02-20 04:04:03
【问题描述】:

我有一种情况,我需要在某个日期插入一行并在活动中的特定日期之后更新所有条目。

为此,我想我会使用LoaderManager 回调加载日期之后的条目,并使用ContentProviderOperation 数组从onLoadFinished() 方法中批量更新所有条目。

我面临的问题是我的光标有setNotificationUri,因此再次调用onLoadfinished,它再次插入行并继续循环(不设置通知Uri不是我的选择)。

是否有任何优雅的解决方案来停止递归调用?

下面是我的onCreateLoaderonLoadFinished的简化代码:

@Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        //retrieve data before the start date
        mStartDate = ProjectContract.getDateFromDb(mUserProjectEntryData.getAsString(ProjectContract.ProjectEntryTable.COLUMN_DATETEXT));
        Date nextDate = Utilities.addDays(mStartDate,1);
        String sortOrder = ProjectContract.ProjectEntryTable.COLUMN_DATETEXT + " ASC";
        Uri projectEntryUri = ProjectContract.ProjectEntryTable.buildProjectEntryWithStartDateUri(mProjectId,
                ProjectContract.getDbDateString(nextDate));
        return new CursorLoader(
                this,
                projectEntryUri,
                PROJECT_ENTRY_COLUMNS,
                null,
                null,
                sortOrder
        );

    }

@Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        mDbOperations = new ArrayList<ContentProviderOperation>();
        long newTotalCount;
        String selection = ProjectContract.ProjectEntryTable.COLUMN_PROJECT_ID + " = ? AND "
                + ProjectContract.ProjectEntryTable.COLUMN_DATETEXT + " = ? ";
//Some code to calculate the entry needed
        mDbOperations.add(
                ContentProviderOperation.newInsert(ProjectContract.ProjectEntryTable.CONTENT_URI)
                        .withValues(mUserProjectEntryData)
                        .withYieldAllowed(true)
                        .build()
        );

        while (data.moveToNext()) {
data.getString(COL_DATETEXT));
            newTotalCount = mCurrentWordCount + data.getLong(COL_WORD_COUNT);
            mDbOperations.add(ContentProviderOperation.newUpdate(ProjectContract.ProjectEntryTable.CONTENT_URI)
                    .withValue(ProjectContract.ProjectEntryTable.COLUMN_TOTAL_WORD_COUNT, newTotalCount)
                    .withSelection(selection, new String[]{
                            Long.toString(data.getLong(COL_PROJECT_ID)),
                            data.getString(COL_DATETEXT)
                    })
                    .build());

        }
//Hacky solution I put in just to make the code working.
//        data.close();
        try {
            getContentResolver().applyBatch(ProjectContract.CONTENT_AUTHORITY, mDbOperations);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        }
    }

【问题讨论】:

  • cursor = contentresolver.query(); iterate cursor; cursor.close(); 在其他线程中......根本没有加载器......
  • 我会尝试使用 AsyncTask .. 这样可以吗?在 doInBackground 中调用 Content 提供程序并遍历 onPostExecute 中的光标......因为我的查询很小,它应该可以正常工作。但是如果它很大并且屏幕旋转会弄乱 AsyncTask 实现呢?
  • no... 在 doInBackground 中执行所有操作 ... 不涉及 UI(或者如果您需要通知 UI 在 onPostExecute 中执行 - 不要在那里迭代)... 或者只是 @987654332 @ ...哦,我看到了您的编辑... AsyncTask 应该保留commonsware.com/blog/2010/09/10/asynctask-screen-rotation.html
  • 嗯..让我尝试实现它...谢谢:)

标签: android cursor android-contentprovider loader android-cursorloader


【解决方案1】:

我最终将 db 操作移至单独的线程,而不使用加载程序回调

【讨论】:

    【解决方案2】:

    决定为和我一样在这个问题上苦苦挣扎的人写一个答案。

    我有 2 个带有外键的表,我需要 1 个表中的 _ID 在第二个表中创建一个外键,这就是为什么我必须单独插入每一行(而不是作为 bulkInsert)。它导致我的加载器在每次插入后更新。我通过阻止 ContentProvider 中的 insert 方法调用 notifyChange 并在每次批量操作后手动通知 ContentProvider 解决了这个问题。

    希望这会对某人有所帮助。

    【讨论】:

      【解决方案3】:

      是否有任何优雅的解决方案来停止递归调用?

      解决方法很简单,关闭光标即可停止递归调用。只需添加这个 -

      data.close();
      

      在 applyBatch 的操作之后。

      【讨论】:

        【解决方案4】:

        您是否尝试过如下方式:

        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
            Log.i(TAG, "Inside onLoadFinished");
            // Swap the new cursor in.  (The framework will take care of closing the
            // old cursor once we return.)
            mAdapter.swapCursor(data);
        
            // The list should now be shown.
            if (isResumed()) {
                setListShown(true);
            } else {
                setListShownNoAnimation(true);
            }
        }
        

        【讨论】:

        • 大声笑,你读过这个问题吗? OP 正在使用 Loader API 来获取光标 但不与 UI 一起使用(不涉及 ListView) ...您的代码无关紧要 - 看起来像一些指南/教程中的随机复制和复制粘贴
        • 我真的没有使用列表,也没有使用适配器。我不需要显示结果,而是处理它们并更新其中的一些值..
        猜你喜欢
        • 2014-01-04
        • 2013-01-21
        • 2016-08-19
        • 1970-01-01
        • 2013-04-29
        • 1970-01-01
        • 1970-01-01
        • 2014-01-28
        • 1970-01-01
        相关资源
        最近更新 更多