Как переместить загрузчик изображений в отдельную ветку на Android? - PullRequest
2 голосов
/ 05 апреля 2010

На моем устройстве Android работает следующий код. Он прекрасно работает и отображает мои элементы списка чудесно. Он также умен в том, что он загружает данные только тогда, когда это необходимо для ArrayAdapter. Однако, пока происходит загрузка миниатюры, весь список останавливается, и вы не можете прокрутить, пока не закончится загрузка. Есть ли какой-нибудь способ проделать это, так что он все равно будет счастливо прокручиваться, может быть, покажет заполнитель для загружаемого изображения, завершит загрузку, а затем покажет?

Я думаю, мне просто нужно поместить свой класс downloadImage в его собственный поток, чтобы он выполнялся отдельно от пользовательского интерфейса. Но как добавить это в мой код - загадка!

Любая помощь с этим была бы очень признательна.

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

Ответы [ 3 ]

4 голосов
/ 05 апреля 2010

Вот упрощенная версия того, что я использую в своих приложениях:

// 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);
                        }
                    });
                }
            }
        });
    }
1 голос
/ 05 апреля 2010

Вы также можете проверить cwac-thumbnail , чтобы найти раскрывающееся решение (хотя оно имеет немного больше накладных расходов, чем простые решения выше).Я использовал его с большим успехом почти везде, где у меня есть веб-изображение для загрузки;вы в основном настраиваете некоторые глобальные параметры кэширования для своего приложения, затем просто оборачиваете свой ListAdapter в ThumbnailAdapter со списком android: идентификаторы изображений в вашем списке и вызываете setTag (imageUrl) для изображений в методе getView вашего адаптера, ион обрабатывает все остальное.

0 голосов
/ 05 апреля 2010

Да. Вы должны избегать работы в потоке пользовательского интерфейса в максимально возможной степени. Когда вы находитесь в 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 ().

В вашем примере, что произойдет, это то, что элемент будет показан на экране, прежде чем изображение станет доступным для отображения. Я предлагаю использовать спиннер «loading» или другой заполнитель, чтобы указать пользователю, что происходит.

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

Вы можете столкнуться с некоторыми трудностями в качестве побочного эффекта изменения представлений после выхода из getView (). Некоторые представления могут нуждаться в вызове invalidate (), чтобы изменения вступили в силу. Также будьте осторожны, если вы перерабатываете представления в вашем getView (), вы должны убедиться, что к тому времени, когда ваш код, изменяющий представление, выполняется, представление все еще используется для контента, который вы применяете. setTag () / getTag () полезен здесь для хранения некоторого идентификатора данных, которые вы можете позже проверить, чтобы убедиться, что ваш View не был переработан.

...