美文网首页Kotlin编程kotlin
Kotlin的Android扩展:对findViewById说再

Kotlin的Android扩展:对findViewById说再

作者: leilifengxingmw | 来源:发表于2020-03-09 21:56 被阅读0次

首先要在应用的build文件中引入kotlin扩展插件,现在Android Studio应该会为我们自动引入。

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

Activity中使用

布局文件

<?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=".findviewbyid.FindViewByIdActivity">

    <Button
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="button"
        android:textAllCaps="false"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

Activity代码

class FindViewByIdActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_find_view_by_id)

        btn.setOnClickListener {
            // do nothing
        }
    }
}

查看反编译Kotlin字节码生成的java类

public final class FindViewByIdActivity extends AppCompatActivity {

   private HashMap _$_findViewCache;

   protected void onCreate(@Nullable Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      this.setContentView(-1300032);
      ((Button)this._$_findCachedViewById(id.btn)).setOnClickListener((OnClickListener)null.INSTANCE);
   }

   //注释1处
   public View _$_findCachedViewById(int var1) {
      if (this._$_findViewCache == null) {
         this._$_findViewCache = new HashMap();
      }
        
      View var2 = (View)this._$_findViewCache.get(var1);
      if (var2 == null) {
         //调用findViewById
         var2 = this.findViewById(var1);
         this._$_findViewCache.put(var1, var2);
      }

      return var2;
   }

   public void _$_clearFindViewByIdCache() {
      if (this._$_findViewCache != null) {
         this._$_findViewCache.clear();
      }

   }
   
}

注释1处,还是调用了Activity的findViewById方法,并且当找到View以后帮我们缓存在了HashMap中了。

Fragment中使用

布局文件

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".findviewbyid.FindViewByIdFragment">

    <TextView
        android:id="@+id/tvInFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/hello_blank_fragment" />

</FrameLayout>

Fragment代码

class FindViewByIdFragment : Fragment() {


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        // Inflate the layout for this fragment

        //tvInFragment.text = "fragment中的字符串"
        return inflater.inflate(R.layout.fragment_find_view_by_id, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        //注释1处
        tvInFragment.text = "fragment中的字符串"
    }

    companion object {

        @JvmStatic
        fun newInstance() = FindViewByIdFragment()
    }
}


查看反编译的Kotlin字节码

public final class FindViewByIdFragment extends Fragment {
   public static final FindViewByIdFragment.Companion Companion = new FindViewByIdFragment.Companion((DefaultConstructorMarker)null);
   private HashMap _$_findViewCache;

   @Nullable
   public View onCreateView(@NotNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
      Intrinsics.checkParameterIsNotNull(inflater, "inflater");
      return inflater.inflate(-1300006, container, false);
   }

   public void onViewCreated(@NotNull View view, @Nullable Bundle savedInstanceState) {
      Intrinsics.checkParameterIsNotNull(view, "view");
      super.onViewCreated(view, savedInstanceState);
      //注释1处
      TextView var10000 = (TextView)this._$_findCachedViewById(id.tvInFragment);
      Intrinsics.checkExpressionValueIsNotNull(var10000, "tvInFragment");
      var10000.setText((CharSequence)"fragment中的字符串");
   }

   public View _$_findCachedViewById(int var1) {
      if (this._$_findViewCache == null) {
         this._$_findViewCache = new HashMap();
      }

      View var2 = (View)this._$_findViewCache.get(var1);
      if (var2 == null) {
         //注释2处 
         View var10000 = this.getView();
         if (var10000 == null) {
            return null;
         }
         //注释3处   
         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();
      //注释4处
      this._$_clearFindViewByIdCache();
   }
   
}

在fragment使用要注意一点,需要在onViewCreated获取控件。不能在onCreateView中获取控件。

我们可以看到注释2处,获取mViewmView就是onCreateView方法返回的View。

public View getView() {
    return mView;
}

注释3处,我们是使用mView来获取控件。在onCreateView方法没有返回的时候mView还是null。所以不能在onCreateView中获取控件。

注释4处,当onDestroyView的时候,清空了所有缓存的View。

在自定义View中使用

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tvInCustomLayout"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        tools:text="Hello world" />
</LinearLayout>

java代码

class MyLinearLayout @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {

