35

I have a LinearLayout with vertical orientation as parent, I want to add some view programmatically multiple times to this parent. Right now I am inflating the child every time getting new references to every UI element before adding to parent. This doesn't seem to be very efficient, is there any better way of doing this.

Current code I am using is below, If I inflate only once before for loop I get runtime error "he specified child already has a parent. You must call removeView() on the child's parent first."

        LayoutInflater inflator = LayoutInflater.from(getBaseContext());
        LinearLayout parentPanel = findViewById(R.id.parent_pannel);

        ArrayList<String> myList = getData();
        for(String data : myList) {
            // inflate child
            View item = inflator.inflate(R.layout.list_item, null);
            // initialize review UI
            TextView dataText = (TextView) item.findViewById(R.id.data);
            // set data
            dataText.setText(data);
            // add child
            parentPanel.addView(item);
        }
mkso
  • 3,178
  • 4
  • 27
  • 35
  • I agree, it would be sweet if there was an easy way to "clone" views, but I have yet to find it. Inflating over and over it is. However, I have to say that from your code snippet, it would seem to me that you'd want to use a `ListView`. – dmon Jun 22 '11 at 14:39
  • I'm afraid this is by design. You can't have multiple parents for one view, as well as add same view to the parent multiple times. It would be quite hard to write bug-free code for ViewGroups (and similar scenarios) if this was not so. – inazaruk Jun 22 '11 at 14:41
  • @dmon I did not design my layout to use ListView because it would have make the code more complex because the way I want every thing to be layed out. I guess for efficiency I have to move everything to ListView. – mkso Jun 22 '11 at 14:54
  • 1
    The reason I point this out is that `ListView` recycles Views for this same reason. Since you only see N views at a time it only inflates those that are necessary, and then just reuses them. Something to consider if you see yourself adding quite a bit of views. – dmon Jun 22 '11 at 15:02
  • Views in most case won't be more then 10, so using ListView would not necessarily improve performance by that much. – mkso Jun 22 '11 at 15:08
  • Move to ListView Only. You can draw every possible view using that. The code you are trying you will have to inflate each time a new view to add it successfully. – Rohit Sharma Jun 22 '11 at 15:08
  • 3
    I would have thought that inflating same xml layout multiple times actually creates separate objects but of the same structure. Why the h.ll would that not be possible? By the way, a ListView is not always an option: say you have everything in a ScrollView - you cannot have a ListView in a ScrollView. Inflating layouts from xml would be great in such case. – Yar Nov 15 '11 at 17:06

4 Answers4

28

Did you actually check if inflate is slow? As far as I know, inflating view is very fast (almost as fast as creating views manually).

It might be surprising for you to hear but inflate in fact does not parse the XMLs at all. XMLs for layout are parsed and pre-processed at compile time - they are stored in a binary form which makes view inflation very efficient (that's why you cannot inflate a view from an XML generated at runtime).

Jarek Potiuk
  • 19,317
  • 2
  • 60
  • 61
  • 3
    https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/view/LayoutInflater.java line 424 – Teodor Jan 23 '13 at 15:33
  • I don't agree on that, during my activities or fragments creations, the XML inflation is always what requires the longest time, that's why I try to keep the layout structure as simple as possible. – Yoann Hercouet Jun 23 '16 at 10:01
  • 1
    My point is that If you have many-level-nested layout, it will be slow regardless if it's done by hand or by inflation. So I agree you should keep the layout as simple as possible (and preferably after latest Google I/O 16 we will all soon move to much simpler/less nested Constrained Layouts). My only point was that there is no XML parsing involved, so parsing is not a problem. – Jarek Potiuk Jun 24 '16 at 11:12
  • @JarekPotiuk Thanks for the clarification! – Yoann Hercouet Jun 25 '16 at 20:55
5

You can't, even if you try to create a new view from the old view object the object will be passed by reference not value, and hence you will got an Exception as the childAlreadyHasParent, and so, the only way is to put the view into a for loop with the number of times you want it to be inflated, and this loop must contain the creating process from beginning not only the inflating lines.

Muhammed Refaat
  • 8,914
  • 14
  • 83
  • 118
5

I'm not sure what your view is but have you creating it manually over inflating the XML:

   ArrayList<String> myList = getData();
    for(String data : myList) {

        LinearLayout layout = new LinearLayout(this);
        layout.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,             LayoutParams.WRAP_CONTENT));
        TextView textView = new TextView(this);
        textView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));

        textView.setText(data);

        layout.addChild(textView);         

        parentPanel.addView(layout);
    }

But yeah your clearly attempting something that has been done for you with Simple ListView & API

Blundell
  • 75,855
  • 30
  • 208
  • 233
4

Inflating multiple times cannot be done the same way doing it in single shot. Hope this works

LayoutInflater inflator = (LayoutInflater).getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    LinearLayout parentPanel = findViewById(R.id.parent_pannel);

    ArrayList<String> myList = getData();
    for(String data : myList) {
        // inflate child
        View item = inflator.inflate(R.layout.list_item, null);
        // initialize review UI
        TextView dataText = (TextView) item.findViewById(R.id.data);
        // set data
        dataText.setText(data);
        // add child
        parentPanel.addView(item);
    }

This will work, at the least worked me

Sidharth
  • 41
  • 1
  • Worked for me as well with View v = inflater.inflate(R.layout.list_item, parent, false) followed later by calling addView(v). Looks like inflate(...) might have an optimization to not attach if its already there. – Pete Doyle Jul 17 '13 at 21:32
  • can you suggest me something if i have to add dynamically view same as above inside a recycler view row – Vivek Pratap Singh Jun 28 '16 at 12:49