赞
踩
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
编译后,AGP会为Module中包含的XML布局文件生成一个绑定类,类名规则:
XML文件名转换为Pascal大小写,并加上Binding,比如:result_profile.xml → ResultProfileBinding。
// View已存在
fun bind(view : View) : T
// View未存在
fun inflate(inflater : LayoutInflater) : T
fun inflate(inflater : LayoutInflater, parent : ViewGroup?, attachToParent : Boolean) : T
接下来演示一波各种场景下的ViewBinding用法,其实都是围绕上述三个API进行的~
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 1、实例化绑定实例
binding = ActivityMainBinding.inflate(layoutInflater)
// 2、获得对根视图的引用
val view = binding.root
// 3、让根视图称为屏幕上的活动视图
setContentView(view)
// 4、引用视图控件
binding.tvContent.text = “修改TextView文本”
}
}
class ContentFragment: Fragment() {
private var _binding: FragmentContentBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentContentBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.ivLogo.visibility = View.GONE
}
override fun onDestroyView() {
super.onDestroyView()
// Fragment的存活时间比View长,务必在此方法中清除对绑定类实例的所有引用
// 否则会引发内存泄露
_binding = null
}
}
如果布局已inflated,还可以采用另一种写法(调bind):
class TestFragment: Fragment(R.layout.fragment_content) {
private var _binding: FragmentContentBinding? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val binding = FragmentContentBinding.bind(view)
_binding = binding
binding.ivLogo.visibility = View.VISIBLE
}
override fun onDestroyView() {
super.onDestroyView()
// 同样需要置空
_binding = null
}
}
如果是继承DialogFragment写法同Fragment,如果是继承Dialog写法示例如下(PopupWindow类似)~
class TestDialog(context: Context) : Dialog(context) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DialogTestBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.tvTitle.text = “对话框标题”
}
}
class TestAdapter(list: List) : RecyclerView.Adapter<TestAdapter.ViewHolder>() {
private var mList: List = list
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
// 需在此初始化以获得父类容器
val binding = ItemTestBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.tvItem.text = “Adapter”
}
override fun getItemCount() = mList.size
// 传递Binding对象
class ViewHolder(binding: ItemTestBinding) : RecyclerView.ViewHolder(binding.root) {
var tvItem: TextView = binding.tvItem
}
}
ViewGroup子类才能使用视图绑定,View子类不可使用,示例如下:
class TestLayout: LinearLayout {
constructor(context: Context): super(context)
constructor(context: Context, attrs: AttributeSet): super(context, attrs) {
val inflater = LayoutInflater.from(this.context)
val binding = ItemLayoutBinding.inflate(inflater, this, true)
binding.tvLayout.text = “自定义ViewGroup”
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
}
}
根据include的布局xml是否带**标签**,分为两种,先是不带的情况:
include的xml文件名为sub_include_test.xml,id为include_layout:
然后是带的情况,布局文件改下:
使用部分的代码不变,运行奔溃报错信息如下:
原因是merge并不会加载到布局里,解法:把include标签的id去掉,然后bind传入父布局~
基础用法很简单,也很好上手,但存在下述问题:
需重复编写:创建和回收ViewBinding实例的样板代码,特别是Fragment,还要手动置空。
所以有必要封装优化一波~
最容易想到的常规写法,配合泛型,把模板代码都在父类中写好,非常简单:
abstract class BaseFragment(layoutId: Int) : Fragment(layoutId) {
private var _binding: T? = null
val binding get() = _binding!!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = initBinding(view)
init()
}
abstract fun initBinding(view: View): T
abstract fun init()
override fun onDestroyView() {
_binding = null
super.onDestroyView()
}
}
// 子类实现
class TestFragment : BaseFragment(R.layout.fragment_content) {
override fun initBinding(view: View) = FragmentContentBinding.bind(view)
override fun init() {
binding.ivLogo.visibility = View.VISIBLE
}
}
有些朋友可能觉得写在父类中侵入性太强,接着试下用其他方式进行封装,先看原始Activity:
要把圈住的代码干掉,先是 泛型传递问题,泛型在进JVM前会被擦除,可在运行时通过反射获得,还可以通过实例化类类型代替类引用,如:
fun <T: Activity> FragmentActivity.startActivity(context: Context, clazz: Class) {
startActivity(Intent(context, clazz))
}
// 调用处
startActivity(context, MainActivity::class.java)
而在Kotlin中还可以用 inline 定义一个 内联函数 (编译时自动替换到调用位置),配合 reified 具体化(类型不擦除),得到泛型类型的Class,如:
inline fun Activity.startActivity(context: Context) {
startActivity(Intent(context, T::class.java))
}
// 调用
startActivity(context)
可以,配合反射invoke()调用,随手写上一个扩展方法:
调用下:
看似十拿九稳,结果一跑就崩:
不过也在意料之内,Activity还没onCreate()就初始化了,不空才怪,可以利用 标准委托-lazy 延迟初始化,修改后的代码:
调用下:
运行通过,你还可以把还可以把setContentView()也塞到扩展中:
配合lifecycle组件,顺手把Fragment的也写出来:
调用下:
对了,如果还不想使用反射,可以利用Kotlin高阶函数,示例如下:
调用下:
啧啧啧,你还可以不用lazy,自己重写ReadOnlyProperty,这里只是试试水封装,并没用到生产上,更完善的封装方案可自行参考下述开源库:
AGP会为模块中每个XML生成一个绑定类,该类的实例会直接引用布局中声明了资源id的View
打开:module模块名/build/generated/intermediates/javac/渠道/包名/databinding
可以看到 (基于AGP 7.1.1,不同AGP版本可能不一样):
自动生成的class文件,随手打开一个:
所以本质上还是findViewById,只是自动生成了控件实例,并一一对应,接着简单了解下大概的生成流程。
执行gradlew assembleDebug,在Task构建列表没找到ViewBinding,却找到了DataBinding:
打开AGP源码,全局搜 dataBindingMergeGenClasses → DataBindingMergeBaseClassLogTask.kt
跟到:TaskManager.kt → createDataBindingTasksIfNecessary
2333,跟DataBinding混一起了,所以 ViewBinding其实只是DataBinding功能的一小部分~
看回:DataBindingMergeBaseClassLogTask
,增量和全量执行动作:
跟下:DataBindingMergeBaseClassLogDelegate
跟下:DataBindingMergeBaseClassLogRunnable
判断文件是否新建、修改、或移除,跟下是哪个文件:
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**
[外链图片转存中…(img-FZmBtpdz-1715908445982)]
[外链图片转存中…(img-uJNtl0tY-1715908445982)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。