ListView适配器异步操作

时间:2019-02-15 19:10:33

标签: java android database sqlite android-recyclerview

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

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

我将所有键缓存在哈希集中

然后我制作了一种方法,用于检查密钥是否存在,如果不存在,则使用AsyncTask获取密钥。

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

可以看到

它仅以第3个适配器项目为主题,但是当我上下滚动时,位置会发生变化。所以它不会改变第3位,而是第5位,您明白了,有人知道我能解决这个问题吗?我已经调试了大约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();
    }
}

但是还是和以前一样。

这是Catlog转储:

enter image description here

2 个答案:

答案 0 :(得分:1)

  

如果我只是从数据库设置颜色并跳过   异步位。但是当我使用异步时,它不起作用。

之所以会这样,是因为您的AsyncTask UIThread 上不起作用,因此,当返回结果时,它就不会redraw您的项目。为此,您需要使用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;
                }

答案 1 :(得分:1)

作为补充。您应该更改查询以仅获取您感兴趣的条目,而不是获取整个数据库并匹配ThemeDatabaseHelper.COLUMN_NAME_TITLE,这将加快您的操作并避免延迟。