如何在SimpleAdapter中使用ImageLoader类来显示ImageUrl中的ImageView?

时间:2012-04-15 10:04:13

标签: android imageview listactivity simpleadapter image-loading

我有以下类解析JSON并显示名称和其他细节,我在listview中没有提到。
ShowViewActivity.java

public class ShowViewActivity extends ListActivity {

private static String url = "http://example.com/myfile.php";
private static final String TAG_ROOT = "root";
private static final String TAG_NAME = "name";
private static final String TAG_IMAGE = "image";

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    ArrayList<HashMap<String, String>> myList = new ArrayList<HashMap<String, String>>();
    JSONParser jParser = new JSONParser();
    JSONObject json = jParser.getJSONFromUrl(url);
    try {
        root = json.getJSONArray(TAG_ROOT);
        for (int i = 0; i < root.length(); i++) {
            JSONObject c = root.getJSONObject(i);
            String name = c.getString(TAG_NAME);
            String image = c.getString(TAG_IMAGE);
            HashMap<String, String> map = new HashMap<String, String>();
            map.put(TAG_NAME, name);
            map.put(TAG_IMAGE, image);
            myList.add(map);
        }
    } catch (JSONException e) {
        e.printStackTrace();
    }


    myAdapter adapter = new myAdapter(this, myList, R.layout.list_item,
            new String[] {}, new int[] {});

    setListAdapter(adapter);
    final ListView lv = getListView();

    // Launching new screen on Selecting Single ListItem
    lv.setOnItemClickListener(new OnItemClickListener() {

        public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) {

        }

    });

}

private class myAdapter extends SimpleAdapter {

    public myAdapter(Context context, List<? extends Map<String, ?>> data,
            int resource, String[] from, int[] to) {
        super(context, data, resource, from, to);

    }

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

        if (convertView == null) {
            convertView = getLayoutInflater().inflate(R.layout.list_item,
                    null);
        }

        HashMap<String, Object> data = (HashMap<String, Object>) getItem(position);

        TextView nameTextView = (TextView) convertView
                .findViewById(R.id.name);
        ImageView iconImageView = (ImageView) convertView
                .findViewById(R.id.listicon);

        String nameString = (String) data.get(TAG_NAME);
        nameTextView.setText(nameString);
        String imageUrl = (String) data.get(TAG_IMAGE);

        return convertView;
    }
}
}

我想实现以下ImageDownloader类来显示来自网址的图片。

ImageDownloader.java

public class ImageLoader {

// the simplest in-memory cache implementation. This should be replaced with
// something like SoftReference or BitmapOptions.inPurgeable(since 1.6)
private HashMap<String, Bitmap> cache = new HashMap<String, Bitmap>();

private File cacheDir;

public ImageLoader(Context context) {
    // Make the background thead low priority. This way it will not affect
    // the UI performance
    photoLoaderThread.setPriority(Thread.NORM_PRIORITY - 1);

    // Find the dir to save cached images
    if (android.os.Environment.getExternalStorageState().equals(
            android.os.Environment.MEDIA_MOUNTED))
        cacheDir = new File(
                android.os.Environment.getExternalStorageDirectory(),
                "LazyList");
    else
        cacheDir = context.getCacheDir();
    if (!cacheDir.exists())
        cacheDir.mkdirs();
}

final int stub_id = R.drawable.icon;

public void DisplayImage(String url, Activity activity, ImageView imageView) {
    if (cache.containsKey(url))
        imageView.setImageBitmap(cache.get(url));
    else {
        queuePhoto(url, activity, imageView);
        imageView.setImageResource(stub_id);
    }
}

private void queuePhoto(String url, Activity activity, ImageView imageView) {
    // This ImageView may be used for other images before. So there may be
    // some old tasks in the queue. We need to discard them.
    photosQueue.Clean(imageView);
    PhotoToLoad p = new PhotoToLoad(url, imageView);
    synchronized (photosQueue.photosToLoad) {
        photosQueue.photosToLoad.push(p);
        photosQueue.photosToLoad.notifyAll();
    }

    // start thread if it's not started yet
    if (photoLoaderThread.getState() == Thread.State.NEW)
        photoLoaderThread.start();
}

private Bitmap getBitmap(String url) {
    // I identify images by hashcode. Not a perfect solution, good for the
    // demo.
    String filename = String.valueOf(url.hashCode());
    File f = new File(cacheDir, filename);

    // from SD cache
    Bitmap b = decodeFile(f);
    if (b != null)
        return b;

    // from web
    try {
        Bitmap bitmap = null;
        InputStream is = new URL(url).openStream();
        OutputStream os = new FileOutputStream(f);
        Utils.CopyStream(is, os);
        os.close();
        bitmap = decodeFile(f);
        return bitmap;
    } catch (Exception ex) {
        ex.printStackTrace();
        return null;
    }
}

// decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f) {
    try {
        // decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new FileInputStream(f), null, o);

        // Find the correct scale value. It should be the power of 2.
        final int REQUIRED_SIZE = 70;
        int width_tmp = o.outWidth, height_tmp = o.outHeight;
        int scale = 1;
        while (true) {
            if (width_tmp / 2 < REQUIRED_SIZE
                    || height_tmp / 2 < REQUIRED_SIZE)
                break;
            width_tmp /= 2;
            height_tmp /= 2;
            scale++;
        }

        // decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
    } catch (FileNotFoundException e) {
    }
    return null;
}

