如何刷新一个Android列表视图后添加/删除动态数据?
当前回答
如果你想从一个服务中更新UI listview,那么在你的Main活动中使适配器静态,并这样做:
@Override
public void onDestroy() {
if (MainActivity.isInFront == true) {
if (MainActivity.adapter != null) {
MainActivity.adapter.notifyDataSetChanged();
}
MainActivity.listView.setAdapter(MainActivity.adapter);
}
}
其他回答
请忽略所有的invalidate(), invalidateViews(), requestLayout(),…这个问题的答案。
正确的做法(幸运的是也被标记为正确答案)是在适配器上调用notifyDataSetChanged()。
故障排除
如果调用notifyDataSetChanged()不起作用,那么所有的布局方法也不会起作用。相信我,ListView已经正确更新了。如果您未能找到差异,则需要检查适配器中的数据来自何处。
如果这只是一个保存在内存中的集合,那么在调用notifyDataSetChanged()之前,请检查是否确实从集合中删除了项或向集合中添加了项。
如果使用的是数据库或服务后端,则必须在调用notifyDataSetChanged()之前调用该方法来再次检索信息(或操作内存中的数据)。
问题是这个notifyDataSetChanged只在数据集发生变化时有效。所以如果你没有发现变化,那就是你要看的地方。必要时进行调试。
ArrayAdapter vs BaseAdapter
我确实发现使用让您管理集合的适配器(如BaseAdapter)工作得更好。一些适配器(如ArrayAdapter)已经管理了自己的集合,因此很难获得适当的集合进行更新。在大多数情况下,这只是一个不必要的额外难度。
哎哟几天前
的确,这个必须从UI线程调用。其他答案有如何实现这一目标的例子。然而,只有当你在UI线程之外处理这些信息时,才需要这样做。它来自服务或非UI线程。在简单的情况下,您将通过单击按钮或其他活动/片段更新数据。仍然在UI线程中。不需要总是弹出runOnUiTrhead。
快速示例项目
可以在https://github.com/hanscappelle/so-2250770.git上找到。只需克隆并在Android Studio (gradle)中打开项目。这个项目有一个mainactitivity构建一个包含所有随机数据的ListView。可以使用操作菜单刷新此列表。
我为这个示例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
}
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();
}
}
更多的信息
另一篇关于listViews功能的好文章可以在这里找到:http://www.vogella.com/articles/AndroidListView/article.html
在其他选项是onWindowFocusChanged方法,但肯定它敏感,需要一些额外的编码谁感兴趣
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
// some controls needed
programList = usersDBHelper.readProgram(model.title!!)
notesAdapter = DailyAdapter(this, programList)
notesAdapter.notifyDataSetChanged()
listview_act_daily.adapter = notesAdapter
}
我有一些问题与动态刷新我的列表视图。
在适配器上调用notifyDataSetChanged()。 关于如何/何时调用notifyDataSetChanged()的其他细节可以在这个谷歌I/O视频中查看。
在我的情况下notifyDataSetChanged()没有正常工作[我从另一个类调用notifyDataSetChanged]。只是在这种情况下,我编辑了ListView在运行的活动(线程)。多亏了克里斯托弗,这个视频给了我们最后的提示。
在我的第二节课上,我用了
Runnable run = new Runnable(){
public void run(){
contactsActivity.update();
}
};
contactsActivity.runOnUiThread(run);
访问update()从我的活动。此更新包括
myAdapter.notifyDataSetChanged();
来告诉适配器刷新视图。 在我看来还不错。
如果我在这里谈论我的场景,上面的答案都不会起作用,因为我有一个显示db值列表的活动,同时还有一个删除按钮,当按下删除按钮时,我想从列表中删除该项。
最酷的是,我没有使用回收器视图,而是使用了一个简单的列表视图,该列表视图在适配器类中初始化。因此,调用notifyDataSetChanged()不会在适配器类内部执行任何操作,甚至不会在初始化了适配器对象的活动类中执行任何操作,因为delete方法位于适配器类中。
因此,解决方案是在适配器类getView方法中从适配器中删除对象(仅删除特定对象,但如果您想删除所有对象,则调用clear())。
为了让你们了解我的代码是什么样的,
public class WordAdapter extends ArrayAdapter<Word> {
Context context;
public WordAdapter(Activity context, ArrayList<Word> words) {}
//.......
@NonNull
@Override
public View getView(final int position, View convertView, ViewGroup group) {
//.......
ImageButton deleteBt = listItemView.findViewById(R.id.word_delete_bt);
deleteBt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (vocabDb.deleteWord(currentWord.id)) {
//.....
} else{
//.....
}
remove(getItem(position)); // <---- here is the trick ---<
//clear() // if you want to clear everything
}
});
//....
注意:这里remove()和getItem()方法继承自Adapter类。
Remove() -删除所单击的特定项 getItem(position) -用于获取项目(在这里,这是我的Word对象 我已经添加到列表)从点击的位置。
这就是我如何在活动类中将适配器设置为listview,
ArrayList<Word> wordList = new ArrayList();
WordAdapter adapter = new WordAdapter(this, wordList);
ListView list_view = (ListView) findViewById(R.id.activity_view_words);
list_view.setAdapter(adapter);
我认为这取决于你对刷新的定义。您的意思是应该刷新GUI显示,还是应该刷新子视图,以便您可以通过编程调用getChildAt(int)并获得与适配器中内容对应的视图?
如果希望刷新GUI显示,则调用适配器上的notifyDataSetChanged()。下次重绘时,GUI将被刷新。
如果您希望能够调用getChildAt(int)并获得反映适配器中的内容的视图,则调用layoutChildren()。这将导致从适配器数据重构子视图。
推荐文章
- 在应用程序本身中更改Locale
- apk (.apk)和应用程序包(.aab)的区别
- 如何设置超时在改造库?
- Android - SPAN_EXCLUSIVE_EXCLUSIVE跨度不能为零长度
- TextView的字体大小在Android应用程序改变字体大小从本机设置
- 如何模拟Android杀死我的进程
- 禁用EditText闪烁光标
- Android Eclipse -无法找到*.apk
- 设置TextView文本从html格式的字符串资源在XML
- 如何允许所有网络连接类型HTTP和HTTPS在Android(9)馅饼?
- Android加载JS包失败
- Android Studio, logcat在应用程序关闭后清理
- 在android中从上下文获取活动
- 无法解析主机"<URL here>"没有与主机名关联的地址
- getActivity()在Fragment函数中返回null