一路做一路学,感谢互联网给我们提供的资源
学习Android开发的小伙伴们都知道,List(列表)、Grid(表格)、RecycleView等使用的是适配器模式,即需要一个Adapter为视图提供数据。而在使用Adapter的时候,getView方法内含了复用机制,即子视图的对象会循环利用,以免造成OOM。
复用机制在早期的List等中,需要开发者手动实现,其示例如下:
此处的itemView是一个上图标下文字的布局。
inner class GridItemViewHolder(val root: View) {
var tvText: TextView
var ivIcon: ImageView
val views = SparseArray<View>()//Android推荐使用的集合框架,键值对形式存储
init {//作为主构造函数的方法体,且一定是第一个调用
tvText = getTextView(R.id.id_tv_grid_text)
ivIcon = getImageView(R.id.id_iv_grid_icon)
}
/**使用泛型优化控件的获取**/
fun <T : View> getView(id: Int): T {
var view = views[id]
if (view == null) {
view = root.findViewById(id)
views.put(id, view)
}
return view as T
}
//提供的附加方法
fun getTextView(id: Int): TextView = getView(id)
fun getImageView(id: Int): ImageView = getView(id)
fun setText(id: Int, text: String) {
getTextView(id).text = text
}
fun setIcon(id: Int, resId: Int) {
getImageView(id).setImageResource(resId)
}
}
ViewHolder的存在是利用复用机制可循环使用对象,让其携带(通过tag属性)一个Holder对象,Holder持有子视图控件的引用,从而循环利用子视图的控件,避免重复创建对象,拉高内存占用。
但为什么需要一个外部Holder对象呢?还有没有别的方法?我想,这些肯定是有人思考过的。它的根本就在于,复用机制需要的是子视图View的对象,而这个对象本身是无法改变的,只得在其拥有的Field、方法等上下手,其tag属性终被程序员发现,这才有了ViewHolder。
这种做法显然有它的限制,那就是Java语法的限制,它规定了在语言中的一切行为,才使得无法在对象本身开刀。那么,Kotlin呢?对了,Kotlin有扩展方法,可以使我们可以忘记ViewHolder,让复用的视图自己包含缓存方法,简化代码,So Happy。
代码如下:
fun <T : View> View.findViewOften(viewId: Int): T {
var viewHolder: SparseArray<View> =
tag as? SparseArray<View> ?: SparseArray()
tag = viewHolder
var childView: View? = viewHolder.get(viewId)
if (null == childView) {
childView = findViewById(viewId)
viewHolder.put(viewId, childView)
}
return childView as T
}
给View扩展一个方法,内部实现与ViewHolder相同的缓存机制,这可能有人会问了,View本身如何获取?Kotlin的扩展方法需要指定接收者类型,使用this关键字即可在方法内获取,在convertView(复用的子View对象)调用该方法是,方法体便可通过this操作接收者对象,因为复用的是同一个对象,那么缓存机制便因此而实现了。
说到这里,另一个问题随之出现,Google自5.0之后推出的RecycleView自带ViewHolder的实现,且必须传入,那这个方法如何去做呢?
当然会有:
class MyViewHolder(val convertView: View) : RecyclerView.ViewHolder(convertView) {
fun <T : View> findView(viewId: Int): T {
return convertView.findViewOften(viewId)
}
}
即使必须要ViewHolder,最终也是逃离不掉convertView的,通过ViewHolder下手即可。
欢迎提出更好的实现方案。
参考来源:http://www.jianshu.com/p/819ba04955a8
额外内容:
获取被声明在arrays数组中的资源ID
1.val typedArray = resources.obtainTypedArray(R.array.home_bar_icon)
2.val itemInfo = ItemInfo(stringArray[i], typedArray.getResourceId(i, 0))
通过对该数组获取typedArray,再获取resourceId
今天就写到这里,最近尽可能的在过好自己的生活,说到的要做到,不过放假难免有其他事,都做好互不影响并尽可能弥补自己吧
写于:2017年7月30日 20:55