Как мне перенести свой образ загрузчика в отдельную нить на Android?
-
24-09-2019 - |
Вопрос
У меня есть следующий код, работающий на моем устройстве Android. Он отлично работает и отлично отображает свои предметы списка. Это также умно в том, что он загружает только данные, когда он нужен arrayAdapter. Однако, в то время как загрузка миниатюр происходит, весь список пробивает, и вы не можете прокрутить до тех пор, пока не завершит загрузку. Есть ли способ нарезать это так, чтобы он еще радостно прокручивался, возможно, покажет место держателя для загрузки изображения, закончите загрузку, а затем показать?
Я думаю, что мне просто нужно поставить свой класс DownloadImage в собственную нить, поэтому его выполняется отдельно от интерфейса UI. Но как добавить это в мой код, это тайна!
Любая помощь с этим была бы очень ценится.
private class CatalogAdapter extends ArrayAdapter<SingleQueueResult> {
private ArrayList<SingleQueueResult> items;
//Must research what this actually does!
public CatalogAdapter(Context context, int textViewResourceId, ArrayList<SingleQueueResult> items) {
super(context, textViewResourceId, items);
this.items = items;
}
/** This overrides the getview of the ArrayAdapter. It should send back our new custom rows for the list */
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.mylists_rows, null);
}
final SingleQueueResult result = items.get(position);
// Sets the text inside the rows as they are scrolled by!
if (result != null) {
TextView title = (TextView)v.findViewById(R.id.mylist_title);
TextView format = (TextView)v.findViewById(R.id.mylist_format);
title.setText(result.getTitle());
format.setText(result.getThumbnail());
// Download Images
ImageView myImageView = (ImageView)v.findViewById(R.id.mylist_thumbnail);
downloadImage(result.getThumbnail(), myImageView);
}
return v;
}
}
// This should run in a seperate thread
public void downloadImage(String imageUrl, ImageView myImageView) {
try {
url = new URL(imageUrl);
URLConnection conn = url.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
Bitmap bm = BitmapFactory.decodeStream(bis);
bis.close();
is.close();
myImageView.setImageBitmap(bm);
} catch (IOException e) {
/* Reset to Default image on any error. */
//this.myImageView.setImageDrawable(getResources().getDrawable(R.drawable.default));
}
}
Решение
Вот упрощенная версия того, что я использую в моих приложениях:
// this lives in Application subclass and is reused
public static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor();
// the method itself
public void attachImage(final String fileUrl, final ImageView view) {
EXECUTOR.execute(new Runnable() {
@Override
public void run() {
final Drawable image = methodThatGetsTheImage(fileUrl);
if (image != null) {
view.post(new Runnable() {
@Override
public void run() {
view.setImageDrawable(drawable);
}
});
}
}
});
}
Другие советы
Вы также можете проверить CWAC-миниатюр Для распаданного раствора (хотя он имеет немного накладки, чем более простые решения выше). Я использовал его с большим успехом в целом где у меня есть веб-изображение для скачивания; Вы в основном настроили некоторые глобальные варианты кэширования для вашего приложения, а затем просто оберните свой listadapter в миниатюре со списком Android: ID IDSViews в вашем списке и вызовите Settag (ImageURL) на ImageViews в методе GetView вашего адаптера, а также Это обрабатывает остальные.
да. Вам следует избегать работать на бите UI как можно больше. Когда вы в GetView (), вы находитесь в потоке пользовательского интерфейса. Вырваться сделать это:
new Thread(new Runnable(){
public void run() {
// your code here
}}).start();
Тогда, когда вам нужно изменить вид, каким-то образом вернитесь на пользовательскую резьбу, как это:
runOnUiThread(new Runnable(){
public void run() {
// your view-modifying code here
}});
.. или используйте механизм View.post ().
В вашем примере произойдет то, что элемент будет отображаться на экране до того, как изображение будет доступно для отображения. Я предлагаю использовать «загрузку» спиннера или какой-то другой заполнитель, чтобы указать пользователю, что происходит.
Вы можете на практике, как это несколько раз, хотя вы достигнете момента, где упрощенный дизайн находится в порядке. Анонимные классы могут быть неэффективными памятью и стрельбой от множества нитей без механизма отмены могут иметь свои собственные недостатки.
Вы можете испытывать некоторые трудности в качестве побочного эффекта изменения мнения после GetView (). Некоторые взгляды могут понадобиться Invernate (), призванный, чтобы их изменения вступили в силу. Также остерегайтесь, если вы перерабатываете представления в вашем GetView (), вы должны убедиться, что к тому времени, когда ваш код изменений в просмотр выполняется, что представление все еще используется для содержимого, которое вы применяете. Settag () / GetTag () полезен здесь для хранения некоторых идентификаторов данных, которые вы можете позже проверить, чтобы убедиться, что ваш вид не был переработан.