android 数据绑定(4)实用特性及疑惑:使用控件、格式化@string/xxx、对象传递、双向数据绑定

1.在布局内使用其它控件 

1.1 效果

  箭头所指3个控件的内容随输入框内容而变化。

1.2 示例代码

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <layout xmlns:app="http://schemas.android.com/apk/res-auto"
 3     xmlns:tools="http://schemas.android.com/tools"
 4     xmlns:android="http://schemas.android.com/apk/res/android">
 5     <data>
 6         <import type="android.view.View" />
 7         <import type="com.example.databind.Exts" />
 8     </data>
 9     <androidx.constraintlayout.widget.ConstraintLayout
10         android:clickable="true"
11         android:background="#ffffff"
12         android:layout_width="match_parent"
13         android:layout_height="match_parent">
14 
15         <TextView
16             android:id="@+id/features_title"
17             android:layout_width="wrap_content"
18             android:layout_height="wrap_content"
19             android:layout_marginTop="16dp"
20             android:text="binding features"
21             android:textAllCaps="false"
22             app:layout_constraintEnd_toEndOf="parent"
23             app:layout_constraintStart_toStartOf="parent"
24             app:layout_constraintTop_toTopOf="parent" />
25 
26 
27         <TextView
28             android:id="@+id/features_txt1"
29             android:layout_width="wrap_content"
30             android:layout_height="wrap_content"
31             android:layout_marginTop="48dp"
32             android:background="#f8f8f8"
33             android:textSize="12sp"
34             android:text='@{featureEdt.text.toString(),default="取 feature_edt 的值"}'
35             app:layout_constraintEnd_toStartOf="@+id/features_txt2"
36             app:layout_constraintStart_toStartOf="parent"
37             app:layout_constraintTop_toBottomOf="@+id/feature_edt" />
38 
39         <TextView
40             android:id="@+id/features_txt2"
41             android:layout_width="wrap_content"
42             android:layout_height="wrap_content"
43             android:background="#f8f8f8"
44             android:textSize="12sp"
45             android:text='@{featureEdt.text.toString(),default="取 feature_edt 的值"}'
46             app:layout_constraintBottom_toBottomOf="@+id/features_txt1"
47             app:layout_constraintEnd_toEndOf="parent"
48             app:layout_constraintStart_toEndOf="@+id/features_txt1"
49             app:layout_constraintTop_toTopOf="@+id/features_txt1" />
50         <!--android:textColor="@{featureEdt.text.hasCharX('e') ? @color/colorAccent : @color/colorPrimaryDark }"-->
51 
52         <EditText
53             android:id="@+id/feature_edt"
54             android:layout_width="0dp"
55             android:layout_height="64dp"
56             android:layout_marginStart="16dp"
57             android:layout_marginLeft="16dp"
58             android:layout_marginTop="32dp"
59             android:layout_marginEnd="16dp"
60             android:layout_marginRight="16dp"
61             android:background="@drawable/edt_bg"
62             android:ems="10"
63             android:textColor='@{featureEdt.text.toString().length() > 8 ? @color/colorAccent : @color/colorPrimaryDark }'
64             android:inputType="textPersonName"
65             android:paddingLeft="8dp"
66             android:text="Name"
67             android:maxLength="16"
68             android:maxLines="1"
69             android:textAllCaps="false"
70             android:textSize="12sp"
71             app:layout_constraintEnd_toEndOf="parent"
72             app:layout_constraintStart_toStartOf="parent"
73             app:layout_constraintTop_toBottomOf="@+id/features_title" />
74 
75         <TextView
76             android:id="@+id/toast"
77             android:layout_width="wrap_content"
78             android:layout_height="wrap_content"
79             android:textSize="9sp"
80             android:textColor='@{featureEdt.text.toString().length() &lt; 1 ? @color/colorAccent : @color/colorPrimaryDark,default=@color/colorPrimary}'
81             android:text='@{featureEdt.text.toString().length() &lt; 1 ? "不能为空" :"1-16个字符",default = "1-16个字符"}'
82             app:layout_constraintStart_toStartOf="@+id/feature_edt"
83             app:layout_constraintTop_toBottomOf="@+id/feature_edt" />
84 
85     </androidx.constraintlayout.widget.ConstraintLayout>
86 </layout>

