麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 開發 > 綜合 > 正文

Kotlin如何直接使用控件ID原理詳析

2024-07-21 23:03:51
字體:
來源:轉載
供稿:網友

前言

最近斷斷續續地把項目的界面部分的代碼由JAva改成了Kotlin編寫,并且如果應用了kotlin-android-extensions插件,一個顯而易見的好處是再也不用寫 findViewById()來實例化你的控件對象了,直接操作你在布局文件里的id即可,這一點我感覺比butterknife做的還簡潔友好。

Activity

import android.support.v7.app.AppCompatActivityimport android.os.Bundleimport 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" }}

其中kotlinx.android.synthetic.main.activity_main.*是kotlin-android-extensions插件自動生成的。下面我們來解析下原理。因為kotlin也是一門JVM語言,最近也會和java一樣編譯成class字節碼,所以我們直接來反編譯看看生成的java文件。

Kotlin,控件ID

選擇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.Bundleimport android.support.v4.app.Fragmentimport android.view.LayoutInflaterimport android.view.Viewimport android.view.ViewGroupimport 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()方法里使用。

其他(動態布局)

除了Activity和Fragment,我們用的最多的UI布局當屬Adapter了,kotlin-android-extensions也提供了對這一類動態布局的支持。因為這一功能是實現性質的,默認關閉,我們需要手動打開,在build.gradle中開啟:

androidExtensions { experimental = true}

然后再recycler.adapter中使用如下:

import kotlinx.android.extensions.LayoutContainerimport kotlinx.android.synthetic.main.item_recyclerview.*class MyAdapter(val context: Context, val data: List<String>) : RecyclerView.Adapter<MyAdapter.ViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {  val view = LayoutInflater.from(context).inflate(R.layout.item_recyclerview, parent, false)  return ViewHolder(view) } override fun onBindViewHolder(holder: ViewHolder, position: Int) {  holder.name_tv.text = data[position]  holder.itemView.setOnClickListener {   Toast.makeText(context,"點擊了第$position 項",Toast.LENGTH_SHORT).show()  } } override fun getItemCount(): Int {  return data.size } inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), LayoutContainer {  override val containerView: View = itemView }}

可以看到相比Activity和Fragment,我們的ViewHolder需要多實現一個接口LayoutContainer。看下它的源碼:

 public final class ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder implements LayoutContainer {  @NotNull  private final View containerView;  private HashMap _$_findViewCache;  @NotNull  public View getContainerView() {   return this.containerView;  }  public ViewHolder(@NotNull View itemView) {   Intrinsics.checkParameterIsNotNull(itemView, "itemView");   super(itemView);   this.containerView = itemView;  }  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.getContainerView();   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();   }  } }

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VeVb武林網的支持。


注:相關教程知識閱讀請移步到kotlin教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 98色视频 | 欧美精品色精品一区二区三区 | 国产一级毛片国语版 | 91精品国产91久久久久久不卞 | 欧美1区2区在线观看 | 久久网站热最新地址4 | 国产久草视频在线 | 全免费午夜一级毛片真人 | 双性精h调教灌尿打屁股的文案 | 天堂成人一区二区三区 | 91网址在线观看 | 在线播放免费人成毛片乱码 | 91,视频免费看 | 国产成人高清成人av片在线看 | 久草在线观看首页 | 日本特级a一片免费观看 | 精品国产一区二区三区在线 | 国产一级毛片av | 最新av网址在线观看 | 亚欧在线免费观看 | 黄片毛片一级 | 成人在线观看地址 | 黄色网址电影 | 草操视频 | 精品一区二区久久久久久久网精 | 国产91免费看 | 久久久久国产精品久久久久 | 欧美日韩在线视频一区 | 亚洲成人入口 | 日韩视频在线视频 | 亚洲午夜免费 | 中国黄色一级生活片 | 高颜值美女啪啪 | 国产亚洲欧美一区久久久在 | 狠狠操天天射 | 日本精品中文字幕 | 一区二区免费看 | 深夜视频在线 | 亚洲成人激情av | 999精品国产 | 久久综合狠狠综合久久 |