#android #listview
Вопрос:
В моем понимании ListView загружает и отображает только видимые элементы, но в моем случае кажется, что он всегда отображает все элементы. Из-за этого требуется до 5 секунд (для ~150 записей), пока представление списка не станет видимым.
Logcat показывает:
I/OpenGLRenderer: Davey! duration=4740ms;
Если я не загружу изображения, это займет ~1 секунду. С моей точки зрения, тоже сильно притормозить.
Ограничив его 5 записями, список быстро расширяется…
Вот упрощенный код, который я использую.
listView = (ListView) view.findViewById(R.id.contact_list);
listView.setAdapter(new ContactAdapter(context, contacts));
ContactAdapter(Context context, List<Contact> contacts) {
this.contactList = contacts;
this.mInflater = LayoutInflater.from(context);
this.context = context;
}
public View getView(final int position, View convertView, final ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.contact_with_pic_ex, null);
holder = new ViewHolder();
holder.imgPicture = (ImageView) convertView.findViewById(R.id.picture);
holder.txtName = (TextView) convertView.findViewById(R.id.name);
holder.txtDate = (TextView) convertView.findViewById(R.id.date);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final Contact contact = contactList.get(position);
holder.imgPicture.setImageBitmap(getPhotoAsBitmap(contact.getID()));
holder.txtName.setText(contact.getName());
holder.txtDate.setText(contact.getDate());
return convertView;
}
private Bitmap getPhotoAsBitmap(final int ID) {
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, ID);
InputStream is = ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(), uri, true);
Bitmap bitmap;
if (is == null)
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.contour_dark);
else {
bitmap = BitmapFactory.decodeStream(input);
}
return bitmap;
}
Это занимает примерно одно и то же время, независимо от того, использую ли я кадры или миниатюры.
Не могли бы вы, пожалуйста, помочь мне сделать код быстрее.
Комментарии:
1. Я бы посоветовал вам использовать более новый
RecyclerView
вместоListView
.2. Самая большая проблема здесь в том, что вы не кэшировали ни одну из переменных. Ограничение до 5 и размещение журнала внутри
getView()
, чтобы сообщить вам, сколько раз он вызывается, — это один из способов. Включение и отключение представлений, используемыхposition
в качестве основы, может помочь. Но в конце концов, почему бы просто не использоватьRecyclerView
?3. Если RecyclerView ускорит его работу, я попробую это сделать.
Ответ №1:
Рендеринг выполняется медленно из BitmapFactory.decodeStream
-за того, что эта инструкция выполняется медленно, вам нужно выполнить обработку в фоновом потоке перед рендерингом.
это может быть что-то вроде этого:
private static class ContactLoader extends AsyncTask<Void, Void, List<Contact>> {
private final Context context;
public ContactLoader(Context context) {
this.context = context;
}
@Override
protected List<Contact> doInBackground(Void... voids) {
List<Contact> contacts = getContactListSomeWhere();
for(Contact contact : contacts) {
contact.setImageBitmap(getPhotoAsBitmap(contact.getID()))
}
return contacts;
}
@Override
protected void onPostExecute(List<Contact> contacts) {
super.onPostExecute(contacts);
// Render data to ListView
}
private Bitmap getPhotoAsBitmap(final int ID) {
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, ID);
InputStream is = ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(), uri, true);
Bitmap bitmap;
if (is == null)
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.contour_dark);
else {
bitmap = BitmapFactory.decodeStream(input);
}
return bitmap;
}
}
Комментарии:
1. Я не понимаю, как это должно помочь. Метод doInBackground также загружает последовательные изображения. onPostExecution вызывается после завершения doInBackground. Он также потребляет много памяти, потому что все изображения хранятся в списке контактов. Кстати, AsycTask не подходит для API 30 . Не могли бы вы объяснить, пожалуйста, как ваше решение должно помочь.