Databinding 使用以及相關問題

DataBinding
官方文檔的解釋:數據綁定庫是一個支持庫,允許您使用聲明性格式而不是以編程方式將佈局中的UI組件綁定到應用程序中的數據源。其實已經出來很久了,但是身邊朋友使用的人不是特別多,今天出一個使用教程:

優點:DataBinding的優點比普通的findViewById之後再設置數據簡單了很多,並且數據更新也很簡單隻要更新綁定的binding,數據更新會自動生效

官方文檔
下面介紹如何使用它:

使用前的配置

1:在module級別的build.gradle上添加對DataBinding的支持:

android {
    ....
    dataBinding {
        enabled = true
    }
}

使用的時候需要在你要綁定的視圖的更目錄添加data支持,具體如下

​
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
    <data>
        <variable
            name="user"
            type="com.kirk.model.User" />

        <variable
            name="isLogin"
            type="boolean" />

        <import type="android.view.View" />
    </data>

    <LinearLayout 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/app_background"
        android:orientation="vertical">


    </LinearLayout>
</layout>

​

代碼中的 <layout><data> 是必須要的,添加在佈局文件的根節點上  variable 是你在視圖綁定中需要用到的類,比如我在這個視圖中需要根據數據不同來設置隱藏顯示那麼就需要添加<import type="android.view.View" />因爲View.GONE是android.view.View下面的屬性,所以需要引入它,跟在class中的導包(import  android.view.View)是一樣,除了可以引入普通的數據類型之外,還可以引入系統的類以及使用中自定義的類。

那麼如何你的某個控件上設置值呢,彆着急下面重頭戲來了,如果你要在TextView上設置動態text值,在未使用Databinding之前的做法都是findViewById或者通過註解拿到這個控件,然後給他setText("屬性值"),但是在使用了Databinding之後就不用這麼麻煩了,你連控件Id都不用添加,代碼如下:

​
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
    <data>
        <variable
            name="user"
            type="com.kirk.model.User" />

        <variable
            name="isLogin"
            type="boolean" />

        <import type="android.view.View" />
    </data>

    <LinearLayout 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/app_background"
        android:orientation="vertical">


                <TextView
                    android:id="@+id/tv_user_name"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="10dp"
                    android:text="@{user.name}"
                    android:textColor="?attr/colorPrimary"
                    android:textSize="@dimen/txt_size_Primary" />

    </LinearLayout>
</layout>

​

就是這麼簡單,你不信?我們稍後再看,其實到這裏,已經完成了一大半了,當你在根節點添加
<layout>
<data></data>
<原始佈局/>
<layout>後,編譯器會爲你自動創建一個ViewDataBinding的類,他繼承了android.databinding.ViewDataBinding,下面我們來看一下這個類

package com.jisu.sports.databinding;
import com.jisu.sports.R;
import com.jisu.sports.BR;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
@SuppressWarnings("unchecked")
public class FragmentMineBinding extends android.databinding.ViewDataBinding  {

    @Nullable
    private static final android.databinding.ViewDataBinding.IncludedLayouts sIncludes;
    @Nullable
    private static final android.util.SparseIntArray sViewsWithIds;
    static {
        sIncludes = null;
        sViewsWithIds = new android.util.SparseIntArray();
        sViewsWithIds.put(R.id.tv_user_name, 7);

    }
    // views

    @NonNull
    public final android.widget.TextView tvUserName;
    // variables
    @Nullable
    private boolean mIsLogin;
    @Nullable
    private com.kirk.model.User mUser;
    // values
    // listeners
    // Inverse Binding Event Handlers

    public FragmentMineBinding(@NonNull android.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
        super(bindingComponent, root, 0);
        final Object[] bindings = mapBindings(bindingComponent, root, 14, sIncludes, sViewsWithIds);
        ensureBindingComponentIsNotNull(com.jisu.sports.common.AppBindingAdapter.class);
        this.tvUserName = (android.widget.TextView) bindings[4];
        this.tvUserName.setTag(null);
        setRootTag(root);
        // listeners
        invalidateAll();
    }

