1

アクティビティに画像を含む ListView があり、LRU キャッシュを追加するまでうまく機能します。画像が読み込まれているときに初めて(スクロールしない場合)ロードすると、最初の要素がロードされていたすべての画像間でその画像が変更されます。

私のLRUキャッシュは次のようになります

public class Image {
    private static LruCache<String, Bitmap>     mMemoryCache    = null;
    private static int                          cacheSize       = 1024 * 1024 * 10;

    private static class AsyncLoader extends AsyncTask<String, Void, Bitmap> {
        private ImageView   mTarget;

        public AsyncLoader(ImageView target) {
            this.mTarget = target;
        }

        @Override
        protected void onPreExecute() {
            mTarget.setTag(this);
        }

        @Override
        protected Bitmap doInBackground(String...urls) {
            String url = urls[0];

            Bitmap result = null;

            if (url != null) {
                result = load(url);

                if (result != null) {
                    mMemoryCache.put(url, result);
                }
            }

            return result;
        }

        @Override
        protected void onPostExecute(Bitmap result) {
            if (mTarget.getTag() == this) {
                mTarget.setTag(null);
                if (result != null) mTarget.setImageBitmap(result);
            }
        }
    }

    public static Bitmap load(String urlString) {
        if (urlString == null || urlString.length() == 0) return null;

        Bitmap bitmap = null;
        URL url = null;

        try {
            url = new URL(urlString);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        try {
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            conn.connect();
            InputStream is = conn.getInputStream();
            bitmap = BitmapFactory.decodeStream(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return bitmap;
    }

    public static void loadToView(String url, ImageView view) {
        if (url == null || url.length() == 0) return;
        if (mMemoryCache == null) {
            mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
                @Override
                protected int sizeOf(String key, Bitmap bitmap) {
                    return (bitmap.getRowBytes() * bitmap.getHeight());
                }
            };
        }

        Bitmap bitmap = getBitmapFromMemCache(url);
        if (bitmap == null) {
            final AsyncLoader task = (AsyncLoader) new AsyncLoader(view);
            view.setTag(task);
            task.execute(url);
        } else {
            view.setImageBitmap(bitmap);
        }
    }
}

使用法:

Image.loadToView("http://image_url", (ImageView) view.findViewById(R.id.img_thumbnail));

これは私の BaseAdapter getView の外観です

@Override
public View getView(final int position, View view, ViewGroup parent) {
    if (view == null) view = inflater.inflate(R.layout.list_item, null);

    ((TextView) view.findViewById(R.id.txt_name)).setText(filtered_data.get(position).name);

    Image.loadToView("http://graph.facebook.com/" + filtered_data.get(position).id + "/picture", (ImageView) view.findViewById(R.id.img_thumbnail));

    return view;
}
4

1 に答える 1

3

リストビューの問題に関する画像、リストビューのリサイクルに関連するもの、関連する投稿について多くのことを読んでいることがわかりました。

私が追加したのは onPostExecute メソッドの else ステートメントです。タグがタグに設定されたものでない場合は、それをキャンセルします。

固定コードは

public class Image {
    private static LruCache<String, Bitmap>     mMemoryCache    = null;
    private static int                          cacheSize       = 1024 * 1024 * 10;

    private static class AsyncLoader extends AsyncTask<String, Void, Bitmap> {
        private ImageView   mTarget;

        public AsyncLoader(ImageView target) {
            this.mTarget = target;
        }

        @Override
        protected void onPreExecute() {
            mTarget.setTag(this);
        }

        @Override
        protected Bitmap doInBackground(String...urls) {
            String url = urls[0];

            Bitmap result = null;

            if (url != null) {
                result = load(url);

                if (result != null) {
                    mMemoryCache.put(url, result);
                }
            }

            return result;
        }

        @Override
        protected void onPostExecute(Bitmap result) {
            if (mTarget.getTag() == this) {
                mTarget.setTag(null);
                if (result != null) mTarget.setImageBitmap(result);
            } else if (mTarget.getTag() != null) {
                ((AsyncLoader) mTarget.getTag()).cancel(true);
                mTarget.setTag(null);
            }
        }
    }

    public static Bitmap load(String urlString) {
        if (urlString == null || urlString.length() == 0) return null;

        Bitmap bitmap = null;
        URL url = null;

        try {
            url = new URL(urlString);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        try {
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            conn.connect();
            InputStream is = conn.getInputStream();
            bitmap = BitmapFactory.decodeStream(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return bitmap;
    }

    public static void loadToView(String url, ImageView view) {
        if (url == null || url.length() == 0) return;
        if (mMemoryCache == null) {
            mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
                @Override
                protected int sizeOf(String key, Bitmap bitmap) {
                    return (bitmap.getRowBytes() * bitmap.getHeight());
                }
            };
        }

        Bitmap bitmap = getBitmapFromMemCache(url);
        if (bitmap == null) {
            final AsyncLoader task = (AsyncLoader) new AsyncLoader(view);
            view.setTag(task);
            task.execute(url);
        } else {
            view.setImageBitmap(bitmap);
        }
    }
}

Google はこれを修正するか、よりクリーンな回避策を提供する必要があると思います。なぜなら、開発者が独自のアプリを構築することだけを気にする必要があり、修正方法を見つける時間を無駄にしないようなものを構築する際に (私の意見では) Google が失敗したためです。 SDK の問題

于 2012-12-04T19:07:50.760 に答える