Android ListView.setOnItemClickListener NullPointerException 当有更多项目时屏幕可以容纳
当此 ListView 有更多项目时,可以在屏幕上显示(您必须滚动才能看到其他项目),并且您选择其中一项我得到 NullPointerException
这是代码:
studentList = (ListView)findViewById(R.id.studentListView);
getAllStudents();
studentList.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> a, View v, int position, long id) {
for (int i = 0; i < studentList.getCount(); i++){
if (i == position){
studentList.getChildAt(i).setBackgroundResource(R.color.selectedListViewBg);
}
else{
studentList.getChildAt(i).setBackgroundResource(R.color.listViewBg);
}
}
从数据库中提取学生并将其添加到StudentList ArrayAdapter:
getAllStudents();
我得到异常:
studentList.getChildAt(i).setBackgroundResource(R.color.<either one>);
如果 ListView 可以容纳所有项目而无需滚动,则可以选择而不出现 NullPointerException
我做错了什么?
编辑:
阅读此问题的答案后,我决定更改程序这部分的逻辑。
我可能应该解释一下我试图做得更好:
我有一个充满学生的 ListView。底部还有一个按钮,上面写着“下一步”。我希望用户能够单击他们的选择并更改背景颜色。这部分代码应该将所选项目的背景更改为一种颜色,并将所有其他项目的背景更改回原始颜色。
我的解决方案: 当用户单击 ListView 项目时,我摆脱了该按钮并转到下一页。
When this ListView has more items then can be shown on the screen (you have to scroll to see the others) and you select one of the items I get a NullPointerException
Here is the code:
studentList = (ListView)findViewById(R.id.studentListView);
getAllStudents();
studentList.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> a, View v, int position, long id) {
for (int i = 0; i < studentList.getCount(); i++){
if (i == position){
studentList.getChildAt(i).setBackgroundResource(R.color.selectedListViewBg);
}
else{
studentList.getChildAt(i).setBackgroundResource(R.color.listViewBg);
}
}
To pull the students from the database and add them to the studentList ArrayAdapter:
getAllStudents();
I get the Exception at:
studentList.getChildAt(i).setBackgroundResource(R.color.<either one>);
If the ListView can hold all the items without having to scroll, you can select without the NullPointerException
What am I doing wrong?
EDIT :
After reading the answers to this question, I decided to change the logic at this part of my program.
I probably should have explained what I was trying to do better:
I have a ListView that is populated with students. There is also a button at the bottom that says "Next". I wanted the user to be able to click on their choice and have the background color change. This section of code was supposed to change the selected item's background to one color and all the other item's backgrounds back to the original color.
My Solution:
I got rid of the button and move on to the next page when the user clicks on the ListView item.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
getChildAt()
返回屏幕中指定索引处的 ListView 的子视图。这将只包含当前渲染的内容(ListView 子视图被回收),因此它总是从 0 到大约 7(例如)。因此,如果您有超过 8 名学生,您将尝试获得第 9 名的学生,但该位置并不存在。然而,您的代码的问题(如果它正常工作)是您需要在模型内部存储“选定”状态,否则一旦您滚动,背景颜色将恢复为原始颜色。
我建议添加一个复选框小部件并将其设置为选中/未选中。您仍然需要将此信息保存在模型中,并在回收时(在 getView() 中)相应地设置复选框状态,但在 Android 环境中,它比使用背景颜色作为“选定指示器”更有意义。
但要回答最初的问题,“修复”代码的最简单方法是利用您获得的 View 参数(v)。
但同样,您会发现,一旦您滚动,这并不会真正起作用。
getChildAt()
returns to you the child View of the ListView at the specified index in the screen. This will only encompass what is currently rendered (ListView children views are recycled), so it will always go from 0 to about 7 (for example). So if you have more than 8 students you're trying to get the one at the 9th position, which does not exist.However, the problem with your code (if it were working) is that you would need to store the "selected" state internally in your model anyway, otherwise once you scroll the background color will go back to being the original one.
I would suggest adding a checkbox widget and set that as checked/unchecked. You will still need to save this information in your model and set the checkbox state accordingly when recycling (in getView()) but it will make more sense in an Android environment than using the background color as a "selected indicator".
But to answer the original question, the easiest way to "fix" your code is to make use of the View argument that you're getting (the v).
But again, you will notice this will not really work as soon as you scroll.
引用自 Android 开发者参考
如果
ListView
容纳的项目数量超过了屏幕可以显示的数量,那么不可见的列表项目行将被循环持有,当然,它们将为 NULL。当您尝试向上/向下滚动以显示它们时,它们将膨胀显示(调用 getView() 方法来膨胀这些项目)。因此,您只能使用屏幕上可见的所有项目行(您可以看到它们)。
解决方案是使用这两个方法:
getFirstVisibleItem()
和getLastVisibleItem()
。除非您知道自己在做什么,否则不要使用getChildAtPosition()
。Quote from Android Developers' Reference
If the
ListView
holds more items than screen can display, then the invisible list item row will be held in a cycle, of course, they would be NULL. And when you're trying to scroll up/down to display them, they will be inflated to display (getView()
method is called to inflate these items).So you can only use all item rows that are visible on screen (you can see them).
The solution is to use these two methods:
getFirstVisibleItem()
andgetLastVisibleItem()
. Don't usegetChildAtPosition()
unless you know what you're doing.