ImageLoader的仅载入列表中的图像列表项已经关闭屏幕后 [英] Imageloader only loading images in list after listitem has gone off screen
问题描述
我有从URL中通过ImageLoader的类适配器加载图像列表视图。
是,直到列表项已滚动关闭屏幕不显示的问题在屏幕上的图像/加载。
所以基本上,列表视图显示,但直到你向下滚动,滚动再次回升没有图像加载。显示它们在第一时间内没有图像加载,直到您滚动回给他们这aplies到列表中,所有的项目。
我没有写的ImageLoader的类我和林有一个很难确切地理解为什么图像不上第一显示加载。已经尝试了很多不同的东西与队列但似乎没有任何帮助。
在ImageLoader的类:
公共类ImageLoader的{ //最简单的内存缓存的实现。这应该与类似SoftReference的或BitmapOptions.inPurgeable更换(自1.6)
私人的HashMap<弦乐,位图>缓存=新的HashMap<弦乐,位图>();
私人文件cacheDir; 公共ImageLoader的(上下文的背景下){
//使THEAD背景低优先级。这样也不会影响用户界面性能
photoLoaderThread.setPriority(Thread.NORM_PRIORITY-1); //查找目录保存缓存图像
如果(android.os.Environment.getExternalStorageState()。等于(android.os.Environment.MEDIA_MOUNTED))
cacheDir =新的文件(android.os.Environment.getExternalStorageDirectory(),LazyList);
其他
cacheDir = context.getCacheDir();
如果(!cacheDir.exists())
cacheDir.mkdirs();
} 最终诠释stub_id = R.drawable.nopic; 公共无效DisplayImage(字符串URL,活动活动,ImageView的ImageView的,进度进度)
{
如果(cache.containsKey(URL)){
imageView.setImageBitmap(cache.get(URL));
如果(进度!= NULL){
progressBar.setVisibility(View.GONE);
imageView.setVisibility(View.VISIBLE);
}
}其他{
queuePhoto(URL,活动,ImageView的,进度); 如果(进度!= NULL){
imageView.setVisibility(View.GONE); //添加
progressBar.setVisibility(View.VISIBLE);
}其他{
imageView.setImageResource(stub_id);
}
}
} 私人无效queuePhoto(字符串URL,活动活动,ImageView的ImageView的,进度进度)
{ //这个ImageView的可之前用于其它图像。所以有可能在队列中的一些旧的任务。我们需要将它们丢弃。
photosQueue.Clean(ImageView的);
PhotoToLoad P =新PhotoToLoad(URL,ImageView的,进度);
同步(photosQueue.photosToLoad){
photosQueue.photosToLoad.push(P);
photosQueue.photosToLoad.notifyAll();
} //启动线程,如果它尚未启动
如果(photoLoaderThread.getState()== Thread.State.NEW)
photoLoaderThread.start();
} 私人位图getBitmap(字符串URL)
{
//我通过哈希code识别图像。没有一个完美的解决方案,很好的演示。
字符串文件名=将String.valueOf(url.hash code());
文件f =新的文件(cacheDir,文件名); //从SD缓存
位图B =去codeFILE(F);
如果(B!= NULL)
返回b; //从网页
尝试{
位图位图= NULL;
InputStream的是=新的URL(网址).openStream();
OutputStream的OS =新的FileOutputStream(F);
Utils.CopyStream(是,OS);
os.close();
位=去codeFILE(F);
返回位图;
}赶上(例外前){
ex.printStackTrace();
返回null;
}
} //德$ C $连拍影像的鳞它来减少内存消耗
私人位图德codeFILE(文件f){
尝试{
//德code图像尺寸
BitmapFactory.Options O =新BitmapFactory.Options();
o.inJustDe codeBounds = TRUE;
BitmapFactory.de codeStream(新的FileInputStream(F),空,O); //找到正确的比例值。它应该是2的幂。
INT requiredSize = 100; INT width_tmp = o.outWidth,height_tmp = o.outHeight;
int标= 1;
而(真){
如果(width_tmp / 2'; requiredSize || height_tmp / 2版; requiredSize)
打破;
width_tmp / = 2;
height_tmp / = 2;
规模* = 2;
} //德code。与inSampleSize
BitmapFactory.Options O2 =新BitmapFactory.Options();
o2.inSampleSize =规模;
返回BitmapFactory.de codeStream(新的FileInputStream(F),空,O2);
}赶上(FileNotFoundException异常五){}
返回null;
} //任务队列
私有类PhotoToLoad
{
公共字符串的URL;
公共ImageView的ImageView的;
公众进度进度;
公共PhotoToLoad(字符串U,ImageView的我,进度P){
URL = U;
ImageView的= I;
进度= P;
}
} PhotosQueue photosQueue =新PhotosQueue(); 公共无效stopThread(){
photoLoaderThread.interrupt();
} //照片商店列表下载
类PhotosQueue
{
私人堆叠式和LT; PhotoToLoad> photosToLoad =新的堆栈< PhotoToLoad>(); //删除此的ImageView的所有实例
公共无效清洁(ImageView的图片)
{
为(中间体J = 0; J&下; photosToLoad.size()){
如果(photosToLoad.get(J).imageView ==图片)
photosToLoad.remove(J);
其他
++焦耳;
}
}
} // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// PHOTOSLOADER:螺纹
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 类PhotosLoader继承Thread {
公共无效的run(){
尝试{
而(真)
{
//线程等待直到有任何图像队列中的加载
如果(photosQueue.photosToLoad.size()== 0)
同步(photosQueue.photosToLoad){
photosQueue.photosToLoad.wait();
}
如果(photosQueue.photosToLoad.size()!= 0)
{
PhotoToLoad photoToLoad;
同步(photosQueue.photosToLoad){
photoToLoad = photosQueue.photosToLoad.pop(); photosQueue.photosToLoad.remove(photoToLoad);
}
BMP位图= getBitmap(photoToLoad.url);
cache.put(photoToLoad.url,BMP);
对象标记= photoToLoad.imageView.getTag();
如果(标记= NULL&放大器;!及((字符串)标签).equals(photoToLoad.url)){
BitmapDisplayer BD =新BitmapDisplayer(BMP,photoToLoad.imageView,photoToLoad.progressBar);
活动一=(活动)photoToLoad.imageView.getContext();
a.runOnUiThread(BD);
}
}
如果(Thread.interrupted())
打破;
}
}赶上(InterruptedException的E){
//允许线程退出
}
}
} PhotosLoader photoLoaderThread =新PhotosLoader();
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//位图显示器
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX //用在UI线程来显示位图
类BitmapDisplayer实现Runnable {
位图位图;
ImageView的ImageView的;
进度进度;
公共BitmapDisplayer(位图B,ImageView的我,进度P){
位= B;
ImageView的= I;
进度= P;
}
公共无效的run(){
如果(位图!= NULL){
imageView.setImageBitmap(位图);
如果(进度!= NULL){
imageView.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
}
}其他{
如果(进度!= NULL){
progressBar.setVisibility(View.VISIBLE);
imageView.setVisibility(View.GONE);
}
}
}
} 公共无效clearCache(){
//清除内存高速缓存
cache.clear(); //清SD缓存
文件[] =文件cacheDir.listFiles();
对于(F文件:文件)
f.delete();
}
}
该适配器:
公共类Adapter_Agenda延伸BaseAdapter { // DEBUG
私人最终字符串标记= this.getClass()getSimpleName()。 私人LayoutInflater吹气= NULL;
公共ViewHolder持有人;
私人的ArrayList<议程与GT;议程;
UnixTimeToStringConverter unixConverter;
ImageLoader的ImageLoader的; 查看六; 公共Adapter_Agenda(上下文的背景下,ArrayList的<议程与GT;议程){ this.agendas =议程;
unixConverter =新UnixTimeToStringConverter();
ImageLoader的=新ImageLoader的(上下文);
吹气=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
} 公众诠释的getCount(){
返回agendas.size();
} @覆盖
公共议程的getItem(INT位置){
返回agendas.get(位置);
} 众长getItemId(INT位置){
返回的位置;
} 公共查看getView(INT位置,查看convertView,父母的ViewGroup){ VI = convertView; 如果(convertView == NULL){ VI = inflater.inflate(R.layout.item_list_agenda,NULL);
持有人=新ViewHolder(); holder.header =(TextView中)vi.findViewById(R.id.item_list_header);
holder.image =(ImageView的)vi.findViewById(R.id.item_list_image);
holder.time =(TextView中)vi.findViewById(R.id.item_list_time);
holder.description =(TextView中)vi.findViewById(R.id.item_list_description); vi.setTag(保持器);
支架=(ViewHolder)vi.getTag();
}其他{
支架=(ViewHolder)vi.getTag();
} holder.header.setText(agendas.get(位置).getHeader());
imageLoader.DisplayImage(agendas.get(位置).getImageURL(),活动,holder.image,NULL);
holder.time.setText(unixConverter.getUnixDateFormated(agendas.get(位置).getStartTime())); 返回VI;
} // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// VIEWHOLDER
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
公共类ViewHolder { 公共TextView的时间;
公众形象ImageView的;
公众的TextView头;
公共TextView的描述; }
}
只是把
holder.image.setTag(agendas.get(位置).getImageURL());
在
imageLoader.DisplayImage(agendas.get(位置).getImageURL(),活动,holder.image,NULL);
I have a listView with an adapter loading images from URLs through a ImageLoader class. The problem is, the images on the screen are not displayed/loaded until the list item has been scrolled off screen.
So basically, the listView is shown, but no images are loaded until you scroll down and scroll back up again. This aplies to all the items in the list, when displaying them the first time no images are loaded until you scroll back to them.
I have not written the ImageLoader class myself and Im having a hard time understanding exactly why the images don't load on the first displaying. Have tried alot of different things with the queue but nothing seems to help.
The ImageLoader class:
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.nopic;
public void DisplayImage(String url, Activity activity, ImageView imageView, ProgressBar progressBar)
{
if(cache.containsKey(url)){
imageView.setImageBitmap(cache.get(url));
if (progressBar != null){
progressBar.setVisibility(View.GONE);
imageView.setVisibility(View.VISIBLE);
}
}else{
queuePhoto(url, activity, imageView, progressBar);
if(progressBar != null){
imageView.setVisibility(View.GONE); //ADDED
progressBar.setVisibility(View.VISIBLE);
} else {
imageView.setImageResource(stub_id);
}
}
}
private void queuePhoto(String url, Activity activity, ImageView imageView, ProgressBar progressBar)
{
//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, progressBar);
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.
int requiredSize = 100;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<requiredSize || height_tmp/2<requiredSize)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
//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 ProgressBar progressBar;
public PhotoToLoad(String u, ImageView i, ProgressBar p){
url=u;
imageView=i;
progressBar = p;
}
}
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;
}
}
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// PHOTOSLOADER: Thread
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
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(); photosQueue.photosToLoad.remove(photoToLoad);
}
Bitmap bmp = getBitmap(photoToLoad.url);
cache.put(photoToLoad.url, bmp);
Object tag = photoToLoad.imageView.getTag();
if(tag != null && ((String)tag).equals(photoToLoad.url)){
BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad.imageView, photoToLoad.progressBar);
Activity a = (Activity)photoToLoad.imageView.getContext();
a.runOnUiThread(bd);
}
}
if(Thread.interrupted())
break;
}
} catch (InterruptedException e) {
//allow thread to exit
}
}
}
PhotosLoader photoLoaderThread = new PhotosLoader();
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// BITMAP DISPLAYER
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable{
Bitmap bitmap;
ImageView imageView;
ProgressBar progressBar;
public BitmapDisplayer(Bitmap b, ImageView i, ProgressBar p){
bitmap = b;
imageView = i;
progressBar = p;
}
public void run(){
if(bitmap != null){
imageView.setImageBitmap(bitmap);
if (progressBar != null){
imageView.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
}
}else{
if (progressBar != null){
progressBar.setVisibility(View.VISIBLE);
imageView.setVisibility(View.GONE);
}
}
}
}
public void clearCache() {
//clear memory cache
cache.clear();
//clear SD cache
File[] files = cacheDir.listFiles();
for(File f:files)
f.delete();
}
}
The Adapter:
public class Adapter_Agenda extends BaseAdapter {
// DEBUG
private final String TAG = this.getClass().getSimpleName();
private LayoutInflater inflater = null;
public ViewHolder holder;
private ArrayList<Agenda> agendas;
UnixTimeToStringConverter unixConverter;
ImageLoader imageLoader;
View vi;
public Adapter_Agenda(Context context, ArrayList<Agenda> agendas) {
this.agendas = agendas;
unixConverter = new UnixTimeToStringConverter();
imageLoader = new ImageLoader(context);
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
return agendas.size();
}
@Override
public Agenda getItem(int position) {
return agendas.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
vi = convertView;
if(convertView == null){
vi = inflater.inflate(R.layout.item_list_agenda, null);
holder = new ViewHolder();
holder.header = (TextView)vi.findViewById(R.id.item_list_header);
holder.image = (ImageView)vi.findViewById(R.id.item_list_image);
holder.time = (TextView)vi.findViewById(R.id.item_list_time);
holder.description = (TextView)vi.findViewById(R.id.item_list_description);
vi.setTag(holder);
holder = (ViewHolder)vi.getTag();
} else {
holder = (ViewHolder)vi.getTag();
}
holder.header.setText(agendas.get(position).getHeader());
imageLoader.DisplayImage(agendas.get(position).getImageURL(), activity, holder.image, null);
holder.time.setText(unixConverter.getUnixDateFormated(agendas.get(position).getStartTime()));
return vi;
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// VIEWHOLDER
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
public class ViewHolder{
public TextView time;
public ImageView image;
public TextView header;
public TextView description;
}
}
just put
holder.image.setTag(agendas.get(position).getImageURL());
before
imageLoader.DisplayImage(agendas.get(position).getImageURL(), activity, holder.image, null);
这篇关于ImageLoader的仅载入列表中的图像列表项已经关闭屏幕后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!