Skip to content
Advertisement

How to make Views iterating on data objects (without ListView / RecyclerView)?

I am trying to spawn some XML view for each instance of POJO data objects in a list, similar to how a ListView would do it, but it’s not a ListView actually, but an empty LinearLayout instead, which is inside a ScrollView below other Fragment‘s content.

This is the item.xml file I want to inflate for each element of the list:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/item_label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="0dp"
        android:text="ITEM_LABEL"
        android:textSize="16sp" />

    <TextView
        android:id="@+id/item_text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="4dp"
        android:text="ITEM_TEXT_1"
        android:textSize="14sp" />

    <TextView
        android:id="@+id/item_text2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="4dp"
        android:text="ITEM_TEXT_2"
        android:textSize="14sp" />
</LinearLayout>

…and this is the way I am trying to inflate it in the Fragment Java class:

public class MyFragment extends Fragment {
    // we skip the "boilerplate"...
    // [...]
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                        Bundle savedInstanceState) {
       // Inflate the layout for this fragment
       View view = inflater.inflate(R.layout.my_fragment, container, false);

       // XXX  I use LiveData<> with Room to retrieve
       //     rows from DB inside POJO objects
       LiveData<List<MyItem>> items_list = itemsViewModel.getItemsByParentId(some_id);
       //  The "parent" is not relevant, let's just
       // focus on the List
       LinearLayout items_list_layout = view.findViewById(R.id.items_list_layout);

       items_list.observe(getActivity(), new Observer<List<MyItem>>() {
           @Override
           public void onChanged(List<MyItem> items) {
               // Just in case, (maybe I'm wrong but) I think otherwise
               // previous inflated objects remain on loading this same
               // fragment for another parent
               objs_list_layout.removeAllViews()
               for (MyItem item : items) {
                   // XXX Here I inflate item.xml as a LinearLayout
                   LinearLayout obj_item = (LinearLayout) View.inflate(view.getContext(), R.layout.item, items_list_layout);
                   // XXX ... and try to change it's TextView children
                   TextView item_label = obj_item.findViewById(R.id.item_label);
                   item_label.setText(item.item_label);
                   TextView item_text1 = obj_item.findViewById(R.id.item_text1);
                   item_text1.setText(item.item_text1);
                   TextView item_text2 = obj_item.findViewById(R.id.item_text2);
                   item_text2.setText(item.item_text2);
               }
           }
       });
    }
}

This works well when the method getItemsByParentId only return a List with one only MyItem instance. But when the query returns more than one Item, it works unexpectedly wrong:

  • The first inflated item.xml element (or the one shown first, on top) has its TextViews modificated as expected, but for the last item in the list.
  • The rest of “inflated elements” have not been changed (it shows just ITEM_LABEL, ITEM_TEXT1 and ITEM_TEXT2 hardcoded strings as they are in the template XML file).
  • However, it inflates the XML template items.size() times as I planned.

Actually, the objective is that each “inflated item.xml” is edited with attributes of each corresponding Item. Just like a ListView would do, but without using ListView at all, because the goal is, actually, bloating an existing ScrollView (the main container in the fragment) that shows other different Views outside of the “LinearLayout” dedicated to generate this “list”. How can I make it work without these errors?

Advertisement

Answer

View.inflate imho is a not the clearest method ) it returns the root View of the inflated hierarchy. If root was supplied, this is the root View; otherwise it is the root of the inflated XML file.

So obj_item is not an item view. It is an items_list_layout view. Inside it you find R.id.item_label in first item view and set it. Other item views are not initialized because findViewById returns first item it found.

Change this part:

LinearLayout obj_item = (LinearLayout) View.inflate(view.getContext(), R.layout.item, items_list_layout);

to

LinearLayout obj_item = LayoutInflator.from(view.getContext()).inflate(R.layout.item, items_list_layout, false);

I prefer to add child views explicitly to make code more readable. So and add this code to add item view to parent layout:

items_list_layout.addView(obj_item)
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement