I have started implementing Android data-binding library to my new app. But, I am having some difficulties with data dynamically added elements. In my POJO
it contains a map of <String,Double>
. Here, String
is the id of a user and Double
is the amount. I have a layout file for displaying single entry. So, if map contains 2 elements, it will looks like this:
Previously, I have done this by inflating layouts inside loop and adding to LinearLayout
for each item of a map. But, now I want to do this with data-binding.
As, the number of elements in the Map
can be anything from 1 to 20, I can not add in the layout file by default. I have to inflate as per the entries in the map. I have successfully implemented data-binding with the POJO
without a Map
. But, unable to understand how this can be done with data-binding easily.
So, Is there any way to do this directly in the data binding (in layout file) or with as little code possible in java code?
Edit:
For all, who sees that it is a simple RecyclerView
, it is not. I agree RecyclerView
is very good choice when you have a list with some elements and scrolling that views will be performance benefit. Here I have multiple elements of different types above and below this list. I have used RecyclerView
with data-binding also and I know how it works, but here it is not the case. I just want to inflate multiple rows inside a layout (LinearLayout) using data-binding.
Since you prefer to create the layout dynamically yourself, I'd propose the following approach. It's completely theoretical at the moment, but I don't see a reason, why this should not work for you.
Considering you set the Map
with a custom attribute for binding.
<LinearLayout ...
app:inflateData="@{dataMap}" />
You then have to create a @BindingAdapter
to handle what the adapter would do for you.
@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);
}
}
Here you inflate the layout for the item and add it to the parent layout. You could generalize it even more by adding more attributes to the layout and binding adapter.
To make the data to be added/removed in dynamic way, you should use the Adapter
instead of add it using your way. As google suggested, RecycelerView
have better performance in UI and memory control. I have made some simple code which might suit to you.
For the Adapter, and the binding method.
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);
}
}
There is some problem if you insist to use Map instead of list for the data since Map is not indexed but the adapter gets Data based on the index of the dataset.
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?
In your xml, you can set your map to the recyclerview and your dataset can be set in 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>
In your activity code,
Map<String, String> lStringStringMap = new HashMap<>();
lStringStringMap.put("A", "A1");
lStringStringMap.put("B", "B1");
lStringStringMap.put("C", "C1");
mBinding.setMap(lStringStringMap);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With