【问题标题】:Stop Android's adapter.notifyDataSetChanged() from running in parallel with the function that contains the notifyDataSetChanged() code停止 Android 的 adapter.notifyDataSetChanged() 与包含 notifyDataSetChanged() 代码的函数并行运行
【发布时间】:2015-01-21 19:52:23
【问题描述】:

我的 Android 应用程序正在运行以下单例

public class ListsApplication extends Application {
public DbxDatastoreManager datastoreManager;
public HashMap<String, ViewItemContainer> itemsSync;
public Typeface Font;
public boolean Fetch;

private static ListsApplication singleton;
public static ListsApplication getInstance() {
    return singleton;
}

@Override
public void onCreate() {
    super.onCreate();
    singleton = this;
    itemsSync = new HashMap<>();
    Font = Typeface.createFromAsset(getAssets(), "fonts/GoodDog.otf");
    Fetch = true;
}}

然后从 Home 活动中我通过

保留单例实例
ListsApplication app = app.getInstance

在 Home 活动中,我设置了一个侦听器,只要在线数据存储发生变化,就会从数据存储在线服务器触发

private void setUpListeners() {
    app.datastoreManager.addListListener(new DbxDatastoreManager.ListListener() {
        @Override
        public void onDatastoreListChange(DbxDatastoreManager dbxDatastoreManager) {
            // Update the UI when the list of datastores changes.
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    app.Fetch = true;
                    Home.this.updateList();
                    app.Fetch = false;

                }
            }, 7000/* 3sec delay */);

            Toast toast = Toast.makeText(getApplicationContext(), "RECEIVED", Toast.LENGTH_SHORT);
            toast.show();
        }
    });

    updateList();
    app.Fetch = false;
}

我在运行 updateList() 之前允许一些时间,因为对数据存储的更新不是原子的,因此在线数据存储上的所有行需要大约 2 秒,暂时忽略 app.Fetch,我将稍后解释。

updateList() 清除 ArrayList 中必须填充 listAdapter 并运行 adapter.notifyDataSetChanged() 的项目

在我的自定义 listAdapter 中,我将 getView 设置如下:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    final ViewHolder mHolder;
    if (convertView == null) {
        /*Toast toast = Toast.makeText(context, "nullConvertView", Toast.LENGTH_SHORT);
        toast.show();*/
        mHolder = new ViewHolder();
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.listitem, parent, false);


        mHolder.PetName = (TextView) convertView.findViewById(R.id.PetName);
        mHolder.BuyFood = (ImageView) convertView.findViewById(R.id.PetBuyFood);
        mHolder.PetImage = (RoundedImageView) convertView.findViewById(R.id.PetImage);





        convertView.setTag(mHolder);
    } else {
        mHolder = (ViewHolder) convertView.getTag();
    }
    updateItem(mHolder, this.getItem(position));return convertView;}

和 updateItem(mHolder, this.getItem(position))

public void updateItem(final ViewHolder currentViewFromList, final DbxDatastoreInfo info){
    app = ListsApplication.getInstance();
    if (app.itemsSync.containsKey(info.id) && !app.Fetch){
        /*Toast toast = Toast.makeText(context, "not fetching "+info.title, Toast.LENGTH_SHORT);
        toast.show();*/
        ViewItemContainer cont = app.itemsSync.get(info.id);
        currentViewFromList.PetName.setTypeface(app.Font);
        currentViewFromList.PetName.setText(cont.PetName);
        currentViewFromList.PetImage.setImageBitmap(cont.PetImage);
        if (cont.BuyFood) currentViewFromList.BuyFood.setVisibility(View.VISIBLE);
        else currentViewFromList.BuyFood.setVisibility(View.INVISIBLE);
    }
    else{
        ViewItemContainer cont = new ViewItemContainer();
        try {
        Toast toast = Toast.makeText(context, "entrato"+info.title, Toast.LENGTH_SHORT);
        toast.show();

        DbxDatastore datastore = app.datastoreManager.openDatastore(info.id);
        datastore.sync();

        if (info.title!=null){
            currentViewFromList.PetName.setTypeface(app.Font);
            cont.PetName = info.title;
            currentViewFromList.PetName.setText(cont.PetName);
        }

        DbxTable table = datastore.getTable("ITEMS");
        DbxRecord record = table.get("INFO");

        if (record!=null && record.hasField("PETPICTURE")){
            byte[] b = record.getBytes("PETPICTURE");
            //Bitmap picture = Misc.ByteArrayToImg(b);
            cont.PetImage = Misc.ByteArrayToImg(b);
            if (cont.PetImage!=null) currentViewFromList.PetImage.setImageBitmap(cont.PetImage);
        } else currentViewFromList.PetImage.setImageResource(R.drawable.ic_launcher);


        if (record!=null){
            cont.BuyFood = record.getBoolean("BUYFOOD");
            if (cont.BuyFood) currentViewFromList.BuyFood.setVisibility(View.VISIBLE);
            else currentViewFromList.BuyFood.setVisibility(View.INVISIBLE);
        }


        datastore.close();
    } catch (DbxException e) {
        e.printStackTrace();
    }

        app.itemsSync.put(info.id,cont);
    }

}

基本上当应用程序启动时,app.Fetch 设置为 true,home 中的 updateList() 创建适配器并调用 adapter.notifyDataSetChanged()。

此时 listAdapter getView 为列表中的每个项目调用, 检查 id 作为 hashmap 中的键,但没有找到 因此它从数据存储中获取数据,并将数据插入到哈希映射和视图中。

到目前为止,一切都很好。列表视图被正确填充,并且当视图被滚动时,数据会从哈希图中正确检索,而不是从数据存储中一遍又一遍地获取。

然后我从另一部手机添加了一个新的数据存储,它触发了监听器,在我的手机上它显示“RECEIVED”toast,这意味着监听器已被触发。 app.Fetch 变为 true,然后调用 updateList()。

如果我在 updateList() 中的任何地方检查 app.Fetch 值,它仍然设置为 true,而如果我在 getView 代码运行时检查它,它会设置为 false,因此它会再次从 hashmap 中检索数据而不是获取更新的在线数据存储。

我认为 getView 代码开始与 updateList 函数并行运行,因此它显示以下行为:

布尔真 updateList() 开始 adapter.notifyDataSetChanged() 运行 ListAdapter getView 开始 updateList() 结束 布尔假 getView 检查布尔值,因为此时它为假,所以它从哈希图中检索数据。

有什么方法可以让 updateList 等到 listview 中的所有项目都通过 getView 运行?

【问题讨论】:

  • 这个Adapter的方法名是getView还是fetchTheData
  • 它是 getView(int position, View convertView, ViewGroup parent)

标签: android android-listview synchronization listadapter getview


【解决方案1】:

是的 - 您确保只在 UI 线程上调用 notifyDataSetChanged。这样你就不会在列表加载时调用它。如果要在异步线程上调用它,请使用 runOnUiThread 块将该调用移动到 UI 线程。这将确保您在绘制列表时永远不会尝试更新列表并避免整个问题。

【讨论】:

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