CursorLoader + CursorAdapter +常规DB更新= Gridview闪烁

时间:2015-08-13 15:17:37

标签: android android-gridview android-cursoradapter android-contentresolver android-cursorloader

我有一个自定义图库应用,可以将图像数据存储在数据库中。该图库是由GridView支持的CursorAdapter

首次请求图像解码时ContentResolver.update更新后台线程中的高度,宽度和方向。由于许多图像一次可见,因此当用户滚动时数据库更新会快速发生,这会导致支持CursorLoader快速刷新GridView,这表现为快速闪烁。

如果底层来源可以快速更改,或者我在这里遗漏了什么,是否无法使用CursorLoaderCursorAdapter

1 个答案:

答案 0 :(得分:0)

当数据库中的监控数据(选择,投影)发生变化时,LoaderManager只会提供一个新光标。因此,就CursorAdapter而言,每次更新数据库时都会有一个全新的数据源(swapCursor):

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor)
{
    mGalleryAdapter.swapCursor(cursor);
}

因此,附加到动态CursorAdapter的理想LoaderManager将需要微观管理视图更新,以确保它不会更新完全相同的视图。为此(因为我的观点相当复杂),我创建了一个辅助对象来处理光标和视图之间的转换和比较(为了简洁起见,删除了大多数视图)。

public static class GalleryItem
{
    private String name;
    private int  rotation;

    public static GalleryItem fromCursor(Context c, Cursor cursor)
    {
        GalleryItem item = new GalleryItem();
        item.rotation = ImageUtils.getRotation(cursor.getInt(Meta.ORIENTATION_COLUMN));
        item.name = cursor.getString(Meta.NAME_COLUMN);
        return item;
    }

    public static GalleryItem fromViewHolder(ViewHolder vh)
    {
        GalleryItem item = new GalleryItem();
        item.rotation = (int)vh.mImageView.getRotation();
        item.name = (String) vh.mFileName.getText();
        return item;
    }

    @Override
    public boolean equals(Object o)
    {
        GalleryItem compare = (GalleryItem) o;
        boolean sameRotation = rotation == compare.rotation;
        boolean sameName = name == null ? compare.name == null : name.equals(compare.name);

        return sameName && sameRotation;
    }
}

然后使用它来检查您是否需要更新视图中的任何内容:

    @Override
    public void onBindViewHolder(ViewHolder vh, final int position, Cursor cursor)
    {
        GalleryItem galleryItem = GalleryItem.fromCursor(mContext, cursor);
        GalleryItem former = GalleryItem.fromViewHolder(vh);

        // If nothing has changed avoid refreshing.
        // The reason for this is that loaderManagers replace cursors meaning every change
        // will refresh the entire data source causing flickering
        if (former.equals(galleryItem))
            return;
...

长话短说,动态LoaderManager你必须实现一种方法来跳过重新创建完全不变的视图。