KTX: Say goodbye to findViewById

android开发中,布局文件一般写在xml文件中。

在java代码中想要获取渲染出来的view对象,一般是在xml中给view设置一个id,然后在java代码中通过findViewById进行获取。

因此,想要获取view的实例需要分两步:1.xml设置id。2.java中findViewById获取。

这无疑是一项重复性且繁琐的工作,而且代码会变得非常臃肿。

不少码农都尝试解决这样的问题。

方案一:
使用butterKnife。
虽然解决了部分臃肿问题,但是依然需要使用@BindView注解。并没有实质性的简化流程。

方案二:
通过编写android studio(IDEA)插件,解析xml文件在java代码中自动生成findViewById的相关代码。理论上是可行的,但是非常缺乏动态性。

方案三:
使用kotlin语言开发,利用KTX(kotlin android extentions)。
该方案简化了java中使用findViewById这一步,直接通过xml中定义的id来引用view实例。

下面我们分析一下方案三是如何实现的:

源代码:

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 = "小明"
    }
}

activity_main.xml




    


反编译后的java代码:

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)"小明");
   }

   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();
      }

   }
}

可以看到关键方法:_$_findCachedViewById。
所以性能上是不会有影响的。

扩展方法:

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 = "小明"
    }
    fun Activity.b(){
        textView.text = "Activity.b"
    }
    fun MainActivity.a() {
        textView.text = "MainActivity.a"
    }
}

反编译后的代码:

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)"小明");
   }

   public final void b(@NotNull Activity $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      TextView var10000 = (TextView)$receiver.findViewById(id.textView);
      Intrinsics.checkExpressionValueIsNotNull(var10000, "textView");
      var10000.setText((CharSequence)"Activity.b");
   }

   public final void a(@NotNull MainActivity $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      TextView var10000 = (TextView)$receiver._$_findCachedViewById(id.textView);
      Intrinsics.checkExpressionValueIsNotNull(var10000, "textView");
      var10000.setText((CharSequence)"MainActivity.a");
   }

   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的扩展并没有使用缓存功能。

kotlin使用了HashMap来缓存view实例,我们还可以自定义缓存实现。

androidExtensions {
    experimental = true
    defaultCacheImplementation = "HASH_MAP" // also SPARSE_ARRAY, NONE
}

在activity、fragment、view对象中可以方便的使用ktx代替findViewById。

如果我们想在其他类中也享受到这项便利功能,可以借助LayoutContainer来实现。

class Person(var name: String) : LayoutContainer {
    override val containerView: View?
        get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.

    fun aa() {
        textView.text = ""
    }
}

注意:需要在build.gradle中声明

    androidExtensions {
        experimental = true
    }
最后:不要使用viewGroup.id的形式来获取view实例对象。

比如说:

var container:ViewGroup = .......
container.textview

这样是没有利用view的缓存的,每次都会调用container.findViewById(R.id.textview)

你可能感兴趣的:(KTX: Say goodbye to findViewById)