Android 官方數據綁定框架:DataBinding(AndroidX學習)

Android 官方數據綁定框架:DataBinding,AndroidX學習

不是每一個人都能成爲,本身想要的樣子,但每一個人,均可以努力,成爲本身想要的樣子。相信本身,你能做繭自縛,就能破繭成蝶。java

什麼是DataBinding,爲了解決什麼問題?

DataBinding是Android推出的一款數據綁定框架,爲了解決 Activity / Fragment 之間獲取控件 findViewById() 的操做,下降數據之間的耦合性android


viewBinding和dataBinding的區別

  • DataBinding僅處理使用 代碼建立的數據綁定佈局
  • ViewBinding不支持佈局變量或佈局表達式,所以它不能用於在 XML 中將佈局與數據綁定,ViewBinding僅是節省了findview的步驟

導入

導入圖(1.1):git

android {
  dataBinding {
        enabled = true
    }
}
複製代碼

基本使用:引用數據類型

alt + enter(回車)選中Convert to data … layout,將佈局改成DataBinding佈局
在這裏插入圖片描述github

改完以後簡單使用:數組

activity_bin.xml佈局:markdown

<?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">
	<!--        DataBinding自動生成別名   -->
    <data class="DataBinding">
        <import type="demo.ht.com.basequickadpater.beans.UserBean" />
        
		 <!--        變量:UserBean     -->
        <variable
            name="user"
            type="UserBean" />
    </data>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="2000dp"
            android:gravity="center"
            android:orientation="vertical"
            tools:context=".activitys.BinActivity">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{user.name}" />
        </LinearLayout>
</layout>
複製代碼

分析:app

  • <data></data > 標籤是用來定義變量的,下邊代碼就是正常的佈局
  • <data class=「DataBinding」></data > 自動生成別名(這個不懂不急,下面會詳細解釋)
  • <import type = 「包名」> 引入包名
  • <variable name = 「別名」 type=「包名」> 用來定義變量,提供下面佈局使用

引用流程:框架

\ide

UserBean類:oop

public class UserBean extends BaseObservable {
    public String name;//共有變量
    private int age;//私有變量
   
	get.. set..
    有參 .. 無參構造 ..
    
    @Bindable  //private 設置數據調用
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
        //private 請求設置數據
        notifyPropertyChanged(BR.age);
    }
}
複製代碼

分析:

  • 共有變量:不須要加任何的註釋,由於外部直接可以調用,也可以使用到

  • 私有變量:

    • 須要extends 自 BaseObservable
    • 給自身的getter()方法加@Bindable註釋,爲了DataBinding可以直接調用到
    • 給自身的setter()方法刷新方法 notifyPropertyChanged(id);爲了使DataBinding可以設置值

notifyPropertyChanged參數介紹:

DataBinding會自動生成本身的BR控件類,須要獲取BR中的對應方法.

\

BinActivity類:

public class BinActivity extends AppCompatActivity {

    private DataBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = DataBindingUtil.setContentView(this, R.layout.activity_bin);
		
		 //設置對象
         binding.setUser(new UserBean("szj", 1));
      }
}
複製代碼

分析:

  • 取消掉了最初的 setContentView(id); 加載佈局的方法;
  • 使用 DataBindingUtil.setContentView(Activity,加載佈局id) 加載佈局
  • 這裏的返回值須要手動改爲對應的值

這裏返回的就是剛剛定義的別名
在這裏插入圖片描述
若是不寫別名會怎麼樣?
在這裏插入圖片描述
自動生成的Binding 就是以 當前佈局取消掉下劃線首字母大寫+BinDing 來命名的

效果圖(2.1):

\

其餘類型使用

<?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">
<!--        DataBinding自動生成別名 -->
    <data>
    
        <import type="demo.ht.com.basequickadpater.beans.UserBean" />

        <import type="java.util.ArrayList" />

        <import type="java.util.HashMap" />

        <import type="demo.ht.com.basequickadpater.activitys.BinActivity" />


        <!--        Map 目前只支持基本引用類型     -->
        <variable
            name="hashMap"
            type="HashMap&lt;String, String>" />

        <!--        int     -->
        <variable
            name="listi"
            type="int" />

        <!--        數組 目前只支持基本引用類型     -->
        <variable
            name="users"
            type="String[]" />

        <!--        ArrayList     -->
        <variable
            name="userList"
            type="ArrayList&lt;UserBean>" />

        <!--        UserBean     -->
        <variable
            name="user"
            type="UserBean" />

        <!--        boolean     -->
        <variable
            name="isCheck"
            type="boolean" />

        <!--        點擊事件     -->
        <variable
            name="OnClickListener"
            type="BinActivity" />
    </data>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="2000dp"
            android:gravity="center"
            android:orientation="vertical"
            tools:context=".activitys.BinActivity">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{user.name}" />


            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{String.valueOf(user.age)}" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{userList[listi].name}" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{hashMap[`name`]}" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{users[0]}" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{users[0]}" />

            <TextView
                android:id="@+id/tv1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:onClick="@{OnClickListener.onClick}"
                android:text='@{isCheck ? "error" : "ok"}' />

            <TextView
                android:id="@+id/tv2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:onClick="@{OnClickListener.onClick}"
                android:text="點擊事件" />

        </LinearLayout>