1.3 特性描述

  • 控件按驼峰式命名法命名,如 :   feature_edt   ->   featureEdt
  • 其它控件可以在布局内访问这个控件以及它的成员,第34、45、81行。
  • 不可以调用控件的扩展成员。第50行。
  • 控件自己可以调用自己,第63行。

2. 可以使用格式化字符串

  • 示例,@string/xxx 可以和 “字符串” 相加 ,如下
    1     <TextView
    2             android:id="@+id/tvFormat"
    3             android:layout_width="wrap_content"
    4             android:layout_height="wrap_content"
    5             android:layout_marginTop="24dp"
    6             android:text='@{@string/format("李4",0x20,33.333333f) + " string/xxx 可以和 字符串相加 ",default=@string/format}'
    7             app:layout_constraintStart_toStartOf="@+id/feature_edt"
    8             app:layout_constraintTop_toBottomOf="@+id/features_txt1" />
  • string.xml
    1 <resources>
    2     <string name="app_name">DataBind</string>
    3     <string name="format">format : name=%1$s,age=%2$1d,value=%3$32f </string>
    4     //...
    5 </resources>
     

3.对象传递到include布局中

3.1 示例

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <layout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:tools="http://schemas.android.com/tools"
 4     xmlns:app="http://schemas.android.com/apk/res-auto"
 5     xmlns:bind="http://schemas.android.com/apk/res-auto">
 6     <data>
 7         <variable name="data" type="com.example.databind.Data" />
 8         <variable name="click" type="com.example.databind.Click" />
 9     </data>
10 
11     <androidx.constraintlayout.widget.ConstraintLayout
12         android:layout_width="match_parent"
13         android:layout_height="match_parent"
14         android:clickable="true"
15         android:focusable="true"
16         android:focusableInTouchMode="true"
17         android:onClick="@{click::onStartClicked}">
18 
19         //...
20 
21         <include
22             android:id="@+id/include"
23             layout="@layout/include"
24             android:layout_width="0dp"
25             android:layout_height="wrap_content"
26             android:layout_marginTop="16dp"
27             app:layout_constraintEnd_toEndOf="@+id/frgmt2"
28             app:layout_constraintStart_toStartOf="@+id/frgmt2"
29             app:layout_constraintTop_toBottomOf="@+id/frgmt2"
30             bind:data="@{data}"
31             bind:title='@{"标题"}'
32             />
33 ...

  代码中把 data 传递给 @layout/include ,要求这个布局也使用数据绑定布局,且也声明data和title变量。

如下:

 1 <layout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:app="http://schemas.android.com/apk/res-auto">
 3 
 4     <data>
 5         <variable name="data" type="com.example.databind.Data" />
 6         <variable name="title" type="String" />
 7     </data>
 8 
 9     <androidx.constraintlayout.widget.ConstraintLayout
10         android:layout_width="match_parent"
11         android:layout_height="wrap_content"
12         android:background="#7ff77ff7"
13         >
14     
15         //...
16 
17         <TextView
18             android:id="@+id/value"
19             android:layout_width="wrap_content"
20             android:layout_height="wrap_content"
21             android:layout_marginStart="32dp"
22             android:layout_marginLeft="32dp"
23             android:text="@{String.valueOf(data.value),default = value}"
24             app:layout_constraintEnd_toEndOf="parent"
25             app:layout_constraintStart_toEndOf="@+id/key"
26             app:layout_constraintTop_toTopOf="@+id/key" />
27 
28       
29 
30     </androidx.constraintlayout.widget.ConstraintLayout>
31 </layout>

