使用Anko創建快400%的布局

pwul2413 8年前發布 | 12K 次閱讀 XML 安卓開發 Android開發 移動開發

我用Anko已經有了一段時間了,很好奇Anko提供了哪些優勢。所以做了一些性能測試。

我打算把一個比較高級的布局遷移到Anko。這個布局包含了一個RelativeLayout,里面有17個ImageView(全是用的.9圖片),一個SurfaceView作為取景器,兩個普通的TextView。仍然是一個比較干凈的布局,因為沒有嵌套。

為什么Anko性能更優?

XML布局是在運行時解析的。也就是說XML需要從資源文件中獲取,然后XmlPullParser需要解析所有的元素并一個一個的創建它們。還要解析元素的屬性,然后設置。這個過程非常繁重,那么到底浪費了多長時間在上面呢?

我在4個老舊的設備上運行了測試,雖然老但又是每個安卓開發者都需要處理的設備。我們在所有的設備上運行了大約4次 DevMetrics 。結果發現性能差距居然達到了350%-600%的程度。

隨著對設計/動畫以及性能的需求日益增加,我認為大家都對應用的速度非常關心,所以為什么要使用Anko就不用多說了吧。

除了布局變快了之外,我們現在構建布局是在運行時,所以可以加上一些邏輯判斷。讓我們用Anko創建一個master-detail的示例:

class MainActivity : AppCompatActivity() {
  private var toolBar: Toolbar? = null
  private var container: ViewGroup? = null

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    coordinatorLayout {
      fitsSystemWindows = true

      appBarLayout {
        toolBar = toolbar {
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) elevation = 4f
        }.lparams(width = matchParent, height = actionBarSize())

      }.lparams(width = matchParent)

      container = frameLayout()
        .lparams(width = matchParent, height = matchParent) {
          behavior = AppBarLayout.ScrollingViewBehavior()
        }
    }
  }
}

就如你看到的那樣,用Anko寫布局跟xml沒有什么兩樣。除了布局構建上的優勢之外,我們可以做兼容性檢查,根據OS的版本設置elevation,而不是在布局目錄中寫兩個xml。

對于提取MainActivity中的的元素,Anko提供了AnkoComponent來解決這個問題,但是你還是需要使用findViewById和類型轉換。不過這也是可以輕松解決的。

我們創建一個提供了一個bind 和一個unbind方法的接口。類似于使用Butter Knife來綁定與解綁。

interface ViewBinder<in T> {
    fun bind(t: T) : View
    fun unbind(t: T)
}

現在我們可以輕松的從前面的布局中提取出元素到MainLayout.kt class。

class MainLayout : ViewBinder<MainActivity> {

  override fun bind(mainActivity: MainActivity): View =
    mainActivity.UI {
      coordinatorLayout {
        fitsSystemWindows = true

        appBarLayout {
          mainActivity.toolBar = toolbar {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) elevation = 4f
          }.lparams(width = matchParent, height = actionBarSize())

        }.lparams(width = matchParent)

        mainActivity.container = frameLayout()
          .lparams(width = matchParent, height = matchParent) {
            behavior = AppBarLayout.ScrollingViewBehavior()
          }
      }
    }.view

  override fun unbind(mainActivity: MainActivity) {
    mainActivity.container = null
    mainActivity.recycView = null
  }
}

 

public class MainActivity extends AppCompatActivity {

    LinearLayout container;
    RecyclerView recycView;
    FrameLayout detailContainer;

    private MainLayout mainLayout = new MainLayout();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(mainLayout.bind(this));
        ...
    }
}

現在我們的activity看起來是不是干凈多了呢?除了調用了setContentView(mainLayout.bind(this))之外沒有什么特別之處,它將設置content view并把view和變量綁定。就如你看到的那樣,無需findViewById和類型轉換。

Runtime layouts

如果你想在構建布局的時候加入邏輯,你肯定會喜歡這個東西。

configuration(orientation = Orientation.LANDSCAPE, smallestWidth = 700) {
  recyclerView {
    init()
  }.lparams(width = widthProcent(50), height = matchParent)

  frameLayout().lparams(width = matchParent, height = matchParent)
}

fun <T : View> T.widthProcent(procent: Int): Int =
  getAppUseableScreenSize().x.toFloat().times(procent.toFloat() / 100).toInt()

讓我們分析一下上面的代碼,anko提供了一個語法友好的configuration用于在運行時檢查配置。可以檢查screenSize, density, language, orientation, fromSdk, sdk, uiMode, nightMode, rightToLeft 以及 smallestWidth。因此這里的layout DSL只有在設備為橫向、橫向寬度是700的時候才會運行。

我們還可以輕松計算出大小,這里將在運行時計算出屏幕寬度并把內容寬度設置為屏幕寬度的50% 。

總結

Anko提供了幾種解決傳統xml布局構建方式的辦法。它繞開了xml布局方式的所有開銷。你無需處理findViewById或者類型轉換,而且在運行時構建布局可以讓你添加想要的邏輯,讓布局更動態。所有這些只需要花很小的代價

 

 

來自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/1123/6795.html

 

 本文由用戶 pwul2413 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!