4

listviewArrayAdapter へのバインドを作成する小さなプロジェクトに取り組んでいます。getView()ArrayAdapterの関数ではurls、スレッド上で Web から画像をロードし、それらをリスト項目に設定します (もちろん位置に基づいているため、url[0]画像はlist_item[0]etc に設定されます)。それはすべてうまくいくようです。

ただし、アプリをテストしていたときに、リストビューが完全に表示されるのを待ってから、前後に高速スクロールを実行すると、あるリスト項目の画像が別のリスト項目の位置にずれることがあることに気付きました (中間状態にあるなど)。 . ただし、間違って表示されたアイテムを画面外にスクロールしてから戻すまで、消えません。

スレッドを使用してウェブをロードすることに関連しているかどうかはわかりませんがurl、ローカル リソース フォルダからイメージをロードすると同じ問題が発生する可能性があります。

これは実際に私が関数について持っている質問につながりgetView()ます. getView()位置に基づいて表示するURLのバインディングと同じくらい簡単なので、ロジックは正しいと思います。getView()また、アイテムを画面外にスクロールしてから戻すなど、呼び出される機会があればいつでも、リストアイテムが正しく表示されます。

私が理解していないのは、発生した問題 (中間状態のような) を説明する方法と、コードを記述するときにそれを回避する方法です。

アダプターのコードを下に貼り付けますが、質問はおそらく一般的なものだと思います。

    @Override
    public View getView(int position, View v, ViewGroup parent) {

        ViewHolder viewHolder = null;

        if (v == null) {
            LayoutInflater inflater = (LayoutInflater) getContext()
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = inflater.inflate(layoutResourceId, parent, false);

            viewHolder = new ViewHolder();
            viewHolder.title = (TextView) v.findViewById(R.id.title);
            viewHolder.description = (TextView) v.findViewById(R.id.description);
            viewHolder.image = (ImageView) v.findViewById(R.id.image);

            v.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) v.getTag();
        }

        listItem item = items[position];  //items is some global array
                                          //passed in to ArrayAdapter constructor
        if (item != null) {
            viewHolder.title.setText(item.title);   
            viewHolder.description.setText(item.description);

            if (!(item.imageHref).equalsIgnoreCase("null")) {
                mDrawableManager.fetchDrawableOnThread(item.imageHref, viewHolder.image);
            } else {
                viewHolder.image.setImageDrawable(null);
            }
        }
        return v;
    }
}

static class ViewHolder {
    TextView title;
    TextView description;
    ImageView image;
}
4

5 に答える 5

0

プロジェクトの以下のリンクからImageLoaderクラスを追加します。 リンク

getView()で以下のように画像ローダークラスのDisplayImage()メソッドを呼び出すだけです。

  ImageLoader imageLoader = new ImageLoader();


 yourImageView.setTag(URL_FOR_Your_Image);

 imageLoader.DisplayImage(URL_FOR_Your_Image,ACTIVITY.this, yourImageView);

あなたの画像はあなたが待つことなくあなたが望むようにバックグラウンドでロードされます。

于 2012-10-26T10:11:22.953 に答える
0

ダウンローダーメソッド fetchDrawableOnThread() を "synchronized" として宣言する必要があると思います。多くのスレッドが同時に動作しているため、後で開始したスレッドは早く終了する可能性があります。そのため、画像が誤って配置される可能性があります。

それは長い間私に起こりました。最後に「同期」により、きれいに行うことができました。あなたにも役立つことを願っています。

于 2012-10-26T12:17:07.110 に答える
0

ダウンロードした画像をキャッシュしていないと仮定して..次のコードを見てみましょう:

    if (!(item.imageHref).equalsIgnoreCase("null")) {
        mDrawableManager.fetchDrawableOnThread(item.imageHref, viewHolder.image);
    } else {
        viewHolder.image.setImageDrawable(null);
    }

画像ビューが再利用される場合、割り当てられたリスト アイテムの古い画像が既に存在します。したがって、スレッドがネットワークから画像をダウンロードするまでは古い画像が表示され、スレッドが現在のアイテムの画像をダウンロードすると、新しい画像に置き換えられます。次のように変更してみてください。

    if (!(item.imageHref).equalsIgnoreCase("null")) {
        viewHolder.image.setImageDrawable(SOME_DEFULAT_IMAGE);
        mDrawableManager.fetchDrawableOnThread(item.imageHref, viewHolder.image);
    } else {
        viewHolder.image.setImageDrawable(null);
    }

または、HTTP URI をサポートし、画像をキャッシュする何かリンクのスマート画像ビューを使用することもできます。スマート イメージ ビューについては、次のリンクを参照してください。

https://github.com/loopj/android-smart-image-view http://loopj.com/android-smart-image-view/

于 2012-10-26T08:55:41.620 に答える
0

もう一度同期してみます。fetchDrawableOnThread() を同期するか、fetchDrawableOnThread() 内でグローバル ハッシュマップ データを同期します。最初は問題が解決したと思っていましたが、後で何度も試してみると、問題がまだ残っていることがわかりました。

次に、同期について考えました。fetchDrawableOnThread() は getView() から呼び出され、getview() 自体には同時実行の問題はありません。Yogesh が言ったように、getView() の内部で起こったことはスレッドベースであり、戻りが早くても遅くても、getView() の正確性、つまりリスト項目の表示には遅かれ早かれ影響を与えることはできません。

fetchDrawableOnThread() 内で行ったこと (同期) は、ハッシュマップを使用してリモート URL からダウンロードした画像をキャッシュしたため、まだ正しいと思います。このハッシュマップはマルチスレッドの状況で読み取り/書き込みされるため、ロックする必要があります。 . しかし、それが UI の配置ミスの根本的な原因だとは思いません。ハッシュマップが台無しにされた場合、画像の配置ミスは永続的になります。

次に、Praful の説明に基づいて、convertView の再利用メカニズムをさらに調べました。彼は、画像が常にリモートから来て、ローカルにキャッシュがない場合に何が起こるかを明確に説明しましたが、私の状況は、高速スクロールを行う前に、リストが完全に表示されるのを待っていました。つまり、すべての画像のダウンロードとキャッシュが完了しました。したがって、私の実験では、画像はキャッシュから読み取られます。

次に、コードを調べたところ、getView() メソッドのように convertView の使用に小さな違いが 1 つあります。使用例の多くは次のようになっています。

public View getView(int position, View convertView, ViewGroup parent) {  // case 1
    View v = convertView;
    ....  // modify v
    return v;
}

ただし、たまたまコピーして使用した例:

public View getView(int position, View convertView, ViewGroup parent) {  // case 2
    ....  // modify convertView
    return convertView;
}

Androidの言うことによると、「ListViewは、convertViewパラメーターで使用されなくなった古いビューをアダプターに送信するため、最初は違いはないと思いました。」では、「convertView」パラを直接使用しないのはなぜですか?

しかし、私は間違っていたと思います。getView() コードをケース 1 に変更しました。すべてが機能します。リストをどれだけ速くスクロールしても、面白いビジネスはありません。

convertView は古いだけですか、それとも古くて使用中ですか? 後者の場合は、コピーを取得してから変更する必要があります..... ??

于 2012-10-26T22:43:14.663 に答える