Какой самый быстрый способ добавить несколько представлений в LinearLayout? - PullRequest
16 голосов
/ 17 декабря 2011

У меня есть 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, насколько я знаю, не будет работать очень хорошо в моем случае.

Ответы [ 3 ]

7 голосов
/ 17 декабря 2011

3 варианта:

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

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

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

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

2 голосов
/ 17 декабря 2011

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

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

1 голос
/ 17 декабря 2011

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

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

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

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

... и переберите свои данные, чтобы добавить на карту столько элементов, сколько вам нужно. Затем установите эту карту в свой ListAdapter. Будь то 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);
    }
...