10

ListViewの画像ファイルのAsyncTaskでサムネイルを機能させようとしています。行のリサイクルという一般的な問題が発生しているため、スクロールするとサムネイルが間違った行に割り当てられます。ImageViewにタグを追加してから、AsyncTaskのonPostExecute()でタグを確認しようとしましたが、失敗しました。誰か助けてください!

カスタムアダプタは次のとおりです。

public class MySimpleAdapter extends SimpleAdapter {

        public MySimpleAdapter(Context context,
                List<? extends Map<String, ?>> data, int resource,
                String[] from, int[] to) {
            super(context, data, resource, from, to);
            // TODO Auto-generated constructor stub
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            final View v = super.getView(position, convertView, parent);
            thumbnail = (ImageView) v.findViewById(R.id.thumbnail);
            checker = (CheckBox) v.findViewById(R.id.checkBox);
            filenametext = (TextView) v.findViewById(R.id.text1);
            String pathtoimage = startLocation.concat("/"
                    + filenametext.getText().toString());
            desctext = (TextView) v.findViewById(R.id.text2);
            String temp = desctext.getText().toString();
            if (temp.equals("Directory") == true) {
                checker.setEnabled(false);
                switch (theme) {
                case 0:
                    thumbnail.setImageResource(R.drawable.folder_light);
                    break;
                case 1:
                    thumbnail.setImageResource(R.drawable.folder_dark);
                    break;
                }

            } else {
                checker.setEnabled(true);
                if (filenametext.getText().toString().endsWith(".jpg")
                        || filenametext.getText().toString().endsWith(".png")
                        || filenametext.getText().toString().endsWith(".bmp")) {
                    Boolean hashmapfound = false;
                    for (HashMap.Entry<String, Bitmap> entry : thumbnaillist
                            .entrySet()) {
                        String key = entry.getKey();
                        if (key.equals(filenametext.getText().toString())) {
                            Log.d(TAG, "HashMapKey Found!");
                            thumbnail.setImageBitmap(entry.getValue());
                            hashmapfound = true;
                        }
                    }
                    if (!hashmapfound) {
                        Log.d(TAG, "NO HashMapKey Found! Adding to HashMap!");
                        switch (theme) {
                        case 0:
                            thumbnail
                                    .setImageResource(R.drawable.unknown_image_light);
                            break;
                        case 1:
                            thumbnail
                                    .setImageResource(R.drawable.unknown_image_dark);
                            break;
                        }
                        thumbnail.setTag((filenametext.getText().toString()));
                        new GetBitMaps(thumbnail).execute(pathtoimage,
                                filenametext.getText().toString());
                    }

                } else {
                    switch (theme) {
                    case 0:
                        thumbnail.setImageResource(R.drawable.file_light);
                        break;
                    case 1:
                        thumbnail.setImageResource(R.drawable.file_dark);
                        break;
                    }
                }
            }
            return v;
        }

    }

AsyncTaskは次のとおりです。

class GetBitMaps extends AsyncTask<String, Void, Bitmap> {

    private ImageView thumbnail;
    private String imageName;

    public GetBitMaps(ImageView thumb) {
        // TODO Auto-generated constructor stub
        thumbnail = thumb;
    }

    @Override
    protected Bitmap doInBackground(String... pathtoimage) {
        Bitmap bmp = createThumbnail(pathtoimage[0]);
        thumbnaillist.put(pathtoimage[1], bmp);
        imageName = pathtoimage[1];
        return bmp;
    }

    @Override
    protected void onPostExecute(Bitmap bmp) {

        if (((String) thumbnail.getTag()).equals(imageName)) {
            thumbnail.setImageBitmap(bmp);
        }
    }

    private Bitmap createThumbnail(String filepath) {
        Bitmap bmp = BitmapFactory.decodeFile(filepath);
        int w = bmp.getWidth();
        int h = bmp.getHeight();
        if (w > h) {
            w = 80;
            h = 40;
        } else if (w < h) {
            w = 40;
            h = 80;
        }
        bmp = Bitmap.createScaledBitmap(bmp, w, h, true);

        return bmp;
    }
}

スクロール中にサムネイルを正しい行に表示するために、他に何をすべきかまだわかりません。

注意:影響を受けた行から離れてスクロールして下にスクロールした後は、問題なく動作しますが、スクロールの問題は解消されません。

4

3 に答える 3

20

このブログ投稿から:

実行したいのは、行ごとのすべてのIOまたはCPUにバインドされた重いルーチンを、別のスレッドで非同期に実行することです。ここでの秘訣は、それを実行し、ListViewのリサイクル動作に準拠することです。たとえば、AsyncTaskを実行してアダプタのgetView()にプロファイル画像をロードする場合、画像をロードするビューは、AsyncTaskが終了する前に別の位置にリサイクルされる可能性があります。したがって、非同期操作が完了したら、ビューがリサイクルされていないかどうかを知るメカニズムが必要です。

これを実現する簡単な方法の1つは、ビューに関連付けられている行を識別する情報をビューに添付することです。次に、非同期操作が終了したときに、ビューのターゲット行がまだ同じであるかどうかを確認できます。これを達成する方法はたくさんあります。これは、あなたがそれを行うことができる1つの方法の単純なスケッチです:

public View getView(int position, View convertView,
        ViewGroup parent) {
    ViewHolder holder;

    ...

    holder.position = position;

    new ThumbnailTask(position, holder)
            .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null);

    return convertView;
}

private static class ThumbnailTask extends AsyncTask {
    private int mPosition;
    private ViewHolder mHolder;

    public ThumbnailTask(int position, ViewHolder holder) {
        mPosition = position;
        mHolder = holder;
    }

    @Override
    protected Cursor doInBackground(Void... arg0) {
        // Download bitmap here
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (mHolder.position == mPosition) {
            mHolder.thumbnail.setImageBitmap(bitmap);
        }
    }
}

private static class ViewHolder {
    public ImageView thumbnail;
    public int position;
}
于 2012-07-28T19:53:34.333 に答える
1

AsyncTask.THREAD_POOL_EXECUTORを使用すると、複数のスレッドを実行してツムネイルをフェッチすることになります。実行方法やフィニッシュ方法、ビューの画像の設定方法に順序はありません。前後にスクロールすると、ビューに間違った画像が表示される可能性があります。

AsyncTask.THREAD_POOL_EXECUTORをテストしましたが、一部のビューで間違った画像が表示されます。

于 2013-06-26T09:15:24.023 に答える
0

ListViewをアクティビティからAdapterコンストラクターに渡すことを試みることができます(非同期タスクにさえ、それをどのように実装したいかによって異なります)。getFirstVisiblePosition()とgetLastVisiblePosition()を使用して位置を比較しますmPosition

于 2013-01-18T09:12:00.077 に答える