Android ListView

ListView

示例(Kotlin)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/**
* ListView 的性能需要一些技巧来提升。
* ListView 的扩展性不够好,并且只能实现数据的纵向滚动效果。
*/
class ListViewActivity : BaseActivity(){

private val fruitList = ArrayList<FruitBean>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_lv)

// val data = intent.getStringArrayListExtra("param1")
// // 最好用的适配器 ArrayAdapter,它通过泛型来指定要适配的数据类型。
// // R.layout.simple_list_item_1 系统内置的布局文件,内部只有一个 TextView。
// val adapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,data)

initFruit()
val adapter = FruitLVAdapter(this, R.layout.item_fruit,fruitList)
lv.adapter = adapter
// lv.setOnItemClickListener{parent, view, position, id ->
// val fruit = fruitList[position]
// Toast.makeText(this,fruit.name,Toast.LENGTH_SHORT).show()
// }
// Kotlin 更加推荐将没有用到的参数使用下划线来替代,但参数的位置不能变。
lv.setOnItemClickListener{ _, _, position, _ ->
val fruit = fruitList[position]
Toast.makeText(this,fruit.name,Toast.LENGTH_SHORT).show()
}
}

private fun initFruit(){
// repeat 函数会将表达式内的内容执行 2 遍。
repeat(3){
fruitList.add(
FruitBean(
"Apple",
R.drawable.ic_launcher_background
)
)
fruitList.add(
FruitBean(
"Apple",
R.drawable.ic_launcher_background
)
)
fruitList.add(
FruitBean(
"Apple",
R.drawable.ic_launcher_background
)
)
fruitList.add(
FruitBean(
"Apple",
R.drawable.ic_launcher_background
)
)
fruitList.add(
FruitBean(
"Apple",
R.drawable.ic_launcher_background
)
)
fruitList.add(
FruitBean(
"Apple",
R.drawable.ic_launcher_background
)
)
fruitList.add(
FruitBean(
"Apple",
R.drawable.ic_launcher_background
)
)
fruitList.add(
FruitBean(
"Apple",
R.drawable.ic_launcher_background
)
)
}
}

companion object{
fun actionStart(context: Context){
val intent = Intent(context, ListViewActivity::class.java)
context.startActivity(intent)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class FruitLVAdapter(activity:Activity, val resourceId:Int, data:ArrayList<FruitBean>):
ArrayAdapter<FruitBean>(activity,resourceId,data){

/**
* 使用 ViewHolder 对控件实例进行缓存
* 使用 inner class 关键字来定义内部类
*/
inner class ViewHolder(val fruitImage:ImageView,val fruitName:TextView)

/**
* 提升 ListView 的运行效率
* 优化一:默认在 getView() 中每次都将布局重新加载一遍,当快速滚动时,会有性能瓶颈。
* 使用 convertView 参数优化,它用于将之前加载好的布局进行缓存。
* 优化二:每次仍会调用 findViewById() 获取一次控件的实例。
* 可借助一个 ViewHolder 来对这部分优化。
*/
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val view:View
val viewHolder : ViewHolder
if (convertView == null){
// false 表示只让我们在父布局中声明的 layout 生效,但不会为这个 View 添加父布局。
// 因为一旦 View 有了父布局后,它就不能再添加到 ListView 中了。
view = LayoutInflater.from(context).inflate(resourceId,parent,false)

// 'kotlin-android-extensions' 插件在适配器中是无法工作的。
// val ivItemFruit : ImageView = view.findViewById(R.id.ivItemFruit)
// val tvItemFruit : TextView = view.findViewById(R.id.tvItemFruit)
// 勘误:'kotlin-android-extensions' 插件在适配器中也能正常工作。
val ivItemFruit : ImageView = view.ivItemFruit
val tvItemFruit : TextView = view.tvItemFruit
viewHolder = ViewHolder(ivItemFruit ,tvItemFruit)
view.tag = viewHolder
}else{
view = convertView
viewHolder = view.tag as ViewHolder
}


// 获取当前项的 FruitBean 实例
val fruit = getItem(position)
if (fruit != null)
{
viewHolder.fruitImage.setImageResource(fruit.imgId)
viewHolder.fruitName.text = fruit.name
}
return view
}
}
1
class FruitBean (val name:String, val imgId:Int)

ListView(也适用于 GridView)的优化主要分三个方面:

  • 采用 ViewHolder 并避免在 getView 中执行耗时操作
  • 根据列表的滑动状态来控制任务的执行频率
  • 尝试开启硬件加速来使 ListView 的滑动更加流畅

其它优化方式比如:

  • Item布局,层级越少越好,使用hierarchyview工具查看优化。
  • 复用convertView
  • 使用ViewHolder
  • item中有图片时,异步加载
  • 快速滑动时,不加载图片
  • item中有图片时,应对图片进行适当压缩
  • 实现数据的分页加载