Pergunta

Eu tenho o seguinte código em execução no meu dispositivo Android. Funciona muito bem e exibe os itens da minha lista maravilhosamente. Também é inteligente no fato de baixar apenas os dados quando é necessário pelo Arrayadapter. No entanto, enquanto o download da miniatura está ocorrendo, a lista inteira para e você não pode rolar até que termine de download. Existe alguma maneira de enfiar isso para que ainda role feliz, talvez mostre um suporte para a imagem de download, termine o download e depois mostre?

Eu acho que só preciso colocar minha aula de download em seu próprio tópico para que seja executado separadamente da interface do usuário. Mas como adicionar isso ao meu código é o mistério!

Qualquer ajuda com isso seria realmente apreciada.

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));
    }
}
Foi útil?

Solução

Aqui está uma versão simplificada do que estou usando em meus aplicativos:

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

Outras dicas

Você também pode conferir CWAC-THUMBNAIL Para uma solução de queda (embora tenha um pouco mais de sobrecarga do que as soluções mais simples acima). Eu o usei com grande sucesso em qualquer lugar em que tenha uma imagem da web para baixar; Você basicamente configura algumas opções globais de armazenamento em cache para o seu aplicativo e, em seguida, embrulhe o seu listrapter em um thumbnailadapter com uma lista de Android: IDs das visualizações Images em sua lista e ligue para o Settag (ImageUrl) nas visualizações de imagem no método GetView do seu adaptador e e e Ele lida com o resto.

Sim. Você deve evitar a execução do tópico da interface do usuário o máximo possível. Quando você está em getview (), você está no tópico da interface do usuário. Para começar a fazer isso:

new Thread(new Runnable(){

  public void run() {
    // your code here

  }}).start();

Então, quando você precisa modificar uma visão de alguma forma, volte para o tópico da interface do usuário como este:

runOnUiThread(new Runnable(){

  public void run() {
    // your view-modifying code here

  }});

.. ou use o mecanismo View.Post ().

No seu exemplo, o que acontecerá é que o item será mostrado na tela antes que a imagem esteja disponível para exibição. Sugiro usar um spinner de 'carregamento' ou algum outro espaço reservado para indicar ao usuário o que está acontecendo.

Você pode, na prática, ninhos como esse várias vezes, embora atinja um ponto em que um design simplificado está em ordem. As aulas anônimas podem ser ineficientes em termos de memória e disparar muitos threads sem um mecanismo de cancelamento podem ter suas próprias desvantagens.

Você pode ter algumas dificuldades como efeito colateral da modificação de visualizações após a saída do getView (). Algumas visualizações podem precisar do invalidato () chamadas para que suas mudanças entrem em vigor. Cuidado também Se você estiver reciclando visualizações em seu getView (), verifique que, no momento em que seu código de alteração de visualização seja executado, a visualização ainda esteja sendo usada para o conteúdo que você está aplicando. SettAg ()/getTag () é útil aqui para armazenar algum ID dos dados que você pode verificar posteriormente para garantir que sua visualização não tenha sido reciclada.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top