• 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放在集合里?还会这么用?不解。

  • 相关阅读:
    jQuery中jsonp的跨域处理,no access-control-allow-origin,unexpected token
    doT中嵌套for循环的使用
    c++ new带括号和不带括号
    python装饰器之使用情景分析
    Python中classmethod与staticmethod区别
    python作用域 scope
    duck type鸭子类型
    EAFP和LBYL 两种防御性编程风格
    c++重载、覆盖和隐藏
    c++ 名字粉碎(name mangling)
  • 原文地址:https://www.cnblogs.com/mhbs/p/11836434.html
Copyright © 2020-2023  润新知