// Task for the queue
private class PhotoToLoad {
    public String url;
    public ImageView imageView;

    public PhotoToLoad(String u, ImageView i) {
        url = u;
        imageView = i;
    }
}

PhotosQueue photosQueue = new PhotosQueue();

public void stopThread() {
    photoLoaderThread.interrupt();
}

// stores list of photos to download
class PhotosQueue {
    private Stack<PhotoToLoad> photosToLoad = new Stack<PhotoToLoad>();

    // removes all instances of this ImageView
    public void Clean(ImageView image) {
        for (int j = 0; j < photosToLoad.size();) {
            if (photosToLoad.get(j).imageView == image)
                photosToLoad.remove(j);
            else
                ++j;
        }
    }
}

class PhotosLoader extends Thread {
    public void run() {
        try {
            while (true) {
                // thread waits until there are any images to load in the
                // queue
                if (photosQueue.photosToLoad.size() == 0)
                    synchronized (photosQueue.photosToLoad) {
                        photosQueue.photosToLoad.wait();
                    }
                if (photosQueue.photosToLoad.size() != 0) {
                    PhotoToLoad photoToLoad;
                    synchronized (photosQueue.photosToLoad) {
                        photoToLoad = photosQueue.photosToLoad.pop();
                    }
                    Bitmap bmp = getBitmap(photoToLoad.url);
                    cache.put(photoToLoad.url, bmp);
                    if (((String) photoToLoad.imageView.getTag())
                            .equals(photoToLoad.url)) {
                        BitmapDisplayer bd = new BitmapDisplayer(bmp,
                                photoToLoad.imageView);
                        Activity a = (Activity) photoToLoad.imageView
                                .getContext();
                        a.runOnUiThread(bd);
                    }
                }
                if (Thread.interrupted())
                    break;
            }
        } catch (InterruptedException e) {
            // allow thread to exit
        }
    }
}

PhotosLoader photoLoaderThread = new PhotosLoader();

// Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable {
    Bitmap bitmap;
    ImageView imageView;

    public BitmapDisplayer(Bitmap b, ImageView i) {
        bitmap = b;
        imageView = i;
    }

    public void run() {
        if (bitmap != null)
            imageView.setImageBitmap(bitmap);
        else
            imageView.setImageResource(stub_id);
    }
}

public void clearCache() {
    // clear memory cache
    cache.clear();

    // clear SD cache
    File[] files = cacheDir.listFiles();
    for (File f : files)
        f.delete();
}

}

我看到扩展BaseAdapter的lazyload示例但在这里我使用的是我的自定义适配器名称myAdapter,它扩展了SimpleAdapter?
如何实现此ImageLoader类以显示来自web image url的imageview?

1 个答案:

答案 0 :(得分:1)

第一步是获取ImageDownloader实例。我建议你为一个实例使用一些集中的位置,例如你自己的Application扩展名。这样你只需要创建一次,但在需要的地方使用它。此外,如果您(重新)每次调用都构造此对象,则提供的缓存将被限制为无用。或者,您可以将该类设置为单身,但我个人更喜欢前者。

获得ImageDownloader对象后,只需对自定义适配器进行更改,如下所述。由于您需要传入Activity引用,请保留传递给Context构造函数的myAdapter变量的句柄。在正常情况下,这实际上是运行时的Activity引用。

private class myAdapter extends SimpleAdapter {

    private Context mContext;

    public myAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) {
        super(context, data, resource, from, to);
        mContext = context;

    }

    ...

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

        // assuming you have an instance of ImageDownloader here
        // 
        mImageDownloader.DisplayImage(imageUrl,(Activity)mContext, iconImageView);
    }

    ...
}