    @Override
    public void invalidateAll() {
        synchronized(this) {
                mDirtyFlags = 0x4L;
        }
        requestRebind();
    }

    @Override
    public boolean hasPendingBindings() {
        synchronized(this) {
            if (mDirtyFlags != 0) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean setVariable(int variableId, @Nullable Object variable)  {
        boolean variableSet = true;
        if (BR.isLogin == variableId) {
            setIsLogin((boolean) variable);
        }
        else if (BR.user == variableId) {
            setUser((com.kirk.model.User) variable);
        }
        else {
            variableSet = false;
        }
            return variableSet;
    }

    public void setIsLogin(boolean IsLogin) {
        this.mIsLogin = IsLogin;
        synchronized(this) {
            mDirtyFlags |= 0x1L;
        }
        notifyPropertyChanged(BR.isLogin);
        super.requestRebind();
    }
    public boolean getIsLogin() {
        return mIsLogin;
    }
    public void setUser(@Nullable com.kirk.model.User User) {
        this.mUser = User;
        synchronized(this) {
            mDirtyFlags |= 0x2L;
        }
        notifyPropertyChanged(BR.user);
        super.requestRebind();
    }
    @Nullable
    public com.kirk.model.User getUser() {
        return mUser;
    }

    @Override
    protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
        switch (localFieldId) {
        }
        return false;
    }

    @Override
    protected void executeBindings() {
        long dirtyFlags = 0;
        synchronized(this) {
            dirtyFlags = mDirtyFlags;
            mDirtyFlags = 0;
        }
        int userBalance = 0;
        boolean isLogin = mIsLogin;
        java.lang.String userName = null;
        java.lang.String javaLangStringUserBalance = null;
        int isLoginViewVISIBLEViewGONE = 0;
        int isLoginViewGONEViewVISIBLE = 0;
        java.lang.String javaLangStringLvUserLevel = null;
        com.jisu.sports.ui.mine.model.User user = mUser;
        java.lang.String userAvatar = null;
        int userLevel = 0;

        if ((dirtyFlags & 0x5L) != 0) {

            if((dirtyFlags & 0x5L) != 0) {
                if(isLogin) {
                        dirtyFlags |= 0x10L;
                        dirtyFlags |= 0x40L;
                }
                else {
                        dirtyFlags |= 0x8L;
                        dirtyFlags |= 0x20L;
                }
            }


                // read isLogin ? View.VISIBLE : View.GONE
                isLoginViewVISIBLEViewGONE = ((isLogin) ? (android.view.View.VISIBLE) : (android.view.View.GONE));
                // read isLogin ? View.GONE : View.VISIBLE
                isLoginViewGONEViewVISIBLE = ((isLogin) ? (android.view.View.GONE) : (android.view.View.VISIBLE));
        }
        if ((dirtyFlags & 0x6L) != 0) {



                if (user != null) {
                    // read user.name
                    userName = user.getName();
                }

        }
        // batch finished
        if ((dirtyFlags & 0x6L) != 0) {
            // api target 1

            this.mBindingComponent.getAppBindingAdapter().image_src(this.ivUserIcon, userAvatar, getDrawableFromResource(ivUserIcon, R.drawable.ico_comment_avatar), (android.graphics.drawable.Drawable)null);
            android.databinding.adapters.TextViewBindingAdapter.setText(this.tvLabelLevel, javaLangStringLvUserLevel);
            android.databinding.adapters.TextViewBindingAdapter.setText(this.tvLabelMoney, javaLangStringUserBalance);
            android.databinding.adapters.TextViewBindingAdapter.setText(this.tvUserName, userName);
        }
        if ((dirtyFlags & 0x5L) != 0) {
            // api target 1

            this.rlHasLogged.setVisibility(isLoginViewVISIBLEViewGONE);
            this.rlNotLogin.setVisibility(isLoginViewGONEViewVISIBLE);
        }
    }
    // Listener Stub Implementations
    // callback impls
    // dirty flag
    private  long mDirtyFlags = 0xffffffffffffffffL;

    @NonNull
    public static FragmentMineBinding inflate(@NonNull android.view.LayoutInflater inflater, @Nullable android.view.ViewGroup root, boolean attachToRoot) {
        return inflate(inflater, root, attachToRoot, android.databinding.DataBindingUtil.getDefaultComponent());
    }
    @NonNull
    public static FragmentMineBinding inflate(@NonNull android.view.LayoutInflater inflater, @Nullable android.view.ViewGroup root, boolean attachToRoot, @Nullable android.databinding.DataBindingComponent bindingComponent) {
        return android.databinding.DataBindingUtil.<FragmentMineBinding>inflate(inflater, com.jisu.sports.R.layout.fragment_mine, root, attachToRoot, bindingComponent);
    }
    @NonNull
    public static FragmentMineBinding inflate(@NonNull android.view.LayoutInflater inflater) {
        return inflate(inflater, android.databinding.DataBindingUtil.getDefaultComponent());
    }
    @NonNull
    public static FragmentMineBinding inflate(@NonNull android.view.LayoutInflater inflater, @Nullable android.databinding.DataBindingComponent bindingComponent) {
        return bind(inflater.inflate(com.jisu.sports.R.layout.fragment_mine, null, false), bindingComponent);
    }
    @NonNull
    public static FragmentMineBinding bind(@NonNull android.view.View view) {
        return bind(view, android.databinding.DataBindingUtil.getDefaultComponent());
    }
    @NonNull
    public static FragmentMineBinding bind(@NonNull android.view.View view, @Nullable android.databinding.DataBindingComponent bindingComponent) {
        if (!"layout/fragment_mine_0".equals(view.getTag())) {
            throw new RuntimeException("view tag isn't correct on view:" + view.getTag());
        }
        return new FragmentMineBinding(bindingComponent, view);
    }
    /* flag mapping
        flag 0 (0x1L): isLogin
        flag 1 (0x2L): user
        flag 2 (0x3L): null
        flag 3 (0x4L): isLogin ? View.VISIBLE : View.GONE
        flag 4 (0x5L): isLogin ? View.VISIBLE : View.GONE
        flag 5 (0x6L): isLogin ? View.GONE : View.VISIBLE
        flag 6 (0x7L): isLogin ? View.GONE : View.VISIBLE
    flag mapping end*/
    //end
}

代碼中我們可以看到, 這個自動生成的類已經把我們要設置的值,和控件全部準備好了,幫擴賦值一系列工作也做好了,萬事俱備,只欠東風,come baby
此時只要把數據設置給dinding就大功告成了

MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity); User user = new User("張三", "18");
 binding.setUser(user);