</layout>
複製代碼

分析:

  • &lt; :是 < 號,在代碼中不能出現<>,由於和佈局標籤重複了,因此必須使用 &lt;
  • 在調用int類型的時候,不能直接調用,必須使用String.valueOf(int)來包裹,由於文字不支持int類型的.
  • 使用List 和 數組直接 list[int] 便可
  • 使用map集合hashMap[` key ` ] , 切記不是單引號( ’ )
  • 使用 boolean時,可使用三目運算符,默認爲false

BinActivity類:

binding = DataBindingUtil.setContentView(
                this,
                R.layout.activity_bin
        );
        
		//ArrayList集合
        ArrayList<UserBean> userList = new ArrayList<UserBean>() {
            {
                add(new UserBean("張三", 23));
                add(new UserBean("王五", 23));
                add(new UserBean("趙六", 23));
                add(new UserBean("武大", 23));
            }
        };
        
		//hashMap
        HashMap<String, String> hashMap = new HashMap<String, String>() {
            {
                put("name", "HashMap");
            }
        };

        String[] s = new String[1];
        s[0] = new String("User數組");
        //設置數組
        binding.setUsers(s);

        //設置int
        binding.setListi(1);


        //設置對象
        binding.setUser(new UserBean("szj", 1));

        //設置List
        binding.setUserList(userList);

        //設置Map
        binding.setHashMap(hashMap);
複製代碼

這裏的setXXX就是對應的佈局中的

\

效果圖(2.3):

點擊事件

activity_bin.xml

<?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">
<!--        DataBinding自動生成別名 -->
    <data>

        <import type="demo.ht.com.basequickadpater.activitys.BinActivity" />

        <!--        點擊事件     -->
        <variable
            name="OnClickListener"
            type="BinActivity" />

    </data>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="2000dp"
            android:gravity="center"
            android:orientation="vertical"
            tools:context=".activitys.BinActivity">

            <TextView
                android:id="@+id/tv1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:onClick="@{OnClickListener.onClick}"
                android:text='@{isCheck ? "error" : "ok"}' />

            <TextView
                android:id="@+id/tv2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:onClick="@{OnClickListener.onClick}"
                android:text="點擊事件" />
        </LinearLayout>
</layout>
複製代碼

BinActivity類:

//設置Text監聽
binding.setOnClickListener(this);

 public void onClick(View view){
        if (view.getId() ==R.id.tv1) {
            Toast.makeText(this, "點擊了tv1", Toast.LENGTH_SHORT).show();

        }else{
            Toast.makeText(this, "點擊了tv2", Toast.LENGTH_SHORT).show();
        }
    }
複製代碼

效果圖(2.4):

Fragment綁定數據

fragment_binding.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <import type="demo.ht.com.basequickadpater.beans.UserBean"/>

        <variable
            name="userBean"
            type="UserBean" />

        <variable
            name="click"
            type="demo.ht.com.basequickadpater.fragments.BindingFragment" />
    </data>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/teal_200"
        tools:context=".fragments.BindingFragment">

        <TextView
            android:onClick="@{click.onTextClick}"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:textAllCaps="false"
            android:textSize="30dp"
            android:gravity="center"
            android:text="@{userBean.name}" />
    </FrameLayout>
</layout>
複製代碼

BindingFragment:

public class BindingFragment extends Fragment {


    private FragmentBindingBinding inflate;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment

        //Fragment
        inflate = DataBindingUtil.inflate(inflater, R.layout.fragment_binding, container, false);

        inflate.setUserBean(new UserBean("Fragment頁面 "));

        inflate.setClick(this);

        return inflate.getRoot();
    }
    public void onTextClick(View view){
        Toast.makeText(getActivity(), "Fragment頁面", Toast.LENGTH_SHORT).show();
    }
}
複製代碼

DataBindingUtil.inflate參數分析:

  • LayoutInflater:佈局管理
  • int: 顯示佈局id
  • ViewGroup:父佈局(ViewGroup)
  • boolean: 默認爲 false

Fragment和Activity只有獲取實例不同,其餘的都是同樣的操做!

效果圖(2.5):

RecyclerView綁定數據

activity_bin.xml:

<androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rel"
                android:layout_width="match_parent"
                android:layout_height="300dp"/>
複製代碼

BinActivity:

private ArrayList<UserBean> userBeans = new ArrayList<>();
		 
		 RecyclerView rel = findViewById(R.id.rel);

         rel.setLayoutManager(new LinearLayoutManager(this));

        //初始化數據
        initItem();

        rel.setAdapter(new MyAdapter(userBeans,this));

	/** * 初始化數據 */
    private void initItem() {
        for (int i = 0; i < 50; i++) {
            userBeans.add(new UserBean("數據: " + i));
        }
    }
複製代碼

這裏的代碼都很簡單,直接來看適配器吧~

item_layout.xml:適配器佈局

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="userBean"
            type="demo.ht.com.basequickadpater.beans.UserBean" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/tv"
            android:text="@{userBean.name}"
            android:textSize="30dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>
</layout>
複製代碼

MyAdapter適配器:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    public List<UserBean> list;
    public Context context;


    public MyAdapter(List<UserBean> list, Context context) {
        this.list = list;
        this.context = context;
    }

    @NonNull
    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ItemLayoutBinding inflate = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.item_layout, parent, false);
        ViewHolder viewHolder = new ViewHolder(inflate.getRoot());
        viewHolder.setInflate(inflate);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull MyAdapter.ViewHolder holder, int position) {
        holder.getInflate().setVariable(BR.userBean,list.get(position));

        //當數據改變時,binding會在下一幀去改變數據,若是咱們須要當即改變,就去調用executePendingBindings方法。
        holder.getInflate().executePendingBindings();
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        private ItemLayoutBinding inflate;

        public ItemLayoutBinding getInflate() {
            return inflate;
        }

        public void setInflate(ItemLayoutBinding inflate) {
            this.inflate = inflate;
        }

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }
}
複製代碼

onCreateViewHolder方法:

  • 該方法是用來設置子條目佈局的,和Fragment設置佈局的方法同樣,使用DataBindingUtil.inflate來設置佈局,
  • 經過ViewHolder來保存當前的狀態
  • 在onBindViewHolder經過獲取ViewHolder中的狀態來設置當前值

總說周知:
在RecyclerView適配器中,首先執行的值getItemCount()方法,其次是onCreateViewHolder()用來設置佈局,最後纔是onBindViewHolder()用來綁定數據

若是你們以爲這種辦法實在是太麻煩,推薦你們使用萬能適配器

有不懂的記得在評論區留言哦~

設置圖片

<?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">
<!--        DataBinding自動生成別名 -->
    <data>
    
 	    .....
 	    
        <!--        Image圖片     -->
        <variable
            name="imageUrl"
            type="demo.ht.com.basequickadpater.beans.ImageBean" />

    </data>

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="2000dp"
            android:gravity="center"
            android:orientation="vertical"
            tools:context=".activitys.BinActivity">	
					.....
            <ImageView
                app:url="@{imageUrl.url}"
                android:layout_width="match_parent"
                android:layout_height="100dp"/>
        </LinearLayout>
    </androidx.core.widget.NestedScrollView>

</layout>
複製代碼

ImageBean 類:

public class ImageBean extends BaseObservable {

    @Bindable
    private String  url;

    public ImageBean(String url) {
        this.url = url;
    }
    
    @BindingAdapter("bind:url")  //bind後的名字任意起,注方法必定要爲靜態,不然報錯
    public static void getImage(ImageView view, String url){
        Glide.with(view.getContext())
         .load(url)
         .apply(new RequestOptions().placeholder(R.mipmap.ic_launcher))
         .into(view);
    }
}
複製代碼

分析:

  • 這裏的getImage()必須爲靜態,不須要調用!
  • 須要添加註解 @BindingAdapter(「bind:XXX」)

這裏的url對應的佈局中的app:url:
在這裏插入圖片描述

BinActivity類:

ImageBean imageBean = new ImageBean("https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo_top-e3b63a0b1b.png");

binding.setImageUrl(imageBean);
複製代碼

效果圖(2.6):

獲取當前時間

和ImageView使用相似

activity_bin.xml佈局:

<?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="date"
            type="java.util.Date" />

    </data>
			...
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{date}" />
			...
</layout>
複製代碼

DateBean類:

public class DateBean {
    //獲取當前日期
    @BindingConversion
    public static String convertDate(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
        return sdf.format(date);
    }
}
複製代碼

分析:

  • 不須要調用,添加註釋後會自動走這裏
  • 必定要靜態!

BinActivity:

binding.setDate(new Date());
複製代碼

效果圖(2.6):

\

完整代碼

去博主主頁查看更多

原創不易,您的點贊就是對我最大的支持哦~

相關文章
相關標籤/搜索