3

i want to reuse an inflated view just the same way a listView adapter does with convertView. Ive been lurking on the source code of adapters with no luck.

I need to add dinamically views depending on data to a recyclerItemView, now im inflating as much times as i need the view but having in mind its inside a recyclerView, this operation could become absurdly costly depending on the amount of data and scrolling behaviour of the user.

Other solution to my problem would be to create a listview inside the recyclerItem, so the listview wouldnt be scrollable, expands to maximum height depending on data added dynamically(making the listview container to expand to show all its data) and make the recyclerItem expand depending on its height.

ACTIVITY

public class Main1Activity extends AppCompatActivity {

    RecyclerView recyclerView;
    CustomAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main1);
        recyclerView = (RecyclerView) findViewById(R.id.recycler);
        setUpRecycler();
    }

    private void setUpRecycler(){
        Sample sample1 = new Sample("List of Items1");
        Sample sample2 = new Sample("List of Items2");
        Sample sample3 = new Sample("List of Items3");
        List<Sample> sampleList = new ArrayList<>();
        sampleList.add(sample1);
        sampleList.add(sample2);
        sampleList.add(sample3);

        adapter = new CustomAdapter(this,sampleList);
        recyclerView.setAdapter(adapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
    }
}

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="30dp">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </android.support.v7.widget.RecyclerView>

</RelativeLayout>

MODEL

public class Sample {

    String name;

    public Sample(){}

    public Sample(String name) {
         this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

XML ITEMS

**item_list**

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

<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

</LinearLayout>

**item_smaple**

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

<TextView
    android:id="@+id/name"
    android:layout_width="120dp"
    android:layout_height="40dp"
    android:layout_margin="10dp"
    android:text="List of Items"
    android:textSize="20sp"/>

<LinearLayout
    android:id="@+id/linearLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="30dp"
    android:orientation="vertical"/>

</LinearLayout>

ADAPTER

public class CustomAdapter extends   RecyclerView.Adapter<CustomAdapter.ViewHolder> {

private List<Sample> mySamples;
private Context mContext;

public CustomAdapter(Context context, List<Sample> mySamples) {
    this.mContext = context;
    this.mySamples = mySamples;
}

private Context getContext() {
    return mContext;
}

public static class ViewHolder extends RecyclerView.ViewHolder {

    public TextView name;
    public LinearLayout linearLayout;

    public ViewHolder(View itemView) {
        super(itemView);
        name = (TextView) itemView.findViewById(R.id.name);
        linearLayout = (LinearLayout) itemView.findViewById(R.id.linearLayout);
    }
}

@Override
public CustomAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    Context context = parent.getContext();
    LayoutInflater inflater = LayoutInflater.from(context);
    View contactView = inflater.inflate(R.layout.item_sample, parent, false);
    ViewHolder viewHolder = new ViewHolder(contactView);
    return viewHolder;
}

@Override
public void onBindViewHolder(CustomAdapter.ViewHolder holder, int position) {
    Sample sample = mySamples.get(position);

    holder.name.setText(sample.getName());

    LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View v = inflater.inflate(R.layout.item_list, null, false);
    for (int i = 0; i < 20; i++){
        TextView textView = (TextView) v.findViewById(R.id.textView);
        textView.setText("hello"+i);
        holder.linearLayout.addView(v);
    }
}

@Override
public int getItemCount() {
    return mySamples.size();
}
}

Right now i´m inflating inside the loop. How could i modify view parameters to make it reusable to the framework?

My app crashes on the addView() -->java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

marcos E.
  • 477
  • 4
  • 11
  • so what's the problem with using a RecyclerView? – lelloman Aug 31 '16 at 14:35
  • My problem is that i want to inflate a complex layout and add it to linearlayout with addView(), so if the recycler-item need to inflate 4-5 of this layout inside the linearLayout, **this could slow or even freeze the scroll on the recyclerview**; because the inflate operation will execute tons of times as the recycler items populate and empty the views, and _inflate its a costly operation that list Widgets avoid to repeat if possible_. Right now i will be doing it 2-3 times per recycler row easily. – marcos E. Sep 01 '16 at 07:41
  • yeah, inflating views it's a costly operation that's why they made ListView/RecyclerView so that it won't inflate the views every time but it will reuse them and just bind the data – lelloman Sep 01 '16 at 07:52
  • if u read the third pharagraph u can see i thought about it already, but ive investigated about a listview that behaves like i need with no luck, so i thought of inflating views on my own,If u know how to create a listview like i need (3 paragraph) just create an answer so i can check it as correct if so, thanks for ur time :) – marcos E. Sep 02 '16 at 07:18

2 Answers2

0

The issue that you are referring to is the one which was addressed by creating RecyclerView which is an upgrade to ListView. What RecyclerView does is that it will create/inflate say 5-10 list item and when the user starts scrolling new listItem view(s) are not inflated infact just the data is updated inside the listItem.

This is a great explainer video of how recycler view actually works with a bit of code as well. https://www.youtube.com/watch?v=Wq2o4EbM74k

I hope this clears your doubt regarding the inflation issue.

Gaurav Sarma
  • 2,248
  • 2
  • 24
  • 45
0

My app crashes on the addView() -->java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

try:

@Override
public void onBindViewHolder(CustomAdapter.ViewHolder holder, int position) {
    Sample sample = mySamples.get(position);

    holder.name.setText(sample.getName());
    LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context
            .LAYOUT_INFLATER_SERVICE);

    for (int i = 0; i < 20; i++) {
        View v = inflater.inflate(R.layout.item_list, holder.linearLayout, false);
        TextView textView = (TextView) v.findViewById(R.id.textView);
        textView.setText("hello" + i);
        holder.linearLayout.addView(v);
    }
}

itemSample.xml

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

<TextView
    android:id="@+id/name"
    android:layout_width="wrap_content"
    android:layout_height="40dp"
    android:layout_margin="10dp"
    android:text="List of Items"
    android:textSize="20sp"/>

<LinearLayout
    android:id="@+id/linearLayout"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:layout_marginLeft="30dp"
    android:orientation="vertical"
    android:isScrollContainer="true"
    />

</LinearLayout>

itemList.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="40dp"
  android:isScrollContainer="true"
  android:id="@+id/txt_cont"
  >

 <TextView
  android:id="@+id/textView"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"/>
</LinearLayout>

Just Raw Solution

You should try answer @

Community
  • 1
  • 1
Johnny
  • 282
  • 1
  • 15
  • The code i want is **doing the inflating operation only once for all the views**, if u read the comments on my question you will see i discuss how bad the performance of the code uve posted here could be, thanks for ur time but this isnt what im looking for.(Indeed my code is working exactly as the one you posted till i figure something out :P) – marcos E. Sep 05 '16 at 07:39