【FirstKotlinApp】使用Kotllin封装Adapter时ViewHolder的一点技巧

来源:互联网 发布:易通网络平台 编辑:程序博客网 时间:2024/06/05 20:55

一路做一路学,感谢互联网给我们提供的资源

学习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数组中的资源ID1.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

阅读全文
1 0
原创粉丝点击