Как мне перенести свой образ загрузчика в отдельную нить на Android?

StackOverflow https://stackoverflow.com/questions/2578439

Вопрос

У меня есть следующий код, работающий на моем устройстве 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 () полезен здесь для хранения некоторых идентификаторов данных, которые вы можете позже проверить, чтобы убедиться, что ваш вид не был переработан.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top