java - ListView 适配器异步操作

标签 java android database sqlite android-recyclerview

我有一个自定义ListView this是我正在使用的 ListView,它在屏幕上显示一些数据,非常简单。现在我需要为显示的数据 View 设置主题。我这样做的方法是保存 key, value到 SQLite 适配器,我不想使用 SharedPrefs,这需要一个很长的过程来读取超过 120 个键!并且 UI 滞后很多,所以我想让我们创建一个异步 setBackground这就是我整理的内容。

public static HashMap<String, String> lruCache = new HashMap<>();

我缓存哈希集中的所有键

然后我创建了一个方法来检查 key 是否存在,如果不存在,则使用 AsyncTask 获取 key

public static void setBackgroundColor(View view, String key, String defaultValue) {
    String val = lruCache.get(key);
    if (val != null) {
        view.setBackgroundColor(ThemeUtils.parseColor(val));
        return;
    }
    new AsyncBackgroundColor(view).execute(key, defaultValue);
}

public static class AsyncBackgroundColor extends AsyncTask<String, String, Integer> {
    WeakReference<View> view;

    AsyncBackgroundColor(View view) {
        this.view = new WeakReference<>(view);
    }

    @Override
    protected Integer doInBackground(String... strings) {
        return ThemeUtils.getColor(strings[0], strings[1]);
    }

    @Override
    protected void onPostExecute(Integer color) {
        view.get().setBackgroundColor(color);
    }
}

这就是我的 getColor方法有效。

public static int getColor(String str, String defaultValue) {
    ThemeDatabaseManager lynxDatabaseHelper = new ThemeDatabaseManager(LynxBase.getApplicationContext()).open();
    return ThemeUtils.parseColor(lynxDatabaseHelper.getString(str, defaultValue));
}

它从我的 SQlite 数据库获取字符串并将其解析为 int。这是我的getString方法

public String getString(String key, String defaultValue) {
    String cachedValue = ThemeDatabaseCache.lruCache.get(key);
    if (cachedValue != null) {
        return cachedValue;
    }
    if (!database.isOpen()) open();
    String[] columns = new String[]{ThemeDatabaseHelper.COLUMN_NAME_TITLE, ThemeDatabaseHelper.COLUMN_NAME_SUBTITLE};
    Cursor cursor = database.query(TABLE_NAME, columns, null, null, null, null, null);
    if(cursor != null) {
        cursor.moveToFirst();
        if(cursor.getCount() != 0) {
            do {
                if (!(cursor.getColumnCount() <= 1)) {
                    String k = cursor.getString(cursor.getColumnIndex(ThemeDatabaseHelper.COLUMN_NAME_TITLE));
                    String value = cursor.getString(cursor.getColumnIndex(ThemeDatabaseHelper.COLUMN_NAME_SUBTITLE));
                    if (k.equals(key)) {
                        cursor.close();
                        if (database.isOpen()) database.close();
                        ThemeDatabaseCache.lruCache.put(key, defaultValue);
                        return value;
                    }
                }
            } while (cursor.moveToNext());
        }
        cursor.close();
    }
    insertOrUpdate(key, defaultValue);
    if (database.isOpen()) database.close();
    return defaultValue;
}

我获取所有 SQLite 列并循环,直到找到正确的键,然后返回该值,如果该值不存在,我只需将默认值插入 SQLite 数据库,这样我总是会得到一个键另一次。

问题就出在这里。它不会为适配器中的所有选项卡设置主题。

enter image description here

如您所见,它仅以第三个适配器项目为主题,但是当我上下滚动时,位置会发生变化。所以它不会改变第三个,它会变成第五个,你明白了,有人知道我该如何解决这个问题吗?我已经调试了大约 5 天,尝试了各种方法似乎无法修复它。

黑色是 setBackgroundColor 后所有项目的外观。已经完成了。白色是使用 XML 布局应用的默认颜色。

这就是我在适配器上的调用方式。

public final View getView(int i, View view, ViewGroup viewGroup){\
    ...
    view = inflate(R.layout.my_view, viewGroup, false);
    setBackground(view);
    ...
}

我的类正在扩展我创建的自定义类,该类扩展了 BaseAdapter如果有帮助的话!

这是我根据答案尝试过的。

public static void setBackgroundColor(BaseAdapter baseAdapter, View view, String key, String defaultValue) {
    String val = lruCache.get(key);
    if (val != null) {
        Log.wtf("Lynx", "background set using cached Color.");
        view.setBackgroundColor(ThemeUtils.parseColor(val));
        baseAdapter.notifyDataSetChanged();
        return;
    }
    new AsyncBackgroundColor(baseAdapter, view).execute(key, defaultValue);
}

..

public static class AsyncBackgroundColor extends AsyncTask<String, String, Integer> {
    WeakReference<View> view;
    BaseAdapter baseAdapter;

    AsyncBackgroundColor(BaseAdapter baseAdapter, View view) {
        this.view = new WeakReference<>(view);
        this.baseAdapter = baseAdapter;
    }

    @Override
    protected Integer doInBackground(String... strings) {

        return ThemeUtils.getColor(strings[0], strings[1]);
    }

    @Override
    protected void onPostExecute(Integer color) {
        Log.wtf("Lynx", "background set using async task.");
        view.get().setBackgroundColor(color);
        if(baseAdapter != null)
        baseAdapter.notifyDataSetChanged();
    }
}

但是还是和以前一样。

这是目录转储:

enter image description here

最佳答案

This works if I just set the color from the database and skip the async bit. But when I use async it doesn't work.

发生这种情况是因为您的 AsyncTask 无法在 UIThread 上工作,因此当结果返回时,它不会重绘您的项目。为此,您需要使用 myAdapter.notifyDataSetChanged();

通知适配器存在新元素

根据您共享的代码,我想您可以从 postExecute 中调用它:

public static class AsyncBackgroundColor extends AsyncTask<String, String, Integer> {
    WeakReference<View> view;
    WeakReference<Adapter> adapter;

    AsyncBackgroundColor(Adapter ad, View view) {
        this.view = new WeakReference<>(view);
        this.adapter = new WeakReference<>(ad);
    }

    @Override
    protected Integer doInBackground(String... strings) {
        return 1;
    }

    @Override
    protected void onPostExecute(Integer color) {
        view.get().setBackgroundColor(color);
        adapter.get().notifyDataSetChanged();
    }
}

另外在您的 getString() 上更改这部分:

if (k.equals(key)) {
                    cursor.close();
                    if (database.isOpen()) database.close();
                    ThemeDatabaseCache.lruCache.put(key, value);
                    return value;
                }

关于java - ListView 适配器异步操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54715709/

相关文章:

java - 使用 Appium 和 Selenium WebDriver 在不重置其状态的情况下测试 Android 应用程序

sql-server - 附加sql server 2012错误,无法打开物理文件

android - 为 Android Lollipop 构建一个向后兼容的自定义 View (代码重复很少)

android - FCM 通知在发布应用程序中不起作用

PHP 从 MySQL 数据库中搜索 FUL​​LTEXT 转义字符串

PHPMyadmin 调用未定义函数 PMA_SQP_parse()

java - 如何使 Camel 路线线程安全?

java - 添加 JFileChooser 而不执行任何操作会导致面板不呈现

java - C# 和 Java 之间通过 protobuf-net 进行序列化/解封

java - 从锁定屏幕控制 android 媒体播放器?