获取视图控件的方法findViewById、kotlin-android-extensions、ViewBinding

kotlin-android-extensions和ViewBinding

findViewById

使用findViewById时,最终会调用ViewGroup中的findViewTraversal,这个方法会遍历所有的子View,形成一个递归查询,找到最末端(View中)。如果找到就会返回这个View并停止查询,如果没找到就会返回为null。在确定要查找的那个View在某个View中的时候,我们调用那个View.findViewById()方法,会减少查询的循环次数,提高效率。

View类似于树的叶子节点,它没有子布局(节点),所以他的遍历很简单,就是简单比较id是否相等,相等就返回当前View,不相等则返回null

kotlin-android-extensions

原理

这个插件会生成一个_$_findCachedViewById()函数(防止和开发者定义的函数名冲突),在这个函数中首先会尝试从一个HashMap中找资源id所对应的控件实例,如果还没有缓存这个控件实例的话,就调用findViewById()函数来查找,并写入HashMap缓存当中。

缺点

每个Activity都需要额外的HashMap来存储控件实例,增加了内存开支。

如果多个布局中,控件使用了相同的id会混淆的,造成意想不到的错误。

ViewBinding

也是为了避免编写findViewById

设置

android {
    ...
    buildFeatures {
        viewBinding true
    }
}

使用

启动此功能后,每一个布局文件都生成一个对应的Binding类。Binding类的命名规则是将布局文件按驼峰重命名后,再加上Binding作为结尾。

Activity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.textView.text = "Hello"
    }
}

// 没有使用ViewBinding
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
				val textView = this.findViewById(R.id.textView)
    }
}

如果需要在onCreate()函数之外的地方对控件进行操作,那就需要将binding变量声明成全局变量,在onCreate中初始化。

Fragment

class MainFragment : Fragment() {

    private var _binding: FragmentMainBinding? = null

    private val binding get() = _binding!!

		// fragment在onCreateView加载布局,所以在这里初始化_binding
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        _binding = FragmentMainBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

}

Adapter

class MyAdapter(val list: List<String>) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {

    inner class ViewHolder(binding: ItemBinding) : RecyclerView.ViewHolder(binding.root) {
        val textView: TextView = binding.textView
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return ViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val string = list[position]
        holder.textView.text = fruit.name
    }

    override fun getItemCount() = list.size

}

RecyclerView.ViewHolder它只会接收View类型的参数,binding.root获得布局根元素的实例传给RecyclerView.ViewHolder。

你可能感兴趣的:(android,android,kotlin)