如何在Android中处理加载图像[重复]
Posted
技术标签:
【中文标题】如何在Android中处理加载图像[重复]【英文标题】:How to handle Loading Images in Android [duplicate] 【发布时间】:2011-07-01 09:58:39 【问题描述】:可能重复:android - How do I do a lazy load of images in ListView
这几天我一直在尝试解决这个问题,但我似乎无法完全理解这个过程。我的应用程序从服务器访问许多图像。截至目前,它设置为一次加载 1 张图像并显示它。当用户点击下一个按钮时,会加载并显示下一个图像。但是加载时间有点太长了。有什么办法可以提高下一张图片的加载时间?
我一直在玩线程和 AsyncTask。我的想法是将前一个和下一个图像也保留在内存中。当用户点击下一步时,我执行以下操作:
prevImage = currentImage;
currentImage = nextImage;
nextImage = getBitmapfromURL(urlPath);
而nextImage实际上是在AsyncTask或Thread中执行的。我的问题是如果用户在该线程完成之前点击下一个按钮(它只是显示一个空白图像)。所以我不确定这是否是要走的路。还有其他方法可以改善这些图片的加载时间吗?
【问题讨论】:
参考这个问题***.com/questions/541966/…,在这里你可以有很多想法,人们说过不同的路径可以到达这个目的地。 感谢您的回复。该代码看起来与 Rohit 发布的完全一样。但我不知道如何将为列表视图设计的示例转换为我的设计,一次只显示一张图像。我添加了 ImageLoader 和 Utils 类。然后我添加了 imageLoader=new ImageLoader(getApplicationContext()); imageLoader.DisplayImage(firstImages[0], this, imgView);在我的类 onCreate 方法中加载第一张图像。但我的图像没有显示。有什么想法吗? 找出问题所在。你必须使用 imgView.setTag(url);不设置标签,下载后不会更新imageView。谢谢你指点我的线程。并感谢罗希特。我只需要看看他是如何使用 ImageLoader 类的。 我很高兴看到你已经解决了你的问题,好朋友 好吧,我想我说得太早了。我确实让它工作了一点。但是在浏览了几张图片后,我收到了内存不足错误。在 Fedor 代码的顶部,他认为您可能应该将其更改为使用 SoftReferences。我玩弄了它并让它编译,但我现在无法加载任何图像。我以前从未使用过软引用,所以我确定我做错了。您将如何在他的代码上实现 SoftReferences?那应该消除OOM错误,对吗?谢谢。 【参考方案1】:这是我从服务器加载图像的类。
package test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.URL;
import java.util.HashMap;
import java.util.Stack;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.widget.ImageView;
import com.com.app.R;
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.no_image;
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
return new BitmapDrawable(new URL(url).openStream()).getBitmap();
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 (photoToLoad.url == null)
photoToLoad.url = "http://192.168.0.2/phpdemoprojects/cardsonmobile/uploads/cards/0009.png";
else
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();
【讨论】:
所以基本上,您将所有图像存储到 SD 卡中,然后在需要时访问它们,对吗?所以对我来说,这样做,我必须让用户等待图像被下载,然后我让他们点击下一个/上一个按钮。我不认为我想要这样,因为这样做可能需要几分钟才能加载。感谢您的回复。 不,用户不必等待下载所有图像.. 图像 URL 被提供给它,它将在后台继续下载并在需要时立即对其进行画像。我将它与我的自定义列表适配器一起使用 我了解您对它的使用。对于我正在尝试做的事情,我不希望在单击按钮查看图像之前加载图像。例如,我有一个带有不同类别的 Spinner 项目的屏幕。然后,当用户单击一个按钮时,会出现一个新屏幕,其中显示许多图片,这些图片基于在微调器中选择的类别。所以在查看图像之前我不会知道要加载哪些图像,这意味着我必须等待它们加载才能查看下一个图像。如果我仍然无法正确理解您,请告诉我。再次感谢。以上是关于如何在Android中处理加载图像[重复]的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Android 的 ListView 中延迟加载图像
如何在android studio中检查ImageView是不是已完成加载和图像