    init {

        View.inflate(context, R.layout.custom_linear_layout, this)
        tvInCustomLayout.text = "Hello world"
    }
}

查看反编译的Kotlin字节码

public final class MyLinearLayout extends LinearLayout {
   //缓存
   private HashMap _$_findViewCache;

   @JvmOverloads
   public MyLinearLayout(@NotNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
      Intrinsics.checkParameterIsNotNull(context, "context");
      super(context, attrs, defStyleAttr);
      View.inflate(context, -1300036, (ViewGroup)this);
      TextView var10000 = (TextView)this._$_findCachedViewById(id.tvInCustomLayout);
      Intrinsics.checkExpressionValueIsNotNull(var10000, "tvInCustomLayout");
      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();
      }
   }
}

内部也是和Activity类似的。

实验功能

开启实验功能,在应用的build.gradle

androidExtensions {
    experimental = true
}

布局容器支持(LayoutContainer support)

Kotlin的Android扩展插件支持不同类型的容器,基本的容器像Activity、Fragment、View。但是实际上你可以通过实现LayoutContainer接口,将任何一个转化成
Android扩展容器。

以RecyclerView的ViewHolder为例

class ViewHolder(view: View) : RecyclerView.ViewHolder(view), LayoutContainer {
    //给containerView赋值
    override val containerView: View = itemView
}

LayoutContainer接口

public interface LayoutContainer {
    /** Returns the root holder view. */
    public val containerView: View?
}

在RecyclerView.Adapter中使用

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    //原来的使用方式
    //holder.itemView.tvInRv.text = data[position]
    //启用LayoutContainer扩展功能后的使用方式
    holder.tvInRv.text = data[position]
    holder.itemView.setOnClickListener {
        Toast.makeText(context, "点击了第$position 项", Toast.LENGTH_SHORT).show()
    }
}

查看以一下反编译的Kotlin字节码

public void onBindViewHolder(@NotNull MyAdapter.ViewHolder holder, final int position) {
   Intrinsics.checkParameterIsNotNull(holder, "holder");
   //注释1处
   TextView var10000 = (TextView)holder._$_findCachedViewById(id.tvInRv);
   Intrinsics.checkExpressionValueIsNotNull(var10000, "holder.tvInRv");
   var10000.setText((CharSequence)this.data.get(position));
   holder.itemView.setOnClickListener((OnClickListener)(new OnClickListener() {
      public final void onClick(View it) {
         Toast.makeText(MyAdapter.this.getContext(), (CharSequence)("点击了第" + position + " 项"), 0).show();
      }
   }));
}

注释1处,调用holder的_$_findCachedViewById方法

public static final class ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder implements LayoutContainer {
   
    @NotNull
     private final View containerView;
    //缓存
     private HashMap _$_findViewCache;

     //获取containerView
     @NotNull
     public View getContainerView() { return this.containerView;
     }

     public ViewHolder(@NotNull View view) {
         Intrinsics.checkParameterIsNotNull(view, "view");
         super(view);
         View var10001 = this.itemView;
         Intrinsics.checkExpressionValueIsNotNull(var10001, "itemView");
         //将itemView赋值给containerView
         this.containerView = var10001;
     }

     public View _$_findCachedViewById(int var1) {
         if (this._$_findViewCache == null) {
            this._$_findViewCache = new HashMap();
         }

         View var2 = (View)this._$_findViewCache.get(var1);
         if (var2 == null) {
            //获取containerView即itemView
            View var10000 = this.getContainerView();
            if (var10000 == null) {
               return null;
            }
            //使用itemView获取控件
            var2 = var10000.findViewById(var1);
            this._$_findViewCache.put(var1, var2);
         }

         return var2;
     }

     public void _$_clearFindViewByIdCache() {
         if (this._$_findViewCache != null) {
            this._$_findViewCache.clear();
         }

     }
}

参考链接:

相关文章

网友评论

    本文标题:Kotlin的Android扩展:对findViewById说再

    本文链接:https://www.haomeiwen.com/subject/zmwfqhtx.html