如何刷新Android列表视图?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2250770/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to refresh Android listview?
提问by UMAR
How to refresh an Android ListView
after adding/deleting dynamic data?
ListView
添加/删除动态数据后如何刷新Android ?
回答by Christopher Orr
Call notifyDataSetChanged()
on your Adapter
object once you've modified the data in that adapter.
一旦您修改了该适配器中的数据,就调用notifyDataSetChanged()
您的Adapter
对象。
Some additional specifics on how/when to call notifyDataSetChanged()
can be viewed in this Google I/O video.
notifyDataSetChanged()
可以在此 Google I/O 视频 中查看有关如何/何时调用的一些其他细节。
回答by Bobs
Also you can use this:
你也可以使用这个:
myListView.invalidateViews();
回答by hcpl
Please ignore all the invalidate()
, invalidateViews()
, requestLayout()
, ... answers to this question.
请忽略此问题的所有invalidate()
, invalidateViews()
, requestLayout()
, ... 答案。
The right thing to do (and luckily also marked as right answer) is to call notifyDataSetChanged()
on your Adapter.
正确的做法(幸运的是也标记为正确答案)是调用notifyDataSetChanged()
您的 Adapter。
Troubleshooting
故障排除
If calling notifyDataSetChanged()
doesn't work all the layout methods won't help either. Believe me the ListView
was properly updated. If you fail to find the difference you need to check where the data in your adapter comes from.
如果调用notifyDataSetChanged()
不起作用,则所有布局方法也无济于事。相信我ListView
已经正确更新了。如果找不到差异,则需要检查适配器中的数据来自何处。
If this is just a collection you're keeping in memory check that you actually deleted from or added the item(s) to the collection before calling the notifyDataSetChanged()
.
如果这只是一个您保存在内存中的集合,请在调用notifyDataSetChanged()
.
If you're working with a database or service backend you'll have to call the method to retrieve the information again (or manipulate the in memory data) before calling the notifyDataSetChanged()
.
如果您正在使用数据库或服务后端,则必须在调用notifyDataSetChanged()
.
The thing is this notifyDataSetChanged
only works if the dataset has changed. So that is the place to look if you don't find changes coming through. Debug if needed.
问题是这notifyDataSetChanged
仅在数据集已更改时才有效。因此,如果您没有发现正在发生的变化,那么这就是查看的地方。如果需要,请进行调试。
ArrayAdapter vs BaseAdapter
ArrayAdapter 与 BaseAdapter
I did find that working with an adapter that lets you manage the collection, like a BaseAdapter works better. Some adapters like the ArrayAdapter already manage their own collection making it harder to get to the proper collection for updates. It's really just an needless extra layer of difficulty in most cases.
我确实发现使用可让您管理集合的适配器(例如 BaseAdapter)效果更好。一些像 ArrayAdapter 这样的适配器已经管理了它们自己的集合,这使得获取更新的正确集合变得更加困难。在大多数情况下,这实际上只是一个不必要的额外难度。
UI Thread
用户界面线程
It is true that this has to be called from the UI thread. Other answers have examples on how to achieve this. However this is only required if you're working on this information from outside the UI thread. That is from a service or a non UI thread. In simple cases you'll be updating your data from a button click or another activity/fragment. So still within the UI thread. No need to always pop that runOnUiTrhead in.
这确实必须从 UI 线程调用。其他答案有关于如何实现这一目标的示例。但是,仅当您从 UI 线程外部处理此信息时才需要这样做。那是来自服务或非 UI 线程。在简单的情况下,您将通过单击按钮或其他活动/片段来更新数据。所以仍然在 UI 线程中。无需总是弹出 runOnUiTrhead 。
Quick Example Project
快速示例项目
Can be found at https://github.com/hanscappelle/so-2250770.git. Just clone and open the project in Android Studio (gradle). This project has a MainAcitivity building a ListView
with all random data. This list can be refreshed using the action menu.
可以在https://github.com/hanscappelle/so-2250770.git找到。只需在 Android Studio (gradle) 中克隆并打开项目即可。这个项目有一个ListView
包含所有随机数据的 MainAcitivity 建筑。可以使用操作菜单刷新此列表。
The adapter implementation I created for this example ModelObject exposes the data collection
我为这个示例 ModelObject 创建的适配器实现公开了数据集合
public class MyListAdapter extends BaseAdapter {
/**
* this is our own collection of data, can be anything we
* want it to be as long as we get the abstract methods
* implemented using this data and work on this data
* (see getter) you should be fine
*/
private List<ModelObject> mData;
/**
* our ctor for this adapter, we'll accept all the things
* we need here
*
* @param mData
*/
public MyListAdapter(final Context context, final List<ModelObject> mData) {
this.mData = mData;
this.mContext = context;
}
public List<ModelObject> getData() {
return mData;
}
// implement all abstract methods here
}
Code from the MainActivity
来自 MainActivity 的代码
public class MainActivity extends Activity {
private MyListAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView list = (ListView) findViewById(R.id.list);
// create some dummy data here
List<ModelObject> objects = getRandomData();
// and put it into an adapter for the list
mAdapter = new MyListAdapter(this, objects);
list.setAdapter(mAdapter);
// mAdapter is available in the helper methods below and the
// data will be updated based on action menu interactions
// you could also keep the reference to the android ListView
// object instead and use the {@link ListView#getAdapter()}
// method instead. However you would have to cast that adapter
// to your own instance every time
}
/**
* helper to show what happens when all data is new
*/
private void reloadAllData(){
// get new modified random data
List<ModelObject> objects = getRandomData();
// update data in our adapter
mAdapter.getData().clear();
mAdapter.getData().addAll(objects);
// fire the event
mAdapter.notifyDataSetChanged();
}
/**
* helper to show how only changing properties of data
* elements also works
*/
private void scrambleChecked(){
Random random = new Random();
// update data in our adapter, iterate all objects and
// resetting the checked option
for( ModelObject mo : mAdapter.getData()) {
mo.setChecked(random.nextBoolean());
}
// fire the event
mAdapter.notifyDataSetChanged();
}
}
More Information
更多信息
Another nice post about the power of listViews is found here: http://www.vogella.com/articles/AndroidListView/article.html
另一个关于 listViews 功能的好文章可以在这里找到:http://www.vogella.com/articles/AndroidListView/article.html
回答by Marckaraujo
Call runnable whenever you want:
随时调用 runnable:
runOnUiThread(run);
OnCreate()
, you set your runnable thread:
OnCreate()
,你设置你的可运行线程:
run = new Runnable() {
public void run() {
//reload content
arraylist.clear();
arraylist.addAll(db.readAll());
adapter.notifyDataSetChanged();
listview.invalidateViews();
listview.refreshDrawableState();
}
};
回答by Wille
i got some problems with dynamic refresh of my listview.
我在动态刷新列表视图时遇到了一些问题。
Call notifyDataSetChanged() on your Adapter.
Some additional specifics on how/when to call notifyDataSetChanged() can be viewed in this Google I/O video.
在您的适配器上调用 notifyDataSetChanged()。
可以在此 Google I/O 视频中查看有关如何/何时调用 notifyDataSetChanged() 的一些其他细节。
notifyDataSetChanged() did not work properly in my case[ I called the notifyDataSetChanged from another class]. Just in the case i edited the ListView in the running Activity (Thread). That video thanks to Christophergave the final hint.
notifyDataSetChanged() 在我的情况下没有正常工作[我从另一个类调用了notifyDataSetChanged]。以防万一我在正在运行的活动(线程)中编辑了 ListView。克里斯托弗的那段视频给出了最后的暗示。
In my second class i used
在我的第二堂课中,我使用了
Runnable run = new Runnable(){
public void run(){
contactsActivity.update();
}
};
contactsActivity.runOnUiThread(run);
to acces the update() from my Activity. This update includes
从我的活动访问 update()。本次更新包括
myAdapter.notifyDataSetChanged();
to tell the Adapter to refresh the view. Worked fine as far as I can say.
告诉适配器刷新视图。据我所知,工作得很好。
回答by freehacker
If you are using SimpleCursorAdaptertry calling requery()on the Cursor object.
如果您使用的是SimpleCursorAdapter,请尝试在 Cursor 对象上调用requery()。
回答by Nandagopal T
if you are not still satisfied with ListView Refreshment, you can look at this snippet,this is for loading the listView from DB, Actually what you have to do is simply reload the ListView,after you perform any CRUD Operation Its not a best way to code, but it will refresh the ListView as you wish..
如果你仍然对 ListView Refreshment 不满意,你可以看看这个片段,这是为了从 DB 加载 listView,实际上你要做的只是在执行任何 CRUD 操作后重新加载 ListView 这不是最好的方法代码,但它会根据需要刷新 ListView ..
It works for Me....if u find better solution,please Share...
它对我有用......如果你找到更好的解决方案,请分享......
....... ...... do your CRUD Operations.. ...... ..... DBAdapter.open(); DBAdapter.insert_into_SingleList(); // Bring that DB_results and add it to list as its contents.... ls2.setAdapter(new ArrayAdapter(DynTABSample.this, android.R.layout.simple_list_item_1, DBAdapter.DB_ListView)); DBAdapter.close();
回答by AntuanSoft
The solutions proposed by people in this post works or not mainly depending on the Android version of your device. For Example to use the AddAll method you have to put android:minSdkVersion="10" in your android device.
这篇文章中人们提出的解决方案是否有效主要取决于您设备的 Android 版本。例如,要使用 AddAll 方法,您必须将 android:minSdkVersion="10" 放在您的 android 设备中。
To solve this questions for all devices I have created my on own method in my adapter and use inside the add and remove method inherits from ArrayAdapter that update you data without problems.
为了解决所有设备的这个问题,我在我的适配器中创建了自己的方法,并在从 ArrayAdapter 继承的 add 和 remove 方法中使用,可以毫无问题地更新数据。
My Code: Using my own data class RaceResult, you use your own data model.
我的代码:使用我自己的数据类 RaceResult,您使用自己的数据模型。
ResultGpRowAdapter.java
ResultGpRowAdapter.java
public class ResultGpRowAdapter extends ArrayAdapter<RaceResult> {
Context context;
int resource;
List<RaceResult> data=null;
public ResultGpRowAdapter(Context context, int resource, List<RaceResult> objects) {
super(context, resource, objects);
this.context = context;
this.resource = resource;
this.data = objects;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
........
}
//my own method to populate data
public void myAddAll(List<RaceResult> items) {
for (RaceResult item:items){
super.add(item);
}
}
ResultsGp.java
结果Gp.java
public class ResultsGp extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
...........
...........
ListView list = (ListView)findViewById(R.id.resultsGpList);
ResultGpRowAdapter adapter = new ResultGpRowAdapter(this, R.layout.activity_result_gp_row, new ArrayList<RaceResult>()); //Empty data
list.setAdapter(adapter);
....
....
....
//LOAD a ArrayList<RaceResult> with data
ArrayList<RaceResult> data = new ArrayList<RaceResult>();
data.add(new RaceResult(....));
data.add(new RaceResult(....));
.......
adapter.myAddAll(data); //Your list will be udpdated!!!
回答by Brandon Yang
If you want to maintain your scroll position when you refresh, and you can do this:
如果您想在刷新时保持滚动位置,您可以这样做:
if (mEventListView.getAdapter() == null) {
EventLogAdapter eventLogAdapter = new EventLogAdapter(mContext, events);
mEventListView.setAdapter(eventLogAdapter);
} else {
((EventLogAdapter)mEventListView.getAdapter()).refill(events);
}
public void refill(List<EventLog> events) {
mEvents.clear();
mEvents.addAll(events);
notifyDataSetChanged();
}
For the detail information, please see Android ListView: Maintain your scroll position when you refresh.
有关详细信息,请参阅Android ListView:刷新时保持滚动位置。
回答by ADM
You need to use a single object of that list whoose data you are inflating on ListView
. If reference is change then notifyDataSetChanged()
does't work .Whenever You are deleting elements from list view also delete them from the list you are using whether it is a ArrayList<> or Something else then Call
notifyDataSetChanged()
on object of Your adapter class.
您需要使用该列表的单个对象,您要对其数据进行膨胀ListView
。如果引用更改,则 notifyDataSetChanged()
不起作用。无论何时您从列表视图中删除元素,也会从您正在使用的列表中删除它们,无论它是 ArrayList<> 还是其他东西,然后调用
notifyDataSetChanged()
您的适配器类的对象。
So here see how i managed it in my adapter see below
所以在这里看看我是如何在我的适配器中管理它的,见下文
public class CountryCodeListAdapter extends BaseAdapter implements OnItemClickListener{
private Context context;
private ArrayList<CountryDataObject> dObj;
private ViewHolder holder;
private Typeface itemFont;
private int selectedPosition=-1;
private ArrayList<CountryDataObject> completeList;
public CountryCodeListAdapter(Context context, ArrayList<CountryDataObject> dObj) {
this.context = context;
this.dObj=dObj;
completeList=new ArrayList<CountryDataObject>();
completeList.addAll(dObj);
itemFont=Typeface.createFromAsset(context.getAssets(), "CaviarDreams.ttf");
}
@Override
public int getCount() {
return dObj.size();
}
@Override
public Object getItem(int position) {
return dObj.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View view, ViewGroup parent) {
if(view==null){
holder = new ViewHolder();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.states_inflator_layout, null);
holder.textView = ((TextView)view.findViewById(R.id.stateNameInflator));
holder.checkImg=(ImageView)view.findViewById(R.id.checkBoxState);
view.setTag(holder);
}else{
holder = (ViewHolder) view.getTag();
}
holder.textView.setText(dObj.get(position).getCountryName());
holder.textView.setTypeface(itemFont);
if(position==selectedPosition)
{
holder.checkImg.setImageResource(R.drawable.check);
}
else
{
holder.checkImg.setImageResource(R.drawable.uncheck);
}
return view;
}
private class ViewHolder{
private TextView textView;
private ImageView checkImg;
}
public void getFilter(String name) {
dObj.clear();
if(!name.equals("")){
for (CountryDataObject item : completeList) {
if(item.getCountryName().toLowerCase().startsWith(name.toLowerCase(),0)){
dObj.add(item);
}
}
}
else {
dObj.addAll(completeList);
}
selectedPosition=-1;
notifyDataSetChanged();
notifyDataSetInvalidated();
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Registration reg=(Registration)context;
selectedPosition=position;
reg.setSelectedCountryCode("+"+dObj.get(position).getCountryCode());
notifyDataSetChanged();
}
}