2

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

3 に答える 3

4

これが私のアプリで使用しているものの簡略版です:

// 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);
                        }
                    });
                }
            }
        });
    }
于 2010-04-05T13:17:27.807 に答える
1

ドロップインソリューションについては、 cwac-thumbnailをチェックすることもできます(ただし、上記の単純なソリューションよりもオーバーヘッドが少し多くなります)。ダウンロードするWeb画像がある場所ならどこでも、これを使用して大成功を収めました。基本的に、アプリにいくつかのグローバルキャッシュオプションを設定し、ListAdapterをThumbnailAdapterでラップして、リスト内のimageviewsのandroid:idsのリストを作成し、アダプターのgetViewメソッドのimageviewsでsetTag(imageUrl)を呼び出します。残りを処理します。

于 2010-04-05T14:15:54.580 に答える
0

はい。UIスレッドでの実行はできるだけ避けてください。getView()を使用しているときは、UIスレッドを使用しています。ブレークアウトするには、これを行います。

new Thread(new Runnable(){

  public void run() {
    // your code here

  }}).start();

次に、何らかの方法でビューを変更する必要がある場合は、次のようにUIスレッドに戻ります。

runOnUiThread(new Runnable(){

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

  }});

..またはView.post()メカニズムを使用します。

あなたの例では、画像が表示される前にアイテムが画面に表示されます。「読み込み中」のスピナーまたはその他のプレースホルダーを使用して、何が起こっているかをユーザーに示すことをお勧めします。

実際には、このように何度か入れ子にすることができますが、単純化された設計が整うところまで到達します。匿名クラスはメモリ的に非効率的である可能性があり、キャンセルメカニズムなしで多くのスレッドを起動することには独自の欠点があります。

getView()が終了した後にビューを変更することの副作用として、いくつかの問題が発生する可能性があります。一部のビューでは、変更を有効にするためにinvalidate()を呼び出す必要がある場合があります。また、getView()でビューをリサイクルする場合は、ビュー変更コードが実行されるまでに、適用するコンテンツにビューが引き続き使用されていることを確認する必要があります。setTag()/ getTag()は、ビューがリサイクルされていないことを後で確認できるデータのIDを格納するのに役立ちます。

于 2010-04-05T13:01:43.100 に答える