动态添加元素的数据绑定
Posted
技术标签:
【中文标题】动态添加元素的数据绑定【英文标题】:Data-binding with dynamically added elements 【发布时间】:2017-01-12 13:24:06 【问题描述】:我已经开始在我的新应用中实现 android 数据绑定库。但是,我在使用数据动态添加元素时遇到了一些困难。在我的POJO
中,它包含<String,Double>
的地图。这里,String
是用户的 id,Double
是数量。我有一个用于显示单个条目的布局文件。因此,如果 map 包含 2 个元素,它将如下所示:
以前,我通过在循环内膨胀布局并为地图的每个项目添加到LinearLayout
来做到这一点。但是,现在我想通过数据绑定来做到这一点。
由于Map
中的元素个数可以是1 到20 之间的任意值,我默认不能在布局文件中添加。我必须根据地图中的条目充气。我已经成功实现了与POJO
的数据绑定,而没有Map
。但是,无法理解如何通过数据绑定轻松做到这一点。
那么,有没有办法直接在数据绑定中(在布局文件中)或在 java 代码中使用尽可能少的代码?
编辑:
对于所有人来说,谁看到它是一个简单的RecyclerView
,它不是。我同意RecyclerView
是一个非常好的选择,当你有一个包含一些元素的列表并且滚动视图将提高性能时。在这里,我在此列表上方和下方有多个不同类型的元素。我也将RecyclerView
与数据绑定一起使用,并且我知道它是如何工作的,但这里并非如此。我只想使用数据绑定在布局 (LinearLayout) 中填充多行。
【问题讨论】:
你试过RecyclerView
吗?
我不需要 RecyclerView,大多数时候最多有 5-7 个元素。 RecyclerView 在有很多滚动元素时会很有用
在你说的1到20的问题中。如果以防万一,元素数量增加到> 7,为了安全起见,我建议使用RecyclerView
。您的绑定问题也将得到解决。如果您以编程方式添加LinearLayout
中的所有元素,并且在屏幕旋转时,您必须滚动才能看到所有元素,这将导致此处出现内存问题。
当然你应该使用RecyclerView
【参考方案1】:
由于您更喜欢自己动态创建布局,我建议采用以下方法。目前这完全是理论上的,但我看不出为什么这不适合你。
考虑到您使用自定义属性设置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);
在这里,您为项目扩展布局并将其添加到父布局。您可以通过向布局和绑定适配器添加更多属性来进一步概括它。
【讨论】:
太棒了!这应该有效。我要试一试。谢谢! 如何将 myItem 添加到父布局?我知道 addView() 方法,但问题是如何访问父布局以调用 addView() 方法? 嗨,它的答案非常好,但我有一些疑问 inflate 返回视图的对象,我无法找到 setKey 和 setValue 方法,例如:myItem.setKey【参考方案2】:这不是数据绑定的用途。这些用于将数据绑定到静态定义的布局。创建或管理视图层次结构可能是可能的,但也比仅使用 RecyclerView
及其适配器复杂得多。
如果您更喜欢只设置布局中的数据,您可以为数据绑定库编写Custom Setters,并在此范围内创建适配器。
@BindingAdapter("adapter")
public static void bindAdapter(RecyclerView view, Map<String, Double> data)
RecyclerView.Adapter adapter = ...;
view.setAdapter(adapter);
【讨论】:
是的,我知道它用于静态定义的布局。在我的布局中,我使用数据绑定在这个小列表的上方和下方绑定了许多属性。但是,就这一部分我被卡住了。并没有找到任何方法。但是,我认为这里不需要回收站视图。【参考方案3】:要以动态方式添加/删除数据,您应该使用Adapter
而不是使用您的方式添加它。正如谷歌建议的那样,RecycelerView
在 UI 和内存控制方面有更好的表现。我已经编写了一些可能适合您的简单代码。
对于Adapter,以及绑定方法。
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 没有索引,但 适配器会根据数据集的索引获取 Data .
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_
android:layout_
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_
android:layout_
data:map="@map"/>
</LinearLayout>
</layout>
在您的活动代码中,
Map<String, String> lStringStringMap = new HashMap<>();
lStringStringMap.put("A", "A1");
lStringStringMap.put("B", "B1");
lStringStringMap.put("C", "C1");
mBinding.setMap(lStringStringMap);
【讨论】:
感谢您的建议。我同意 RecyclerView 是一个非常好的选择,当你有一个包含一些元素的列表并且滚动视图将提高性能时。但是,在这里使用 RecyclerView 并不是一个好的选择,因为我想要一些视图(通常在 5-7 左右)与此列表上方和下方的许多不同视图内联。我已经将数据绑定与回收器视图一起使用,它工作得很好。但在这里,它不是必需的。 这意味着你有 binding1,binding2,binding3... 但不超过 7 个。而 7 个绑定(如果是 7 )是完全不同的布局。您想将其添加到单个容器中(可能是 LinearLayout)。现在您想找到一种更简单的方法来在单个容器内添加 7 种不同的布局,而不是使用数据绑定逐个添加? 不,不是那样的。让我解释。假设我有一个包含这么多元素的 POJO:标题、描述、所有者、created_at、created_by、modified_at、modified_by、图标、类别、标签、位置、参与者。所以,有了这个 POJO 和数据绑定,我可以轻松设置所有内容。但是,“参与者”部分是一张棘手的地图。对于那张地图,我想为每个地图显示一个相当小的行。【参考方案4】:这实际上是对已接受答案的查询。我没有足够的声誉来添加评论。 答案中的“MyItem”是什么?是不是布局的data标签中定义的变量?
【讨论】:
以上是关于动态添加元素的数据绑定的主要内容,如果未能解决你的问题,请参考以下文章