Kotlin-Android-Extensions:不仅仅是替代findViewById
来源:互联网 发布:分答软件下载 编辑:程序博客网 时间:2024/06/06 06:43
kotlin-android-extensions
是kotlin为Android专门提供的扩展插件,虽然现在其提供的功能不多,但是光是替代findViewById
功能,就已经值得使用了。至于以后官方是否会提供更多的功能,让Android开发更快速便捷,就只能拭目以待了。
module:app -> build.gradle 添加以下代码
apply plugin: 'kotlin-android-extensions'
和findViewById说再见
直接上实例,布局文件activity_main
<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="cn.andrlin.kotlin.demo.MainActivity"> <TextView android:id="@+id/helloTv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /></android.support.constraint.ConstraintLayout>
Activity主要代码:
import kotlinx.android.synthetic.main.activity_main.*class TestActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) helloTv.text = "Hello Kotlin!" }}
我们不需要使用findViewById
来获取控件,只需要使用控件的id
就可以操作控件的相关方法。当然大家也发现了import
,没错,这也是必须的,AndroidStudio会自动为你添加。如果你不嫌麻烦,手动写也是没毛病的。
import
格式是这样的:kotlinx.android.synthetic.main.布局名称.*
。需要注意的是include
进来的布局,也是需要通过import
导入相应布局,这样才能正常使用。
建议布局文件中id的命名规则和java类中的命名规则保持一致,都使用驼峰命名。
真的是和findViewById说再见了吗?
AndroidStudio中可以直接打开kotlin Bytecode
,进行反编译查看编译后的代码。 Tools->Kotlin->Show Kotlin Bytecode->Decompile
查看编译后的代码,我们可以发现很有趣的东西。
... private HashMap _$_findViewCache; protected void onCreate(@Nullable Bundle savedInstanceState) { ... ((TextView)this._$_findCachedViewById(id.helloTv)).setText((CharSequence)"Hello Kotlin!"); } public View _$_findCachedViewById(int var1) { if(this._$_findViewCache == null) { this._$_findViewCache = new HashMap(); } View var2 = (View)this._$_findViewCache.get(Integer.valueOf(var1)); if(var2 == null) { var2 = this.findViewById(var1); this._$_findViewCache.put(Integer.valueOf(var1), var2); } return var2; } public void _$_clearFindViewByIdCache() { if(this._$_findViewCache != null) { this._$_findViewCache.clear(); } }...
代码很简单,在第一次使用控件的时候,在缓存集合中进行查找,有就直接使用,没有就通过findViewById
进行查找,并添加到缓存集合中。其还提供了_$_clearFindViewByIdCache()
方法用于清除缓存,在我们想要彻底替换界面控件时可以使用到。
我们再来看看Fragment中使用,编译过后的代码是如何的。
private HashMap _$_findViewCache; ... public void onViewCreated(@Nullable View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); ((TextView)this._$_findCachedViewById(id.helloTv)).setText((CharSequence)"Hello Fragment By Kotlin!"); } public View _$_findCachedViewById(int var1) { if(this._$_findViewCache == null) { this._$_findViewCache = new HashMap(); } View var2 = (View)this._$_findViewCache.get(Integer.valueOf(var1)); if(var2 == null) { View var10000 = this.getView(); if(var10000 == null) { return null; } var2 = var10000.findViewById(var1); this._$_findViewCache.put(Integer.valueOf(var1), var2); } return var2; } public void _$_clearFindViewByIdCache() { if(this._$_findViewCache != null) { this._$_findViewCache.clear(); } } // $FF: synthetic method public void onDestroyView() { super.onDestroyView(); this._$_clearFindViewByIdCache(); }
和Activity的唯一区别就是在onDestroyView()
方法中调用了_$_clearFindViewByIdCache()
,来清楚缓存,所以我们不用担心在View销毁的时候,缓存不能及时释放的问题。
到这里,我想大家肯定很清楚了,我们并没有完全的离开findViewById
,只是kotlin的扩展插件利用缓存的方式让我们开发更方便、更快捷。
ViewHolder中如何使用Extansions
刚开始使用kotlin的时候,唯一觉得不太好的就是ViewHolder中不能使用kotlin扩展替代findViewById
。但是在八月kotlin更新的1.1.4
版本中,做了相应的更新。
Android Extensions plugin now supports not only Activities and Fragments, but also custom Views and even custom layout containers such as a ViewHolder. Also, variants are now fully supported.
使用1.1.4
版本的kotlin-android-extensions
增强功能,需要在build.gradle
中开启实验性标志:
androidExtensions { experimental = true}
接下来我们就可以试着去编写ViewHolder了,只需要实现LayoutContainer
接口,该接口只提供了一个containerView
,用于存储视图,具体作用看编译后源码:
import android.support.v7.widget.RecyclerViewimport android.view.Viewimport kotlinx.android.extensions.LayoutContainerimport kotlinx.android.synthetic.main.activity_main.*class ViewHolder constructor(override val containerView: View?) : RecyclerView.ViewHolder(containerView), LayoutContainer { fun setContent(str: String) { helloTv.text = str }}
编译后代码:
public final class ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder implements LayoutContainer { @Nullable private final View containerView; private HashMap _$_findViewCache; public final void setContent(@NotNull String str) { Intrinsics.checkParameterIsNotNull(str, "str"); ((TextView)this._$_findCachedViewById(id.helloTv)).setText((CharSequence)str); } @Nullable public View getContainerView() { return this.containerView; } public ViewHolder(@Nullable View containerView) { super(containerView); this.containerView = containerView; } public View _$_findCachedViewById(int var1) { if(this._$_findViewCache == null) { this._$_findViewCache = new HashMap(); } View var2 = (View)this._$_findViewCache.get(Integer.valueOf(var1)); if(var2 == null) { View var10000 = this.getContainerView(); if(var10000 == null) { return null; } var2 = var10000.findViewById(var1); this._$_findViewCache.put(Integer.valueOf(var1), var2); } return var2; } public void _$_clearFindViewByIdCache() { if(this._$_findViewCache != null) { this._$_findViewCache.clear(); } }}
ViewHolder初始化的时候,将传进来的view存储在containerView
变量中,和Activity的_$_findCachedViewById
一样,ViewHolder中的使用的是containerView.findViewById
,即通过传进来的View
进行View.findViewById
,从而获取控件。
使用ContainerOptions修改View的缓存类型
默认View的缓存是是使用的HashMap来做的,官方提供了注解的方式来进行修改:
@ContainerOptions(CacheImplementation.SPARSE_ARRAY)class TestActivity : AppCompatActivity() { ...}
CacheImplementation
提供了三种方式:
public enum class CacheImplementation { SPARSE_ARRAY, HASH_MAP, NO_CACHE; public val hasCache: Boolean get() = this != NO_CACHE companion object { val DEFAULT = HASH_MAP }}
当然某些时候你只在Activity加载的时候,使用一次控件,那么就可以选择NO_CACHE
,我们可以来看一下其编译后的源码:
@ContainerOptions( cache = CacheImplementation.NO_CACHE)...public final class TestActivity extends AppCompatActivity { protected void onCreate(@Nullable Bundle savedInstanceState) { ... ((TextView)this.findViewById(id.helloTv)).setText((CharSequence)"Hello Kotlin!"); }}
没错,当你每次使用控件的时候,都会通过findViewById
进行查找获取控件,将不会再有_$_findCachedViewById
方法,在特殊情况下不使用缓存可能会更好,所以应根据不同的情况来决定使用哪种缓存方式。
Parcelable 扩展
1.1.4
版本中新增了通过注解的方式实现Parcelable。
@Parcelizeclass User(val firstName: String, val lastName: String) : Parcelable
值得注意的是此方法也是处于实验阶段,也需要在build.gradle
文件中开启实验性标志,其他Parcelable相关请查看官方详情
- Kotlin-Android-Extensions:不仅仅是替代findViewById
- Kotlin Android Extensions- 与 findViewById 说再见 (KAD 04) -- 更新版
- < Kotlin > Kotlin Android Extensions (译文)
- Use Kotlin Android Extensions
- 不仅仅是修改(Android EditText光标)
- Kotlin Android Extensions工具使用
- kotlin初窥之Kotlin Android Extensions
- Kotlin学习之kotlin-android-extensions
- Kotlin开发Android笔记10:Kotlin中Kotlin Android Extensions
- 婚姻不仅仅是爱情、、、
- 不仅仅是便宜
- 不仅仅是土豆
- 不仅仅是硬件部门
- 不仅仅是开源
- 推理不仅仅是感觉
- PASCAL不仅仅是语言
- 编程不仅仅是decode
- 设计不仅仅是粉饰
- Leetcode之Maximum Product of Three Numbers 问题
- m序列的原理以及verilog实现
- zk应用实例
- PullToRefresh
- 细谈C语言中的strcpy,strncpy,memcpy,memmove,memset函数
- Kotlin-Android-Extensions:不仅仅是替代findViewById
- Caffe 使用Python绘制网络结构图是遇到的错误
- React Native 错误 Module does not exist in the module map
- 购物车MainActivity
- Hbase 常见问题及设置
- 异常
- 计算1-1/2+1/3-....+1/99-1/100的值
- 购物车Adapter
- Hash Table -- Leetcode problem350. Intersection of Two Arrays II