Какой самый быстрый способ добавить несколько представлений в LinearLayout?

У меня есть представление LinearLayout, которое уже содержит несколько элементов. Я хочу добавить к нему много общего. И поскольку это находится внутри ScrollView, все будет прокручиваться.

Итак, что я делаю, просматриваю мой список и добавляю в него новые экземпляры моего пользовательского представления. Это настраиваемое представление раздувает XML-макет и добавляет несколько методов.

Этот подход работает хорошо. Проблема в том, что он очень медленный, даже без сумасшедшего кода... список с 10 элементами занимает около 500 мс для создания экземпляра. В качестве точки зрения пользователя это трудно усвоить.

Мой вопрос в том, правильно ли это/лучший подход? Android, похоже, занимает много времени, раздувая макет, хотя "R.layout.my_list_item" очень прост. Интересно, есть ли способ, возможно, повторно использовать "завышенные" макеты для дополнительных просмотров, вроде кэширования более сложного разбора?

Я пробовал сделать это с помощью ListView (и адаптера и обертки), и это, кажется, намного быстрее. Проблема в том, что я не могу использовать простой ListView; мой макет более сложный, чем простой список (сам LinearLayout содержит дополнительные пользовательские значки, и у него есть еще один родитель с еще большим количеством представлений до того, как он обернут ScrollView).

Но есть ли способ использовать адаптер для LinearLayout? Будет ли это быстрее, чем пытаться самостоятельно добавлять представления?

Любая помощь приветствуется. Я бы хотел сделать это быстрее.

Далее следует код.

Основная деятельность:

// 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);
    }
}

То, что я пытаюсь сделать, это. Рассмотрим этот макет:

Basic layout

Этот макет представляет собой FrameLayout (внешнее поле), содержащее ImageView (серый), TextView (внутренний прямоугольник сверху) и LinearLayout (внутренний прямоугольник внизу). Этот прямоугольник LinearLayout является тем, который я динамически заполняю несколькими элементами.

После того, как я заполнил его, я хочу, чтобы конечный результат был таким (где каждый новый прямоугольник является новым экземпляром MyListItem):

Populated layout

То есть все прокручивается (фоновое изображение, например, выравнивается сверху). LinearLayout не прокручивается сам по себе (все остальное следует), поэтому почему ListView, из того, что я знаю, не будет работать очень хорошо в моем случае.

Ответы

Ответ 1

3 Опции:

  • Замените все на ListView, а другие родительские и пользовательские значки - в виде заголовка для ListView. ListView работает быстрее, поскольку он только создает Views по мере необходимости.

  • Программно создайте содержимое my_list_item вместо раздувания, возможно, быстрее

  • Использование ViewStubs может позволить вам загружать представления по требованию.

  • Возможно, это не загрузка представлений, а данных? в этом случае подготовьте данные в фоновом потоке.

Ответ 2

A ListView - путь.

Вы говорите, что ваш макет слишком сложный. Но вполне нормально раздувать сложный макет в детстве. Например, макет, который имеет текст, а затем значок:

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

Может быть раздуто в вашем адаптере так:

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    LinearLayout root = null;
    ImageView editImageView;

    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        root = (LinearLayout)inflater.inflate(R.layout.item, null);
    } else {
        root = (LinearLayout)convertView;
    }
}

Вы также можете быть немного умнее, чтобы поддерживать заголовок. Просто добавьте проверку, если индекс является корнем и раздувает другое представление. Поскольку заголовок является единственным, который отличается, вы все равно будете использовать все остальные строки, которые можно использовать повторно. Вы даже можете предварительно раздуть и сохранить заголовок и повторно использовать его, чтобы полностью избавиться от инфляции.

Ответ 3

Просто используйте ListView!

Это проще всего настроить и упростить. Вы определяете XML-макет для List-Row и XML-макет для представления, который содержит весь список. ListAdapter делает все остальное для вас.

Просто создайте a:

List<HashMap<String, String>> services = new ArrayList<HashMap<String, String>>();

... и прокрутите свои данные, чтобы добавить столько элементов, сколько вам нравится на карте. Затем установите эту карту в свой список. Будь то 10 элементов или 100 элементов, ListAdapter создаст список с таким количеством элементов.

Пример:

    public void updateProductList(String searchTerm) {
        createOrOpenDB(this);
        Cursor cursor = (searchTerm!=null)? dbAdapter.fetchWhere(TBL_NAME, KEY_NAME+" LIKE '%"+searchTerm+"%'")
                : dbAdapter.fetchAll(TBL_NAME);
        int rows = cursor.getCount();
        if (rows<=0) return;
        services.clear(); //clear current list
        for (int i=0; i<rows; i++) {
            HashMap<String, String> map = new HashMap<String, String>();
            cursor.moveToPosition(i);
            map.put(KEY_NAME, "" + cursor.getString(cursor.getColumnIndex(KEY_NAME)));
            map.put(KEY_DESC, "" + cursor.getString(cursor.getColumnIndex(KEY_DESC)));
            map.put(KEY_COST, "" + cursor.getDouble(cursor.getColumnIndex(KEY_COST)));
            services.add(map);
        }
        cursor.close();
        closeDB();

        ListAdapter adapter = new SimpleAdapter(this, services, R.layout.products_view_row,
                new String[] {KEY_NAME, KEY_DESC, KEY_COST},
                new int[] {R.id.listViewText1, R.id.listViewText2, R.id.listViewText3});
        setListAdapter(adapter);
    }