What's the quickest way to add several views to a LinearLayout?

zeh picture zeh · Dec 16, 2011 · Viewed 7.1k times · Source

I have a LinearLayout view that already contains several elements. I want to add a lot more Views to it, programmatically. And because this is inside a ScrollView, everything will be scrolled.

So what I do is go through my list, and add new instances of my custom View to it. That custom view inflates a XML layout and adds a few methods.

This approach works well. The problem is that it's super slow, even without any crazy code... a list with 10 items takes around 500ms to instantiate. As an user experience standpoint, this is hard to swallow.

My question is, is this the correct/best approach? Android seems to take a lot of time inflating the layout, even though "R.layout.my_list_item" is super simple. I wonder if there's a way to maybe to reuse "inflated" layouts for additional views, kinda caching the more complex parsing?

I've tried doing this with a ListView (and adapter and a wrapper) and it seems to be much faster. The problem is that I can't use a simple ListView; my layout is more complex than a simple list (the LinearLayout itself contains additional custom icons, and it has another parent with even more Views before it's wrapped by the ScrollView).

But is there a way to use an adapter for a LinearLayout? Would that be faster than trying to add the views myself?

Any help is appreciated. I'd love to make this faster.

Code follows.

Main Activity:

// The LinearLayout that will contain everything
lineList = (LinearLayout) findViewById(R.id.lineList);

// Add a lot of items for testing
for (int i = 0; i < 10; i++) {
    addListItem("Item number " + i);
}

protected void addListItem(String __title) {
    MyListItem li;
    li = new MyListItem(this);
    li.setTitle(__title);
    lineList.addView(li);       
}

MyListItem:

public class MyListItem extends RelativeLayout {

    protected TextView textTitle;

    public MyListItem(Context __context) {
        super(__context);
        init();
    }

    public MyListItem(Context __context, AttributeSet __attrs) {
        super(__context, __attrs);
        init();
    }

    public MyListItem(Context __context, AttributeSet __attrs, int __attrsdefStyle) {
        super(__context, __attrs, __attrsdefStyle);
        init();
    }

    protected void init() {
        // Inflate the XML layout
        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.my_list_item, this);

        // Create references
        textTitle = (TextView)findViewById(R.id.textTitle);
    }

    public void setTitle(String __text) {
        textTitle.setText(__text);
    }
}

What I'm trying to accomplish is this. Consider this layout:

Basic layout

This layout is a FrameLayout (outer box) containing a ImageView (in gray), a TextView (inner rectangle, on top) and a LinearLayout (inner rectangle, on bottom). This LinearLayout rectangle is the one I'm dynamically populating with a few items.

After I populate it, I want the final result to be this (where every new rectangle is a new MyListItem instance):

Populated layout

That is, everything is scrollable (the background image, for example, is aligned on top). The LinearLayout isn't scrollable by itself (everything else follows) hence why a ListView, from what I know, wouldn't work very well in my case.

Answer

FunkTheMonk picture FunkTheMonk · Dec 16, 2011

3 Options:

  1. Replace everything with a ListView, with the other parent and custom icons as a header view for the ListView. ListView is faster, because it only creates Views as it needs them.

  2. Programatically create the contents of my_list_item instead of inflating, might be quicker

  3. Use of ViewStubs may allow you to load views on-demand.

  4. Maybe it isn't loading the views but the data? in which case prepare the data in a background thread.