3.2 不支持 merge 为直接子元素

数据绑定不支持 include 作为 merge 元素的直接子元素

 1     <?xml version="1.0" encoding="utf-8"?>
 2     <layout xmlns:android="http://schemas.android.com/apk/res/android"
 3             xmlns:bind="http://schemas.android.com/apk/res-auto">
 4        <data>
 5            <variable name="user" type="com.example.User"/>
 6        </data>
 7        <merge><!-- Doesn't work -->
 8            <include layout="@layout/name"
 9                bind:user="@{user}"/>
10            <include layout="@layout/contact"
11                bind:user="@{user}"/>
12        </merge>
13     </layout>
14     

#.后台线程的疑惑

#.1 问题

英文原版

中文版 

#.2 疑惑?

  Collection<T> 实现类 里存放的数据,不能在后台线程中修改?

#.3 测试代码

  在后台线程中对list 操作,并没有发现问题

  1 package com.example.databind
  2 
  3 import android.os.Bundle
  4 import android.view.LayoutInflater
  5 import android.view.View
  6 import android.view.ViewGroup
  7 import androidx.databinding.ObservableField
  8 import androidx.fragment.app.Fragment
  9 import com.example.databind.databinding.MapCollectionBinding
 10 import kotlin.concurrent.thread
 11 
 12 class MapCollectionFrgmt : Fragment() {
 13 
 14     lateinit var binding : MapCollectionBinding
 15 
 16     val list    = ArrayList<String>()
 17     val map     = HashMap<String,ObservableField<String>>()
 18     val data    = Data()
 19 
 20     init {
 21         data.key = "data key"
 22         data.key = "data value"
 23 
 24         map.put("key1",ObservableField("value1"))
 25         map.put("key2",ObservableField("value2"))
 26         map.put("key3",ObservableField("value3"))
 27         map.put("key4",ObservableField("value4"))
 28 
 29         list.add("value0")
 30         list.add("value1")
 31         list.add("value2")
 32         list.add("value3")
 33     }
 34 
 35 
 36     fun onDataThreadMainClicked(view: View){
 37         val random = (Math.random() * 1000).toInt()
 38         data.key = "新Main key$random"
 39         data.value = random
 40         binding.data = data
 41     }
 42 
 43     fun onDataThreadOtherClicked(view: View){
 44         thread {
 45             val random = (Math.random() * 1000).toInt()
 46             data.key = "新other key$random"
 47             data.value = random
 48             binding.data = data
 49         }
 50     }
 51 
 52     fun onMap1ThreadMain(v : View){
 53         val random = (Math.random() * 1000).toInt()
 54         val ob = ObservableField<String>()
 55         ob.set("新Main value$random")
 56         map.put("key1",ob)
 57         binding.map = map
 58     }
 59     fun onMap1ThreadOther(v : View){
 60         thread {
 61             val random = (Math.random() * 1000).toInt()
 62             val ob = ObservableField<String>()
 63             ob.set("新Main value$random")
 64             map.put("key1",ob)
 65             binding.map = map
 66         }
 67     }
 68     fun onList0ThreadMain(v : View){
 69         val random = (Math.random() * 1000).toInt()
 70         list[0] = "新Main value$random"
 71         binding.list = list
 72     }
 73     fun onList0ThreadOther(v : View){
 74         thread {
 75             val random = (Math.random() * 1000).toInt()
 76             list[0] = "新Main value$random"
 77             binding.list = list
 78         }
 79     }
 80     fun initBinding(){
 81         binding.list = list
 82         binding.data = data
 83         binding.map = map
 84 
 85         binding.threadMainData.setOnClickListener(this::onDataThreadMainClicked)
 86         binding.threadOtherData.setOnClickListener(this::onDataThreadOtherClicked)
 87         binding.threadMainMap1.setOnClickListener(this::onMap1ThreadMain)
 88         binding.threadOtherMap1.setOnClickListener(this::onMap1ThreadOther)
 89         binding.threadMainList0.setOnClickListener(this::onList0ThreadMain)
 90         binding.threadOtherList0.setOnClickListener(this::onList0ThreadOther)
 91         /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
 92             val text: String = getString(R.string.map_title, map.size)
 93             val styledText: Spanned = Html.fromHtml(text, FROM_HTML_OPTION_USE_CSS_COLORS)
 94             binding.mapTitle.text = styledText
 95         }*/
 96     }
 97 
 98 
 99     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
