内容简介:最近断断续续地把项目的界面部分的代码由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 手势密码控件
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Agile Web Development with Rails, Third Edition
Sam Ruby、Dave Thomas、David Heinemeier Hansson / Pragmatic Bookshelf / 2009-03-17 / USD 43.95
Rails just keeps on changing. Rails 2, released in 2008, brings hundreds of improvements, including new support for RESTful applications, new generator options, and so on. And, as importantly, we’ve a......一起来看看 《Agile Web Development with Rails, Third Edition》 这本书的介绍吧!