android-data-binding
這是一個可以將 json 字符串 直接綁定到 view 上的庫, 不用先將 json 轉換為 model 類。
github 傳送門: https://github.com/gplibs/android-data-binding
1. 安裝
gradle:
dependencies { compile 'com.gplibs:data-binding:1.0.0'}
2. 一個簡單的例子
json字符串數據源 json_data_source_binding_json.txt:
{ name: "my name"}
StringJsonDataSourceBindingActivity:
public class StringJsonDataSourceBindingActivity extends AppCompatActivity { // 將 json 中的 name 字符段綁定到 TextView 的 text 上 @Binding(source = "name", target = "text") private TextView tvName; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_string_json_data_source_binding); tvName = (TextView) findViewById(R.id.tv_name); // 讀取json數據 String json = Utils.readText("json_data_source_binding_json.txt"); // 綁定操作 BindingManager.binding(json, this); } }
運行結果
3. 值轉換
某些時候數據源的類型可能與 view 的目標字段類型不一致,此時就需要對值進行轉換。
json字符串數據源 convert_binding_json.txt:
{ name: "my name", sex: 1, head_url: "https://github.com/gplibs/resources/raw/master/sample.jpeg", is_vip: true}
定義一個將 boolean 轉換為 visibility 的轉換器:
class BooleanToVisibilityConverter implements IValueConverter { @Override public Object convert(Object sourceValue) { return ((Boolean) sourceValue) ? View.VISIBLE : View.GONE; } }
定義一個將 表示性別的整形值 轉換為對應文本的轉換器:
class SexToStringConverter implements IValueConverter { @Override public Object convert(Object sourceValue) { return (((Integer) sourceValue) == 0) ? "Female" : "Male"; } }
定義一個將 url字符串 轉換為 bitmap 的轉換器:
(為了不阻塞主線程,實現的是一個異步轉換器接口 IAsyncValueConverter)
class UrlToBitmapConverter implements IAsyncValueConverter { @Override public void convert(final Object sourceValue, final IValueConverterCallback callback) { Executors.newSingleThreadExecutor().submit(new Runnable() { @Override public void run() { try { URL url = new URL((String) sourceValue); callback.run(BitmapFactory.decodeStream(url.openStream())); } catch (Exception ex) { ex.printStackTrace(); } } }); } }
ConvertBindingActivity:
public class ConvertBindingActivity extends AppCompatActivity { @Binding(source = "name", target = "text") private TextView tvName; // 使用轉換器將 json 中整形字段 sex 轉換為對應文案, 綁定到 TextView 的 text 上 @ConvertBinding(source = "sex", target = "text", converter = SexToStringConverter.class) private TextView tvSex; // 使用轉換器將 json 中布爾字段 is_vip 轉換為對應 visibility, 綁定到 TextView 的 visibility 上, 是 vip 才顯示 @ConvertBinding(source = "is_vip", target = "visibility", converter = BooleanToVisibilityConverter.class) private TextView tvVip; // 使用轉換器將 json 中布爾字段 head_url 轉換為 bitmap, 綁定到 ImageView 的 imageBitmap 上 @ConvertBinding(source = "head_url", target = "imageBitmap", converter = UrlToBitmapConverter.class) private ImageView ivHead; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_convert_binding); tvName = (TextView) findViewById(R.id.tv_name); tvSex = (TextView) findViewById(R.id.tv_sex); tvVip = (TextView) findViewById(R.id.tv_vip); ivHead = (ImageView) findViewById(R.id.iv_head); // 讀取json數據 String json = Utils.readText("convert_binding_json.txt"); // 綁定操作 BindingManager.binding(json, this); } }
運行結果
4. 將多個字段綁定到同一個 View 的不同屬性上
json字符串數據源 multi_binding_json.txt:
{ name: "my name", is_vip: true, vip_data: "I am Vip"}
定義一個將 boolean 轉換為 visibility 的轉換器:
class BooleanToVisibilityConverter implements IValueConverter { @Override public Object convert(Object sourceValue) { return ((Boolean) sourceValue) ? View.VISIBLE : View.GONE; } }
MultiBindingActivity:
public class MultiBindingActivity extends AppCompatActivity { @Binding(source = "name", target = "text") private TextView tvName; // 將 json 字段 is_vip 綁定到 TextView 的 visibility 上, 是 vip 才顯示 // 將 json 字段 vip_data 綁定到 TextView 的 text 上 @ConvertBinding(source = "is_vip", target = "visibility", converter = BooleanToVisibilityConverter.class) @Binding(source = "vip_data", target = "text") private TextView tvVip; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_multi_binding); tvName = (TextView) findViewById(R.id.tv_name); tvVip = (TextView) findViewById(R.id.tv_vip); // 讀取 json 文本 String json = Utils.readText("multi_binding_json.txt"); // 綁定操作 BindingManager.binding(json, this); } }
運行結果
5. 路徑綁定
某些 json 有較復雜的數據結構,有子對象 或者 數組; 我們也可以將子對象或者數組中的字段綁定到 View 上;
路徑綁定語法中 "." 可以獲取子對象; ".[數字索引]" 可以獲取數組中某索引處的元素。
json字符串數據源 path_binding_json.txt:
{ name: "my name", father: { name: "my father" }, children: [ { name: "my son" }, { name: "my daughter" } ]}
PathBindingActivity:
public class PathBindingActivity extends AppCompatActivity { @Binding(source = "name", target = "text") private TextView tvName; // 將 json 中子對象 father 的 name 字段綁定到 TextView 的 text 上 @Binding(source = "father.name", target = "text") private TextView tvFatherName; // 將 json 中子對象 children 數組的第0個元素的 name 字段綁定到 TextView 的 text 上 @Binding(source = "children.[0].name", target = "text") private TextView tvSonName; // 將 json 中子對象 children 數組的第1個元素的 name 字段綁定到 TextView 的 text 上 @Binding(source = "children.[1].name", target = "text") private TextView tvDaughterName; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_path_binding); tvName = (TextView) findViewById(R.id.tv_name); tvFatherName = (TextView) findViewById(R.id.tv_father_name); tvSonName = (TextView) findViewById(R.id.tv_son_name); tvDaughterName = (TextView) findViewById(R.id.tv_daughter_name); // 讀取 json 文本 String json = Utils.readText("path_binding_json.txt"); // 綁定操作 BindingManager.binding(json, this); } }
運行結果
5. 其他非字符串數據源
除了可以使用 json 字符串作為數據源外,我們也簡單支持其他數據源進行綁定。
a. Model類作為數據源, 需實現 ModelSource:
class TestModel extends ModelSource { // @BindingField注解作用為:讓框架使用其標注的名稱作為綁定中數據源字段名 // GSON 中的 @SerializedName 注解也有同樣的效果 @BindingField("name") public String name = "my name"; }
public class ModelSourceActivity extends AppCompatActivity { @Binding(source = "name", target = "text") private TextView tvName; private Button btnTest; private int index; private TestModel testModel = new TestModel(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_model_source); tvName = (TextView) findViewById(R.id.tv_name); btnTest = (Button) findViewById(R.id.btn_test); btnTest.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 修改 ModelSource 的 name 屬性, 界面也會一起改變。 testModel.setProperty("name", "new name " + (++index)); } }); // 綁定操作 BindingManager.binding(testModel, this); } }
運行結果
b. 數組數據源:
可以使用 "[數字索引]" 語法將某個元素綁定到 View。
public class ArraySourceActivity extends AppCompatActivity { @Binding(source = "[0]", target = "text") private TextView tvName; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_array_source); tvName = (TextView) findViewById(R.id.tv_name); String[] data = new String[] { "item1", "item2", "item3" }; BindingManager.binding(data, this); } }
c. Collection數據源:
與數組數據源一樣
public class CollectionSourceActivity extends AppCompatActivity { @Binding(source = "[1]", target = "text") private TextView tvName; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_collection_source); tvName = (TextView) findViewById(R.id.tv_name); Collection<String> data = new ArrayList<>(); data.add("item1"); data.add("item2"); data.add("item3"); BindingManager.binding(data, this); } }
d. Map數據源:
只支持 Key 類型為 String 的 Map。
public class MapSourceActivity extends AppCompatActivity { @Binding(source = "key1", target = "text") private TextView tvName; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_map_source); tvName = (TextView) findViewById(R.id.tv_name); Map<String, String> data = new HashMap<>(); data.put("key1", "value1"); BindingManager.binding(data, this); http://www.cnblogs.com/gplibs/p/6536658.html