100         binding = MapCollectionBinding.inflate(inflater,container,false)
101         initBinding()
102         return binding.root
103     }
104 
105     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
106         super.onViewCreated(view, savedInstanceState)
107     }
108 
109     override fun onDetach() {
110         super.onDetach()
111     }
112 
113 }

布局

  1 <?xml version="1.0" encoding="utf-8"?>
  2 <layout xmlns:app="http://schemas.android.com/apk/res-auto"
  3     xmlns:tools="http://schemas.android.com/tools"
  4     xmlns:android="http://schemas.android.com/apk/res/android">
  5     <data >
  6         <import type="androidx.databinding.ObservableField" />
  7         <variable name="data" type="com.example.databind.Data" />
  8         <variable name="map" type="java.util.HashMap&lt;String,ObservableField&lt;String>>" />
  9         <variable name="list" type="java.util.List&lt;String>" />
 10     </data>
 11     <androidx.constraintlayout.widget.ConstraintLayout
 12         android:clickable="true"
 13         android:background="#ffffff"
 14         android:layout_width="match_parent"
 15         android:layout_height="match_parent">
 16 
 17         <TextView
 18             android:id="@+id/data_title"
 19             android:layout_width="0dp"
 20             android:layout_height="wrap_content"
 21             android:layout_marginTop="16dp"
 22             android:background="#f6f6f6"
 23             android:paddingLeft="16dp"
 24             android:text="data "
 25             app:layout_constraintEnd_toEndOf="parent"
 26             app:layout_constraintStart_toStartOf="parent"
 27             app:layout_constraintTop_toTopOf="parent" />
 28 
 29         <TextView
 30             android:id="@+id/map_title"
 31             android:layout_width="0dp"
 32             android:layout_height="wrap_content"
 33             android:layout_marginTop="16dp"
 34             android:background="#f8f8f8"
 35             android:paddingLeft="16dp"
 36             android:text="@{@string/map_title(map.size()) ,default=@string/map_title}"
 37             app:layout_constraintEnd_toEndOf="parent"
 38             app:layout_constraintStart_toStartOf="parent"
 39             app:layout_constraintTop_toBottomOf="@+id/data_key" />
 40 
 41 
 42         <TextView
 43             android:id="@+id/data_key"
 44             android:layout_width="wrap_content"
 45             android:layout_height="wrap_content"
 46             android:layout_marginStart="32dp"
 47             android:layout_marginLeft="32dp"
 48             android:layout_marginTop="16dp"
 49             android:text='@{data.key}'
 50             app:layout_constraintStart_toStartOf="@+id/data_title"
 51             app:layout_constraintTop_toBottomOf="@+id/data_title" />
 52 
 53         <TextView
 54             android:id="@+id/data_value"
 55             android:layout_width="wrap_content"
 56             android:layout_height="wrap_content"
 57             android:layout_marginStart="16dp"
 58             android:layout_marginLeft="16dp"
 59             android:text='@{String.valueOf(data.value)}'
 60             app:layout_constraintStart_toEndOf="@+id/data_key"
 61             app:layout_constraintTop_toTopOf="@+id/data_key" />
 62 
 63         <TextView
 64             android:id="@+id/map_key1"
 65             android:layout_width="wrap_content"
 66             android:layout_height="wrap_content"
 67             android:layout_marginStart="24dp"
 68             android:layout_marginLeft="24dp"
 69             android:layout_marginTop="16dp"
 70             android:text='@{@string/map_key_value("key1",map["key1"]),default=@string/map_key_value}'
 71             app:layout_constraintStart_toStartOf="parent"
 72             app:layout_constraintTop_toBottomOf="@+id/map_title" />
 73 
 74         <TextView
 75             android:id="@+id/map_key3"
 76             android:layout_width="wrap_content"
 77             android:layout_height="wrap_content"
 78             android:layout_marginTop="8dp"
 79             android:text='@{@string/map_key_value("key1",map["key3"]),default=@string/map_key_value}'
 80             app:layout_constraintStart_toStartOf="@+id/map_key1"
 81             app:layout_constraintTop_toBottomOf="@+id/map_key2" />
 82 
 83         <TextView
 84             android:id="@+id/map_key4"
 85             android:layout_width="wrap_content"
 86             android:layout_height="wrap_content"
 87             android:layout_marginTop="8dp"
 88             android:text='@{@string/map_key_value("无效key",map["无效key"]),default=@string/map_key_value}'
 89             app:layout_constraintStart_toStartOf="@+id/map_key2"
 90             app:layout_constraintTop_toBottomOf="@+id/map_key3" />
 91 
 92         <TextView
 93             android:id="@+id/map_key2"
 94             android:layout_width="wrap_content"
 95             android:layout_height="wrap_content"
 96             android:layout_marginTop="8dp"
 97             android:text='@{@string/map_key_value("key2",map["key2"]),default=@string/map_key_value}'
 98             app:layout_constraintStart_toStartOf="@+id/map_key1"
 99             app:layout_constraintTop_toBottomOf="@+id/map_key1" />
