android中的ArrayAdapter线程安全吗?如果没有,我该怎么做才能使其线程安全? [英] Is ArrayAdapter thread safe in android? If not, what can I do to make it thread safe?

查看:32
本文介绍了android中的ArrayAdapter线程安全吗?如果没有,我该怎么做才能使其线程安全?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我扩展了 ArrayAdapter并在我覆盖的代码中 getView(int i, View v, ViewGroup g),我使用 getItem(i).我可以确定 getItem(i) 即使其他线程操作相同的 <代码>ArrayAdapter?

Lets say I extend ArrayAdapter and in the code where I am overriding getView(int i, View v, ViewGroup g), I retrieve the current item using getItem(i). Can I be sure that getItem(i) will return an item even if other threads manipulate the same ArrayAdapter?

我不确定,但我认为答案是否定的.如果是,你建议我怎么做才能使其线程安全?

I am not sure, but I think the answer is no. If it is, what do you suggest I do to make it thread-safe?

推荐答案

ArrayAdapter 线程安全不是问题.ListView 和其他与适配器一起使用的此类 UI 小部件不允许适配器的内容在它们上发生意外更改.这不仅仅是由于其他线程 - 在下一次尝试与您的适配器交互之前,您需要将您所做的更改告诉 ListView.

It's not a matter of ArrayAdapter being thread safe. ListView and other such UI widgets that work with an Adapter do not allow the contents of the adapter to change unexpectedly on them. And this is more than just due to other threads -- you need to tell the ListView about the change you make before it next tries to interact with your adapter.

如果您允许另一个线程修改适配器,或者在主线程上修改它,但在允许其他任何事情发生之前不告诉 ListView 有关更改的信息,您将随机(由于竞争)得到 ListView 抛出的异常适配器意外更改.

If you allow another thread to modify the adapter, or modify it on the main thread but don't tell ListView about the change before allowing anything else to happen, you will randomly (due to races) get exceptions thrown by ListView about the adapter changing unexpectedly.

在 ArrayAdapter 的特定情况下,如果您使用 API 修改其内容,它将负责将更改告知列表视图.但是,您必须在主线程上进行此类更改,以确保列表视图不会尝试在您进行更改和列表视图被告知该更改之间访问适配器.

In the specific case of ArrayAdapter if you use the API to modify its contents it will take care of telling the list view about the change. However you must make such changes on the main thread, to make sure that the list view doesn't try to access the adapter between the point where your change is made and the list view is told about that change.

如果您只是对 ArrayAdapter 进行简单的更改(添加和删除一些项目),那么您会没事的,但您必须在主线程上执行这些操作.

If you are only making simple changes to ArrayAdapter (adding and removing a few items), then you will be fine but you must do these on the main thread.

对于更重要的更改(例如说适配器由于从服务器获取新数据而获取新数据集),请考虑不使用 ArrayAdapter 而是实现您自己的 BaseAdapter 子类.ArrayAdapter 适用于您有一组小的简单且相当静态的数据要显示的情况——简单的情况.对于更复杂的事情,您可能会更高兴实现 BaseAdapter 并自己进行数据管理.

For more significant changes (such as say the adapter getting a new data set due to a fetch of new data from a server), Consider not using ArrayAdapter and instead implementing your own subclass of BaseAdapter. ArrayAdapter is intended for situations where you have a small simple fairly static set of data to show -- simple situations. For more complicated things, you'll probably be happier just implementing BaseAdapter and doing the data management yourself.

适配器在这些复杂情况下更新的典型方式是后台线程生成新数据集,一旦可用,然后在主线程上通过调用 notifyDataSetChanged() 原子地交换到适配器让 ListView 知道数据已更改.

The typical way an adapter updates in these complicated situations is that a background thread generates the new data set, and once that is available then on the main thread it is swapped in to the adapter atomically with a call to notifyDataSetChanged() to let the ListView know that the data has changed.

假设您正在显示一些数据,这些数据是 MyItem 对象的数组.将您的数据保存在播放数组中:

So let's say you are showing some data that is an array of MyItem objects. Keep your data in a play array:

ArrayList<MyItem>

实现显示此列表的 BaseAdapter 子类:

Implement a subclass of BaseAdapter that shows this list:

class MyAdapter extends BaseAdapter<MyItem> {
    ArrayList<MyItem> mItems;

    public int getCount() {
        return mItems != null ? mItems.size() : 0;
    }

    public MyItem getItem(int position) {
        return mItems.get(i);
    }

    ...
}

现在,您可以在适配器上实现一个函数,该函数可以从另一个线程调用以提供要显示的新数据集:

And now here is a function you could implement on the adapter that can be called from another thread to provide a new data set to be shown:

    final Handler mHandler = new Handler();

    void setDataFromAnyThread(final ArrayList<MyItem> newData) {
        // Enqueue work on mHandler to change the data on
        // the main thread.
        mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mItems = newData;
                    notifyDataSetChanged();
                }
            });
    }

当然,如果您使用 AsyncTask 来生成数据,这已经有一个方便的工具可以在主线程上执行该工作.同样,您可以使用新的 Loader 工具在后台处理生成.

Of course if you are using AsyncTask to do your data generation this already has a convenient facility for performing that work back on the main thread. Likewise you could use the new Loader facility to take care of the generation in the background.

如果您仍然想使用 ArrayAdapter,在您的上述函数中,您可以通过清除当前数据并将新数据添加到现在为空的适配器来实现.这只是更多的开销,并没有真正为您带来任何好处.

And if you still want to use ArrayAdapter, in your function above you could do this by clearing the current data and adding the new data to the now empty adapter. This is just more overhead that doesn't really gain you anything.

这篇关于android中的ArrayAdapter线程安全吗?如果没有,我该怎么做才能使其线程安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