沒錯,生成的DataBinding類是根據你的佈局文件的命名來的,後面追加了Binding,如果你打出了佈局文件的名字但是沒有提示出來MainActivityBinding,這時候你需要build一下工程。完成以上步驟就算是完整的databinding使用了。

對,我引入的View,你是不是想問難道只能設置text的時候才能用databinding嗎,那也太單一了,NONONO,控件的隱藏顯示,圖片,都可以使用,比如:

android:visibility="@{isLogin?View.VISIBLE:View.GONE,default=visible}"

再比如背景色:

            android:background="@{user.age>18@color/red_deepen:@color/reds,default=@color/reds}"

它還可以進行一些普通的邏輯運算

要注意的坑:&&  和 <
有些情況下我們需要雙重判斷也就是&&正常情況下我們這樣寫覺得沒有問題,但是&&始終會報錯,強制編譯運行就出問題像下面這種錯誤

那是因爲&&,在databinding中做邏輯判斷使用時  &&需要轉譯爲:&amp;&amp;    需要轉譯爲:&lt;  修改後:

                    android:text="@{coin>=30&amp;&amp;coin &lt; 60?`未完成`:``}"

databinding還有很多強大的用處,後面學習了再貼出,先到這裏。有什麼意見或者建議歡迎在留言區討論

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章