内容简介:最近断断续续地把项目的界面部分的代码由JAva改成了Kotlin编写,并且如果应用了下面我们来解析下原理。因为kotlin也是一门JVM语言,最近也会和java一样编译成class字节码,所以我们直接来反编译看看生成的java文件。选择
最近断断续续地把项目的界面部分的代码由 JAva 改成了Kotlin编写,并且如果应用了 kotlin-android-extensions
插件,一个显而易见的好处是再也不用写 findViewById()
来实例化你的控件对象了,直接操作你在布局文件里的id即可,这一点我感觉比 butterknife
做的还简洁友好。
Activity
import android.support.v7.app.AppCompatActivity import android.os.Bundle import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) textview.text="hello world" } } 复制代码
下面我们来解析下原理。因为kotlin也是一门JVM语言,最近也会和java一样编译成class字节码,所以我们直接来反编译看看生成的java文件。
选择 Decompile
,解析出来的代码如下
public final class MainActivity extends AppCompatActivity { private HashMap _$_findViewCache; protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(2131296284); TextView var10000 = (TextView)this._$_findCachedViewById(id.textview); Intrinsics.checkExpressionValueIsNotNull(var10000, "textview"); var10000.setText((CharSequence)"hello world"); } public View _$_findCachedViewById(int var1) { if (this._$_findViewCache == null) { this._$_findViewCache = new HashMap(); } View var2 = (View)this._$_findViewCache.get(var1); if (var2 == null) { var2 = this.findViewById(var1); this._$_findViewCache.put(var1, var2); } return var2; } public void _$_clearFindViewByIdCache() { if (this._$_findViewCache != null) { this._$_findViewCache.clear(); } } } 复制代码
可以很清楚看到最终还是调用了 findViewById()
,不过获取View对象直接调用的是 findCachedViewById
,并且创建一个 HashMap 进行View对象的缓存,避免每次调用 View 时都会重新调用 findViewById()
进行查找。
Fragment
再来看下 Fragment
中的使用:
import android.os.Bundle import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import kotlinx.android.synthetic.main.fragment_blank.* class BlankFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_blank, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) textview_fra.text="hello world" } } 复制代码
反编译后代码如下
public final class BlankFragment extends Fragment { private HashMap _$_findViewCache; @Nullable public View onCreateView(@NotNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { Intrinsics.checkParameterIsNotNull(inflater, "inflater"); return inflater.inflate(2131296285, container, false); } public void onViewCreated(@NotNull View view, @Nullable Bundle savedInstanceState) { Intrinsics.checkParameterIsNotNull(view, "view"); super.onViewCreated(view, savedInstanceState); TextView var10000 = (TextView)this._$_findCachedViewById(id.textview_fra); Intrinsics.checkExpressionValueIsNotNull(var10000, "textview_fra"); var10000.setText((CharSequence)"hello world"); } public View _$_findCachedViewById(int var1) { if (this._$_findViewCache == null) { this._$_findViewCache = new HashMap(); } View var2 = (View)this._$_findViewCache.get(var1); if (var2 == null) { View var10000 = this.getView(); if (var10000 == null) { return null; } var2 = var10000.findViewById(var1); this._$_findViewCache.put(var1, var2); } return var2; } public void _$_clearFindViewByIdCache() { if (this._$_findViewCache != null) { this._$_findViewCache.clear(); } } // $FF: synthetic method public void onDestroyView() { super.onDestroyView(); this._$_clearFindViewByIdCache(); } } 复制代码
可以看到最终是通过调用 getView().findViewById()
来进行控件的实例化。 看下getView()源码
@Nullable public View getView() { return this.mView; } 复制代码
再看下mView成员变量的赋值时机:
void performCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { if (this.mChildFragmentManager != null) { this.mChildFragmentManager.noteStateNotSaved(); } this.mPerformedCreateView = true; this.mViewLifecycleOwner = new LifecycleOwner() { public Lifecycle getLifecycle() { if (Fragment.this.mViewLifecycleRegistry == null) { Fragment.this.mViewLifecycleRegistry = new LifecycleRegistry(Fragment.this.mViewLifecycleOwner); } return Fragment.this.mViewLifecycleRegistry; } }; this.mViewLifecycleRegistry = null; this.mView = this.onCreateView(inflater, container, savedInstanceState); if (this.mView != null) { this.mViewLifecycleOwner.getLifecycle(); this.mViewLifecycleOwnerLiveData.setValue(this.mViewLifecycleOwner); } else { if (this.mViewLifecycleRegistry != null) { throw new IllegalStateException("Called getViewLifecycleOwner() but onCreateView() returned null"); } this.mViewLifecycleOwner = null; } } 复制代码
可以看到 mView
其实就是 onCreateView()
的返回值,所以我们不能在 onCreateView()
方法里操作控件ID的方式操作View对象,会产生空指针异常。建议在 onViewCreated()
方法里使用。
以上所述就是小编给大家介绍的《Kotlin直接使用控件ID原理解析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- react-lazyload懒加载控件源码解析
- WindowsXamlHost:在 WPF 中使用 UWP 控件库中的控件
- WindowsXamlHost:在 WPF 中使用 UWP 控件库中的控件
- Flutter控件--Scaffold
- Flutter控件--AppBar
- Flutter 手势密码控件
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
深入React技术栈
陈屹 / 人民邮电出版社 / 2016-11-1 / CNY 79.00
全面讲述React技术栈的第一本原创图书,pure render专栏主创倾力打造 覆盖React、Flux、Redux及可视化,帮助开发者在实践中深入理解技术和源码 前端组件化主流解决方案,一本书玩转React“全家桶” 本书讲解了非常多的内容,不仅介绍了面向普通用户的API、应用架构和周边工具,还深入介绍了底层实现。此外,本书非常重视实战,每一节都有实际的例子,细节丰富。我从这......一起来看看 《深入React技术栈》 这本书的介绍吧!