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