100 
101 
102         <TextView
103             android:id="@+id/list_title"
104             android:layout_width="0dp"
105             android:layout_height="wrap_content"
106             android:layout_marginTop="24dp"
107             android:background="#f8f8f8"
108             android:paddingLeft="16dp"
109             android:text="@{@string/list_title(list.size()) ,default=@string/list_title}"
110             app:layout_constraintEnd_toEndOf="parent"
111             app:layout_constraintStart_toStartOf="parent"
112             app:layout_constraintTop_toBottomOf="@+id/map_key4" />
113 
114 
115         <TextView
116             android:id="@+id/list_0"
117             android:layout_width="wrap_content"
118             android:layout_height="wrap_content"
119             android:layout_marginStart="24dp"
120             android:layout_marginLeft="24dp"
121             android:layout_marginTop="16dp"
122             android:text='@{@string/list_index(0,list[0]),default=@string/list_index}'
123             app:layout_constraintStart_toStartOf="parent"
124             app:layout_constraintTop_toBottomOf="@+id/list_title" />
125 
126         <TextView
127             android:id="@+id/list_1"
128             android:layout_width="wrap_content"
129             android:layout_height="wrap_content"
130             android:layout_marginTop="8dp"
131             android:text='@{@string/list_index(1,list[1]),default=@string/list_index}'
132             app:layout_constraintStart_toStartOf="@+id/list_0"
133             app:layout_constraintTop_toBottomOf="@+id/list_0" />
134 
135         <TextView
136             android:id="@+id/list_2"
137             android:layout_width="wrap_content"
138             android:layout_height="wrap_content"
139             android:layout_marginTop="8dp"
140             android:text='@{@string/list_index(2,list[2]),default=@string/list_index}'
141             app:layout_constraintStart_toStartOf="@+id/list_1"
142             app:layout_constraintTop_toBottomOf="@+id/list_1" />
143 
144         <TextView
145             android:id="@+id/list_3"
146             android:layout_width="104dp"
147             android:layout_height="15dp"
148             android:layout_marginTop="8dp"
149             android:text='@{@string/list_index(-1,list[-1]) ,default=@string/list_index}'
150             app:layout_constraintStart_toStartOf="@+id/list_2"
151             app:layout_constraintTop_toBottomOf="@+id/list_2" />
152 
153         <TextView
154             android:id="@+id/thread_title"
155             android:layout_width="0dp"
156             android:layout_height="wrap_content"
157             android:layout_marginTop="32dp"
158             android:background="#f8f8f8"
159             android:paddingLeft="16dp"
160             android:text="在线程中修改数据"
161             app:layout_constraintEnd_toEndOf="parent"
162             app:layout_constraintStart_toStartOf="parent"
163             app:layout_constraintTop_toBottomOf="@+id/list_3" />
164 
165         <Button
166             android:id="@+id/thread_main_data"
167             android:layout_width="wrap_content"
168             android:layout_height="wrap_content"
169             android:layout_marginTop="16dp"
170             android:text="主线程修改data"
171             android:textAllCaps="false"
172             app:layout_constraintEnd_toStartOf="@+id/thread_other_data"
173             app:layout_constraintStart_toStartOf="parent"
174             app:layout_constraintTop_toBottomOf="@+id/thread_title" />
175 
176         <Button
177             android:id="@+id/thread_other_data"
178             android:layout_width="wrap_content"
179             android:layout_height="wrap_content"
180             android:layout_marginTop="16dp"
181             android:text="非主线程修改data"
182             android:textAllCaps="false"
183             app:layout_constraintEnd_toEndOf="parent"
184             app:layout_constraintStart_toEndOf="@+id/thread_main_data"
185             app:layout_constraintTop_toBottomOf="@+id/thread_title" />
186 
187         <Button
188             android:id="@+id/thread_main_list0"
189             android:layout_width="wrap_content"
190             android:layout_height="wrap_content"
191             android:layout_marginTop="16dp"
192             android:text="主线程修改list[0]"
193             android:textAllCaps="false"
194             app:layout_constraintEnd_toStartOf="@+id/thread_other_list0"
195             app:layout_constraintStart_toStartOf="parent"
196             app:layout_constraintTop_toBottomOf="@+id/thread_main_data" />
197 
198         <Button
199             android:id="@+id/thread_other_list0"
200             android:layout_width="wrap_content"
201             android:layout_height="wrap_content"
202             android:layout_marginTop="16dp"
203             android:text="非主线程修改list[0]"
204             android:textAllCaps="false"
205             app:layout_constraintEnd_toEndOf="parent"
206             app:layout_constraintStart_toEndOf="@+id/thread_main_list0"
207             app:layout_constraintTop_toBottomOf="@+id/thread_main_data" />
208 
209         <Button
210             android:id="@+id/thread_main_map1"
211             android:layout_width="wrap_content"
212             android:layout_height="wrap_content"
213             android:layout_marginTop="16dp"
214             android:text="主线程修改map[key1]"
215             android:textAllCaps="false"
216             app:layout_constraintEnd_toStartOf="@+id/thread_other_map1"
217             app:layout_constraintStart_toStartOf="parent"
218             app:layout_constraintTop_toBottomOf="@+id/thread_main_list0" />
219 
220         <Button
221             android:id="@+id/thread_other_map1"
222             android:layout_width="wrap_content"
223             android:layout_height="wrap_content"
224             android:layout_marginTop="16dp"
225             android:text="非主线程修改map[key1]"
226             android:textAllCaps="false"
227             app:layout_constraintEnd_toEndOf="parent"
228             app:layout_constraintStart_toEndOf="@+id/thread_main_map1"
229             app:layout_constraintTop_toBottomOf="@+id/thread_main_list0" />
230 
231     </androidx.constraintlayout.widget.ConstraintLayout>
232 </layout>

 

#.4 viewModel 放在集合里?

  布局文件中通过viewModel访问数据,然后viewModel放在集合里?还会这么用?不解。

原文地址:https://www.cnblogs.com/mhbs/p/11836434.html