1. 程式人生 > >Android Kotlin 學習總結(一) 《KAE 優缺點並且深入位元組碼分析工作原理》

Android Kotlin 學習總結(一) 《KAE 優缺點並且深入位元組碼分析工作原理》

本章會分為以下內容:

1.Kotlin KAE介紹,使用和原始Android findViewById對比優缺點

2.Kotlin KAE所存在的問題

3.通過位元組碼分析他的實現原理

閱讀本章內容大概需要您5分鐘的時間

一、Kotlin KAE介紹,使用和原始Android findViewById對比優缺點

說起Koltin大家可能不陌生,Android的小夥伴,谷歌Android的一級語言,國內雖然還不算太流行,不過也慢慢火了起來,今天就來說一下Kotlin的一個擴充套件外掛 kotlin-android-extensions , 簡稱KAE ,

1.1 KAE的使用

如果你的AndroidStudio版本比較低,那麼你需要去在AndroidStudio裡面下載Kotlin的支援,這裡不講述了(Google一下~)

我們就說一下版本比較高的AndroidStudio怎麼使用KAE , 我們建立一個專案之後,我們需要在Project的Gradle裡面新增上我們的 buildscript裡新增上support_version欄位 然後再我們的模組Gradle中plugin我們的AKE 具體見下圖

這時候我們的KAE就算安裝完畢了

關於使用:

在我們原來View繫結XML控制元件的時候,我們通常會做findViewById(R.id.xx)的工作,這是很頭疼的事情,介面簡單還好說,如果介面複雜,你會遇到下面這種事情

一大串的findViewById, 用外掛生成還好說,手動寫就很頭疼,第一它樣板程式碼,第二他太多了太多了太多了!,如果要寫成全域性的控制元件,上面還要寫一份,就是雙倍了有木有,但是我們使用KAE的話 就是如下的樣子

有的小夥伴可能就會問了,findViewById呢,去哪了? 其實KAE幫我們做了這個事情,下面在位元組碼分析會講到他是怎麼做的,這裡我們想使用控制元件,直接引入一個包就可以了,這個包並不是實際存在的,

這個包會直接繫結上我們的試圖中所有的控制元件,怎麼樣,程式碼是不是簡潔了很多。我們就可以節省更多的時間不去寫findViewById了,把更多的時間用在控制元件的邏輯互動上,節省了開發時間。

二.Kotlin KAE所存在的問題

當我們的介面比較複雜,比如說我們想給ListView加一個Header的時候,我們可能要引入另一個View,當兩個View控制元件id一樣的時候,我們就會出現一個問題,如下圖

也就是說,不同xml佈局檔案id相同的控制元件用在一個Acitivity中 會引起歧義,這時候我們可以通過別名(外號)的方式解決衝突在我們引包的地方加上個別名即可

但是解決問題的根源就是預防問題,所以當我們寫id的時候還需要嚴謹一些!

三、通過位元組碼分析他的實現原理

我們就還是繼續上面的程式碼來進行檢視一下生成的位元組碼,生成的位元組碼我放在下面供大家參考

package github.nixo.com.github.Common.View;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import github.nixo.com.github.Common.Present.LoginPersenter;
import github.nixo.com.github.R.id;
import github.nixo.com.github.mvp.Impl.BaseActivity;
import java.util.HashMap;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@Metadata(
   mv = {1, 1, 11},
   bv = {1, 0, 2},
   k = 1,
   d1 = {"\u0000&\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0003\n\u0002\u0010\u0003\n\u0002\b\u0005\u0018\u00002\b\u0012\u0004\u0012\u00020\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0003J\u0012\u0010\u0004\u001a\u00020\u00052\b\u0010\u0006\u001a\u0004\u0018\u00010\u0007H\u0016J\b\u0010\b\u001a\u00020\u0005H\u0016J\u000e\u0010\t\u001a\u00020\u00052\u0006\u0010\n\u001a\u00020\u000bJ\u0006\u0010\f\u001a\u00020\u0005J\u0006\u0010\r\u001a\u00020\u0005J\u0012\u0010\u000e\u001a\u00020\u00052\b\u0010\u000f\u001a\u0004\u0018\u00010\u0007H\u0016¨\u0006\u0010"},
   d2 = {"Lgithub/nixo/com/github/Common/View/LoginActivity;", "Lgithub/nixo/com/github/mvp/Impl/BaseActivity;", "Lgithub/nixo/com/github/Common/Present/LoginPersenter;", "()V", "onCreate", "", "savedInstanceState", "Landroid/os/Bundle;", "onDestory", "onLoginError", "e", "", "onLoginStart", "onLoginSuccess", "onViewStateResotre", "saveInstanceState", "production sources for module app"}
)
public final class LoginActivity extends BaseActivity {
   private HashMap _$_findViewCache;

   public void onCreate(@Nullable Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      this.setContentView(2131361819);
      ((Button)this._$_findCachedViewById(id.login_login)).setOnClickListener((OnClickListener)(new OnClickListener() {
         public final void onClick(View it) {
            LoginPersenter var10000 = (LoginPersenter)LoginActivity.this.getPresenter();
            EditText var10001 = (EditText)LoginActivity.this._$_findCachedViewById(id.login_account);
            Intrinsics.checkExpressionValueIsNotNull(var10001, "login_account");
            String var2 = var10001.getText().toString();
            EditText var10002 = (EditText)LoginActivity.this._$_findCachedViewById(id.login_password);
            Intrinsics.checkExpressionValueIsNotNull(var10002, "login_password");
            var10000.doLogin(var2, var10002.getText().toString());
         }
      }));
   }

   public final void onLoginSuccess() {
      CharSequence message$iv = (CharSequence)"登陸成功";
      Toast var3 = Toast.makeText(this, message$iv, 0);
      var3.show();
      Intrinsics.checkExpressionValueIsNotNull(var3, "Toast\n        .makeText(…         show()\n        }");
   }

   public final void onLoginError(@NotNull Throwable e) {
      Intrinsics.checkParameterIsNotNull(e, "e");
      CharSequence message$iv = (CharSequence)"登陸失敗";
      Toast var4 = Toast.makeText(this, message$iv, 0);
      var4.show();
      Intrinsics.checkExpressionValueIsNotNull(var4, "Toast\n        .makeText(…         show()\n        }");
   }

   public final void onLoginStart() {
   }

   public void onViewStateResotre(@Nullable Bundle saveInstanceState) {
   }

   public void onDestory() {
   }

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

   }
}

我們首先找到我們的login_login控制元件,我們可以發現他也執行了findViewById,只不過是findCacheViewById,其實這裡使用了HashMap作為控制元件快取,我們看一下這兩個方法,就是判斷是否有這個快取,如果用直接用,沒有在呼叫findViewById,所以Kotlin的KAE 其實就是在編譯時期將我們的控制元件執行了findViewById的操作,它只不過幫我們做了這件事,並且是編譯時期呼叫,變為相同程式碼,原理跟ButterKinfe差不多,但是比ButterKinfe更簡潔,而且使用KAE有一個好處,我們保證了型別的安全性,不會因為寫錯控制元件型別而導致強轉錯誤~

以上就是本章的全部內容了,今天中秋節,祝大家中秋節快樂!