Какой самый быстрый способ добавить несколько представлений в 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);
}