使用动态添加的元素进行数据绑定
Data-binding with dynamically added elements
我已经开始为我的新应用实施 Android 数据绑定库。但是,我在数据动态添加元素方面遇到了一些困难。在我的 POJO
中,它包含一张 <String,Double>
的地图。这里,String
是用户id,Double
是金额。我有一个用于显示单个条目的布局文件。所以,如果 map 包含 2 个元素,它将看起来像这样:
以前,我是通过在循环内膨胀布局并为地图的每个项目添加到 LinearLayout
来完成此操作的。但是,现在我想用数据绑定来做到这一点。
因为,Map
中的元素数量可以是1到20之间的任何值,我默认不能在布局文件中添加。我必须根据地图中的条目充气。我已经成功地实现了 POJO
的数据绑定,而没有 Map
。但是,无法理解如何通过数据绑定轻松完成此操作。
那么,有没有办法直接在数据绑定(在布局文件中)或在 java 代码中使用尽可能少的代码?
编辑:
对于所有看到它是简单的 RecyclerView
的人来说,事实并非如此。我同意 RecyclerView
是一个很好的选择,当你有一个包含一些元素的列表并且滚动视图将提高性能时。在这里,我在此列表的上方和下方有多个不同类型的元素。我也将 RecyclerView
与数据绑定一起使用,我知道它是如何工作的,但这里不是这种情况。我只想使用数据绑定在布局 (LinearLayout) 中膨胀多行。
这不是数据绑定的用途。这些用于将数据绑定到静态定义的布局。创建或管理视图层次结构是可能的,但也比仅使用 RecyclerView
及其适配器要复杂得多。
如果您更喜欢从布局中设置数据,您可以为数据绑定库编写 Custom Setters 并在此范围内创建适配器。
@BindingAdapter({"adapter"})
public static void bindAdapter(RecyclerView view, Map<String, Double> data) {
RecyclerView.Adapter adapter = ...;
view.setAdapter(adapter);
}
要使数据以动态方式成为 added/removed,您应该使用 Adapter
而不是使用您的方式添加它。正如 google 所建议的那样,RecycelerView
在 UI 和内存控制方面具有更好的性能。我做了一些简单的代码,可能适合你。
对于适配器,以及绑定方法。
public class MyOwnBindingUtil {
public static class Holder extends RecyclerView.ViewHolder {
private ItemBinding mItemBinding;
public Holder(ItemBinding itemView) {
super(itemView.getRoot());
mItemBinding = itemView;
}
}
public static class OwnAdapter extends RecyclerView.Adapter<Holder> {
private Map<String, String> mMap;
private List<String> keys;
private List<Double> values;
public OwnAdapter() {
keys = new ArrayList<>();
values = new ArrayList<>();
}
public void add(String key, Double value) {
keys.add(key);
values.add(value);
}
@Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
ItemBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item, parent, false);
return new MyOwnBindingUtil.Holder(binding);
}
@Override
public void onBindViewHolder(Holder holder, int position) {
holder.mItemBinding.setKey(keys.get(position));
holder.mItemBinding.setValue(String.valueOf(values.get(position)));
}
@Override
public int getItemCount() {
return keys.size();
}
}
@BindingAdapter("data:map")
public static void bindMap(RecyclerView pRecyclerView, Map<String, Double> pStringStringMap) {
pRecyclerView.setLayoutManager(new LinearLayoutManager(pRecyclerView.getContext()));
OwnAdapter lAdapter = new OwnAdapter();
for (Map.Entry<String, Double> lStringStringEntry : pStringStringMap.entrySet()) {
lAdapter.add(lStringStringEntry.getKey(), lStringStringEntry.getValue());
}
pRecyclerView.setAdapter(lAdapter);
}
}
如果您坚持使用 Map 而不是列表作为数据,则会出现一些问题,因为 Map 没有索引,但是 适配器根据索引获取数据数据集.
https://www.mkyong.com/java8/java-8-convert-map-to-list/
How to convert a Map to List in Java?
How does one convert a HashMap to a List in Java?
在您的 xml 中,您可以将地图设置为 recyclerview,您的数据集可以在 xml 中设置。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:data="http://schemas.android.com/tools"
>
<data>
<import type="java.lang.String"/>
<import type="java.util.Map"/>
<variable
name="map"
type="Map<String, String>"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
data:map="@{map}"/>
</LinearLayout>
</layout>
在您的 activity 代码中,
Map<String, String> lStringStringMap = new HashMap<>();
lStringStringMap.put("A", "A1");
lStringStringMap.put("B", "B1");
lStringStringMap.put("C", "C1");
mBinding.setMap(lStringStringMap);
由于您更喜欢自己动态创建布局,我建议采用以下方法。目前这完全是理论上的,但我看不出为什么这不适合你。
考虑到您将 Map
设置为自定义绑定属性。
<LinearLayout ...
app:inflateData="@{dataMap}" />
然后您必须创建一个 @BindingAdapter
来处理适配器为您做的事情。
@BindingAdapter({"inflateData"})
public static void inflateData(LinearLayout layout, Map<String, Double> data) {
LayoutInflater inflater = LayoutInflater.from(layout.getContext());
for (Entry<String, Double> entry : data.entrySet()) {
MyItem myItem = inflater.inflate(R.layout.my_item, layout, true);
myItem.setKey(entry.getKey);
myItem.setValue(entry.getValue);
}
}
在这里,您为项目扩充布局并将其添加到父布局。您可以通过向布局和绑定适配器添加更多属性来进一步概括它。
我已经开始为我的新应用实施 Android 数据绑定库。但是,我在数据动态添加元素方面遇到了一些困难。在我的 POJO
中,它包含一张 <String,Double>
的地图。这里,String
是用户id,Double
是金额。我有一个用于显示单个条目的布局文件。所以,如果 map 包含 2 个元素,它将看起来像这样:
以前,我是通过在循环内膨胀布局并为地图的每个项目添加到 LinearLayout
来完成此操作的。但是,现在我想用数据绑定来做到这一点。
因为,Map
中的元素数量可以是1到20之间的任何值,我默认不能在布局文件中添加。我必须根据地图中的条目充气。我已经成功地实现了 POJO
的数据绑定,而没有 Map
。但是,无法理解如何通过数据绑定轻松完成此操作。
那么,有没有办法直接在数据绑定(在布局文件中)或在 java 代码中使用尽可能少的代码?
编辑:
对于所有看到它是简单的 RecyclerView
的人来说,事实并非如此。我同意 RecyclerView
是一个很好的选择,当你有一个包含一些元素的列表并且滚动视图将提高性能时。在这里,我在此列表的上方和下方有多个不同类型的元素。我也将 RecyclerView
与数据绑定一起使用,我知道它是如何工作的,但这里不是这种情况。我只想使用数据绑定在布局 (LinearLayout) 中膨胀多行。
这不是数据绑定的用途。这些用于将数据绑定到静态定义的布局。创建或管理视图层次结构是可能的,但也比仅使用 RecyclerView
及其适配器要复杂得多。
如果您更喜欢从布局中设置数据,您可以为数据绑定库编写 Custom Setters 并在此范围内创建适配器。
@BindingAdapter({"adapter"})
public static void bindAdapter(RecyclerView view, Map<String, Double> data) {
RecyclerView.Adapter adapter = ...;
view.setAdapter(adapter);
}
要使数据以动态方式成为 added/removed,您应该使用 Adapter
而不是使用您的方式添加它。正如 google 所建议的那样,RecycelerView
在 UI 和内存控制方面具有更好的性能。我做了一些简单的代码,可能适合你。
对于适配器,以及绑定方法。
public class MyOwnBindingUtil {
public static class Holder extends RecyclerView.ViewHolder {
private ItemBinding mItemBinding;
public Holder(ItemBinding itemView) {
super(itemView.getRoot());
mItemBinding = itemView;
}
}
public static class OwnAdapter extends RecyclerView.Adapter<Holder> {
private Map<String, String> mMap;
private List<String> keys;
private List<Double> values;
public OwnAdapter() {
keys = new ArrayList<>();
values = new ArrayList<>();
}
public void add(String key, Double value) {
keys.add(key);
values.add(value);
}
@Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
ItemBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item, parent, false);
return new MyOwnBindingUtil.Holder(binding);
}
@Override
public void onBindViewHolder(Holder holder, int position) {
holder.mItemBinding.setKey(keys.get(position));
holder.mItemBinding.setValue(String.valueOf(values.get(position)));
}
@Override
public int getItemCount() {
return keys.size();
}
}
@BindingAdapter("data:map")
public static void bindMap(RecyclerView pRecyclerView, Map<String, Double> pStringStringMap) {
pRecyclerView.setLayoutManager(new LinearLayoutManager(pRecyclerView.getContext()));
OwnAdapter lAdapter = new OwnAdapter();
for (Map.Entry<String, Double> lStringStringEntry : pStringStringMap.entrySet()) {
lAdapter.add(lStringStringEntry.getKey(), lStringStringEntry.getValue());
}
pRecyclerView.setAdapter(lAdapter);
}
}
如果您坚持使用 Map 而不是列表作为数据,则会出现一些问题,因为 Map 没有索引,但是 适配器根据索引获取数据数据集.
https://www.mkyong.com/java8/java-8-convert-map-to-list/
How to convert a Map to List in Java?
How does one convert a HashMap to a List in Java?
在您的 xml 中,您可以将地图设置为 recyclerview,您的数据集可以在 xml 中设置。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:data="http://schemas.android.com/tools"
>
<data>
<import type="java.lang.String"/>
<import type="java.util.Map"/>
<variable
name="map"
type="Map<String, String>"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
data:map="@{map}"/>
</LinearLayout>
</layout>
在您的 activity 代码中,
Map<String, String> lStringStringMap = new HashMap<>();
lStringStringMap.put("A", "A1");
lStringStringMap.put("B", "B1");
lStringStringMap.put("C", "C1");
mBinding.setMap(lStringStringMap);
由于您更喜欢自己动态创建布局,我建议采用以下方法。目前这完全是理论上的,但我看不出为什么这不适合你。
考虑到您将 Map
设置为自定义绑定属性。
<LinearLayout ...
app:inflateData="@{dataMap}" />
然后您必须创建一个 @BindingAdapter
来处理适配器为您做的事情。
@BindingAdapter({"inflateData"})
public static void inflateData(LinearLayout layout, Map<String, Double> data) {
LayoutInflater inflater = LayoutInflater.from(layout.getContext());
for (Entry<String, Double> entry : data.entrySet()) {
MyItem myItem = inflater.inflate(R.layout.my_item, layout, true);
myItem.setKey(entry.getKey);
myItem.setValue(entry.getValue);
}
}
在这里,您为项目扩充布局并将其添加到父布局。您可以通过向布局和绑定适配器添加更多属性来进一步概括它。