使用Anko創建快400%的布局
我用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