Android: Ayuda en la adaptación del adaptador ListView con una clase ImageLoader (LazyList)

Tengo un adaptador ListView personalizado que implementa una clase ImageThreadLoader. Desafortunadamente, la clase no habilita una opción de caché, descarga las imágenes de la web y las guarda como caché.

Y luego encontré este LazyList o aquí realmente útil, se comporta lo mismo como mi clase ImageThreadLoader, pero es capaz de guardar las imágenes como caché. Por lo tanto, quiero implementar su clase ImageLoader a mi adaptador ListView personalizado actual.

Desafortunadamente la estructura de mis códigos y la de Lazylist es bastante diferente, resultando algunos conflictos en mis intentos. Por ejemplo, LazyList utiliza una matriz de cadenas para la URL de la imagen, en la otra mano uso JSON como fuente de la URL de la imagen.

Es por eso que necesito una ayuda aquí para adaptar mi adaptador ListView a esta clase ImageLoader.

Aquí están los códigos:

ImageLoader Clase que quiero implementar a mi adaptador ListView personalizado:

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(),"Android/data/LazyList"); else cacheDir=context.getCacheDir(); if(!cacheDir.exists()) cacheDir.mkdirs(); } final int stub_id=R.drawable.stub; 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*=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 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); Object tag=photoToLoad.imageView.getTag(); if(tag!=null && ((String)tag).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(); } } 

El adaptador de vista de lista personalizada del proyecto LazyList:

 public class LazyAdapter extends BaseAdapter { private Activity activity; private String[] data; private static LayoutInflater inflater=null; public ImageLoader imageLoader; public LazyAdapter(Activity a, String[] d) { activity = a; data=d; inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); imageLoader=new ImageLoader(activity.getApplicationContext()); } public int getCount() { return data.length; } public Object getItem(int position) { return position; } public long getItemId(int position) { return position; } public static class ViewHolder{ public TextView text; public ImageView image; } public View getView(int position, View convertView, ViewGroup parent) { View vi=convertView; ViewHolder holder; if(convertView==null){ vi = inflater.inflate(R.layout.item, null); holder=new ViewHolder(); holder.text=(TextView)vi.findViewById(R.id.text);; holder.image=(ImageView)vi.findViewById(R.id.image); vi.setTag(holder); } else holder=(ViewHolder)vi.getTag(); holder.text.setText("item "+position); holder.image.setTag(data[position]); imageLoader.DisplayImage(data[position], activity, holder.image); return vi; } } 

Y aquí está mi adaptador ListView personalizado: clase ProjectAdapter

 public class ProjectAdapter extends ArrayAdapter<Project> { int resource; String response; Context context; private final static String TAG = "MediaItemAdapter"; private ImageThreadLoader imageLoader = new ImageThreadLoader(); //Initialize adapter public ProjectAdapter(Context context, int resource, List<Project> items) { super(context, resource, items); this.resource=resource; } @Override public View getView(int position, View convertView, ViewGroup parent) { TextView textTitle; final ImageView image; Project pro = getItem(position); LinearLayout projectView; //Inflate the view if(convertView==null) { projectView = new LinearLayout(getContext()); String inflater = Context.LAYOUT_INFLATER_SERVICE; LayoutInflater vi; vi = (LayoutInflater)getContext().getSystemService(inflater); vi.inflate(resource, projectView, true); } else { projectView = (LinearLayout) convertView; } try { textTitle = (TextView)projectView.findViewById(R.id.txt_title); image = (ImageView)projectView.findViewById(R.id.image); } catch( ClassCastException e ) { Log.e(TAG, "Your layout must provide an image and a text view with ID's icon and text.", e); throw e; } Bitmap cachedImage = null; try { cachedImage = imageLoader.loadImage(pro.smallImageUrl, new ImageLoadedListener() { public void imageLoaded(Bitmap imageBitmap) { image.setImageBitmap(imageBitmap); notifyDataSetChanged(); } }); } catch (MalformedURLException e) { Log.e(TAG, "Bad remote image URL: " + pro.smallImageUrl, e); } textTitle.setText(pro.project_title); if( cachedImage != null ) { image.setImageBitmap(cachedImage); } return projectView; } } 

¡¡Muchas gracias!!

EDITAR

ACTUALIZADO: Actividad de ProjectList

  public class ProjectsList extends Activity { /** Called when the activity is first created. */ //ListView that will hold our items references back to main.xml ListView lstTest; //Array Adapter that will hold our ArrayList and display the items on the ListView ProjectAdapter arrayAdapter; ProgressDialog dialog; //List that will host our items and allow us to modify that array adapter ArrayList<Project> prjcts=null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.projects_list); //Initialize ListView lstTest= (ListView)findViewById(R.id.lstText); //Initialize our ArrayList prjcts = new ArrayList<Project>(); //Initialize our array adapter notice how it references the listitems.xml layout arrayAdapter = new ProjectAdapter(ProjectsList.this, R.layout.listitems,prjcts,ProjectsList.this); //Set the above adapter as the adapter of choice for our list lstTest.setAdapter(arrayAdapter); if (isOnline()) { //Instantiate the Web Service Class with he URL of the web service not that you must pass //WebService webService = new WebService("http://notalentrocks.com/myplaceapp/projects.json"); WebService webService = new WebService("http://liebenwald.spendino.net/admanager/dev/android/projects.json"); //Pass the parameters if needed , if not then pass dummy one as follows Map<String, String> params = new HashMap<String, String>(); params.put("var", ""); //Get JSON response from server the "" are where the method name would normally go if needed example // webService.webGet("getMoreAllerts", params); String response = webService.webGet("", params); try { dialog = ProgressDialog.show(ProjectsList.this, "", "Fetching Projects...", true); dialog.setCancelable(true); dialog.setCanceledOnTouchOutside(true); dialog.setOnCancelListener(new OnCancelListener() { public void onCancel(DialogInterface dialog) { } }); //Parse Response into our object Type collectionType = new TypeToken<ArrayList<Project>>(){}.getType(); //JSON expects an list so can't use our ArrayList from the lstart List<Project> lst= new Gson().fromJson(response, collectionType); //Now that we have that list lets add it to the ArrayList which will hold our items. for(Project l : lst) { prjcts.add(l); ConstantData.projectsList.add(l); } //Since we've modified the arrayList we now need to notify the adapter that //its data has changed so that it updates the UI arrayAdapter.notifyDataSetChanged(); dialog.dismiss(); } catch(Exception e) { Log.d("Error: ", e.getMessage()); } } lstTest.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Intent care = new Intent(ProjectsList.this, ProjectDetail.class); care.putExtra("spendino.de.ProjectDetail.position",position); startActivity(care); } }); } protected boolean isOnline() { ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo netInfo = cm.getActiveNetworkInfo(); if (netInfo != null && netInfo.isConnected()) { return true; } else { AlertDialog.Builder alertbox = new AlertDialog.Builder(this); alertbox.setTitle("spendino Helfomat"); alertbox.setMessage ("Please check your internet connection"); alertbox.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { //Main.this.finish(); } }); alertbox.show(); return false; } } } 

ACTUALIZADO Aquí está mi stacktrace:

 05-12 11:36:52.670: ERROR/AndroidRuntime(299): Caused by: java.lang.NullPointerException 05-12 11:36:52.670: ERROR/AndroidRuntime(299): at android.content.ContextWrapper.getCacheDir(ContextWrapper.java:183) 05-12 11:38:29.386: ERROR/AndroidRuntime(324): at spendino.de.ImageLoader.<init>(ImageLoader.java:41) 05-12 11:36:52.670: ERROR/AndroidRuntime(299): at spendino.de.Main.<init>(Main.java:56) 

ImageLoader 41 es: cacheDir=context.getCacheDir(); Main 56 es: private ImageLoaderCache imageLoader = new ImageLoaderCache(Main.this);

Main.java

Public class Main extends Actividad {/ ** Se llama cuando se crea la actividad por primera vez. * /

 ArrayList<Project> prjcts=null; private final static String TAG = "MediaItemAdapter"; ImageLoader imageLoader; private Activity activity; ImageView image1; ImageView image2; ImageView image3; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); if (isOnline()) { prjcts = new ArrayList<Project>(); WebService webService = new WebService("http://liebenwald.spendino.net/admanager/dev/android/projects.json"); Map<String, String> params = new HashMap<String, String>(); params.put("var", ""); String response = webService.webGet("", params); imageLoader = new ImageLoader(Main.this); try { Type collectionType = new TypeToken<ArrayList<Project>>(){}.getType(); List<Project> lst= new Gson().fromJson(response, collectionType); for(Project l : lst) { prjcts.add(l); ConstantData.projectsList.add(l); } } catch(Exception e) { Log.d("Error: ", e.getMessage()); } try { image1 = (ImageView)findViewById(R.id.top1); image2 = (ImageView)findViewById(R.id.top2); image3 = (ImageView)findViewById(R.id.top3); } catch( ClassCastException e ) { Log.e(TAG, "Your layout must provide an image and a text view with ID's icon and text.", e); throw e; } //randomize the index of image entry int max = prjcts.size(); List<Integer> indices = new ArrayList<Integer>(max); for(int c = 1; c < max; ++c) { indices.add(c); } Random r = new Random(); int arrIndex = r.nextInt(indices.size()); int randomIndex1 = indices.get(arrIndex); indices.remove(arrIndex); int arrIndex2 = r.nextInt(indices.size()); int randomIndex2 = indices.get(arrIndex2); indices.remove(arrIndex2); int arrIndex3 = r.nextInt(indices.size()); int randomIndex3 = indices.get(arrIndex3); indices.remove(arrIndex3); imageLazy(image1, prjcts.get(randomIndex1)); imageLazy(image2, prjcts.get(randomIndex2)); imageLazy(image3, prjcts.get(randomIndex3)); image1.setOnClickListener(new RandomClickListener(randomIndex1)); image2.setOnClickListener(new RandomClickListener(randomIndex2)); image3.setOnClickListener(new RandomClickListener(randomIndex3)); } final Button project = (Button) findViewById(R.id.btn_projectslist); final Button infos = (Button) findViewById(R.id.btn_infos); final Button contact = (Button) findViewById(R.id.btn_contact); project.setOnClickListener(project_listener); infos.setOnClickListener(infos_listener); contact.setOnClickListener(contact_listener); } /* * isOnline - Check if there is a NetworkConnection * @return boolean */ protected boolean isOnline() { ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo netInfo = cm.getActiveNetworkInfo(); if (netInfo != null && netInfo.isConnected()) { return true; } else { AlertDialog.Builder alertbox = new AlertDialog.Builder(this); alertbox.setTitle("spendino Helfomat"); alertbox.setMessage ("Bitte überprüfen Sie Ihre Internetverbindung"); alertbox.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { Main.this.finish(); } }); alertbox.show(); return false; } } public static class ViewHolder{ public ImageView image; } public void imageLazy(final ImageView image,Project pro) { imageLoadery.displayImage(pro.smallImageUrl, activity, image); } public void setImage(Bitmap cachedImage, final ImageView image, Project pro) { try { cachedImage = imageLoader.loadImage(pro.smallImageUrl, new ImageLoadedListener() { public void imageLoaded(Bitmap imageBitmap) { image.setImageBitmap(imageBitmap); } }); } catch (MalformedURLException e) { Log.e(TAG, "Bad remote image URL: " + pro.smallImageUrl, e); } if( cachedImage != null ) { image.setImageBitmap(cachedImage); } } public class RandomClickListener implements View.OnClickListener { private final int randomIndex; public RandomClickListener(final int randomIndex) { this.randomIndex = randomIndex; } @Override public void onClick(View v) { Intent top = new Intent(Main.this, ProjectDetail.class); top.putExtra("spendino.de.ProjectDetail.position", randomIndex); startActivity(top); } } 

Stacktrace:

 05-12 13:48:12.606: ERROR/AndroidRuntime(433): at spendino.de.ImageLoaderCache$PhotosLoader.run(ImageLoaderCache.java:244) 

Parece que no usaste ningún titular de vista en tu adaptador

He hecho cambios en tus clases. Espero que funcione para ti sin ninguna dificultad

La clase ImageThreadLoader

  import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; 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.widget.ImageView; public class ImageThreadLoader { //the simplest in-memory cache implementation. This should be replaced with something like SoftReference or BitmapOptions.inPurgeable(since 1.6) /** The cache. */ private HashMap<String, Bitmap> cache=new HashMap<String, Bitmap>(); /** The cache dir. */ private File cacheDir; /** * Instantiates a new image loader. * * @param context the context */ public ImageThreadLoader(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(),"cache_dir_img"); else cacheDir=context.getCacheDir(); if(!cacheDir.exists()) cacheDir.mkdirs(); } //This is used for a stub when the user can not see the actual image.. //this images will be seen final int stub_id =R.drawable.sample_image; /** * Display image. * * @param url the url * @param activity the activity * @param imageView the image view */ 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); } } /** * Queue photo. * * @param url the url * @param activity the activity * @param imageView the image view */ 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(); } /** * Gets the bitmap. * * @param url the url * @return the bitmap */ 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); 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 /** * Decode file. * * @param f the f * @return the bitmap */ 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 /** * The Class PhotoToLoad. */ private class PhotoToLoad { /** The url. */ public String url; /** The image view. */ public ImageView imageView; /** * Instantiates a new photo to load. * * @param u the u * @param i the i */ public PhotoToLoad(String u, ImageView i){ url=u; imageView=i; } } /** The photos queue. */ PhotosQueue photosQueue=new PhotosQueue(); /** * Stop thread. */ public void stopThread() { photoLoaderThread.interrupt(); } //stores list of photos to download /** * The Class PhotosQueue. */ class PhotosQueue { /** The photos to load. */ private Stack<PhotoToLoad> photosToLoad=new Stack<PhotoToLoad>(); //removes all instances of this ImageView /** * Clean. * * @param image the image */ public void Clean(ImageView image) { for(int j=0 ;j<photosToLoad.size();){ if(photosToLoad.get(j).imageView==image) photosToLoad.remove(j); else ++j; } } } /** * The Class PhotosLoader. */ class PhotosLoader extends Thread { /* (non-Javadoc) * @see java.lang.Thread#run() */ 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 } } } /** The photo loader thread. */ PhotosLoader photoLoaderThread=new PhotosLoader(); //Used to display bitmap in the UI thread /** * The Class BitmapDisplayer. */ class BitmapDisplayer implements Runnable { /** The bitmap. */ Bitmap bitmap; /** The image view. */ ImageView imageView; /** * Instantiates a new bitmap displayer. * * @param b the b * @param i the i */ public BitmapDisplayer(Bitmap b, ImageView i){bitmap=b;imageView=i;} /* (non-Javadoc) * @see java.lang.Runnable#run() */ public void run() { if(bitmap!=null) imageView.setImageBitmap(bitmap); else imageView.setImageResource(stub_id); } } /** * Clear cache. */ public void clearCache() { //clear memory cache cache.clear(); //clear SD cache File[] files=cacheDir.listFiles(); for(File f:files) f.delete(); } public static void copyStream(InputStream is, OutputStream os) { final int buffer_size=1024; try { byte[] bytes=new byte[buffer_size]; for(;;) { int count=is.read(bytes, 0, buffer_size); if(count==-1) break; os.write(bytes, 0, count); } } catch(Exception ex){} } } 

Ahora su clase ProjectAdapter

 import java.util.List; import android.app.Activity; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; public class ProjectAdapter extends ArrayAdapter<Project> { int resource; String response; Context context; List<Project> items; private ImageThreadLoader imageLoader; LayoutInflater mInflater; Activity activity; // Initialize adapter public ProjectAdapter(Context context, int resource, List<Project> items, Activity activity) { super(context, resource, items); this.resource = resource; imageLoader = new ImageThreadLoader(context); this.items = items; mInflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); this.activity = activity; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; // Inflate the view if (convertView == null) { convertView = mInflater.inflate(resource, null); holder = new ViewHolder(); holder.image = (ImageView) convertView.findViewById(R.id.image); holder.textTitle = (TextView) convertView .findViewById(R.id.txt_title); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } Project project = items.get(position); holder.textTitle.setText(project.project_title); String imageurl = project.smallImageUrl; holder.image.setTag(imageurl); imageLoader.displayImage(imageurl, activity, holder.image); return convertView; } static class ViewHolder { TextView textTitle; ImageView image; } 

Y por último, cuando se establece el adaptador en su ListView después de obtener los datos web, utilice este

 your_listview.setAdapter(your_ProjectAdapter_instance ); your_ProjectAdapter_instance .notifyDataSetChanged(); 

Tengo el eproblema sam de diferentes tipos de datos distintos de la matriz de cadenas, pero estoy usando Arraylist (pero no JASON) por lo que hacer cambios en el código de Fedor y por debajo de mi aplicación, espero que esta ayuda

LazyAdapter

 public LazyAdapter(Activity a, ArrayList<?> mStatus) { activity = a; data = mStatus; inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); imageLoader = new ImageLoader(activity.getApplicationContext()); } public int getCount() { if(data != null && data.size() > 15) return data.size(); else return 15; } 

He encontrado que incluso si los archivos en sdcard no carga porque su comprobación de que el objeto que va nulo si se cambia la actividad en la que la lista se implementa por lo que cambió getBitmap() código también ImageLoader

 private Bitmap getBitmap(String urlString) { String filename = String.valueOf(urlString.substring(urlString.lastIndexOf("/") + 1)); File f = new File(cacheDir, filename); try { if(!f.exists()) { Bitmap bitmap = null; InputStream is = new URL(urlString).openStream(); OutputStream os = new FileOutputStream(f); Globals.CopyStream(is, os); os.close(); bitmap = decodeFile(f); return bitmap; } else { Bitmap bitmap = decodeFile(f); return bitmap; } } catch (Exception ex) { ex.printStackTrace(); BitmapDrawable mDrawable = (BitmapDrawable) context.getResources().getDrawable(R.drawable.placeholder); return mDrawable.getBitmap(); } } 

El miembro de Stackoverflow Fedor publicó alguna fuente para un ImageLoader en caché en respuesta a esta pregunta. Android – ¿Cómo hago una carga perezosa de imágenes en ListView? La fuente es aquí fuente . Su respuesta consiguió 100+ upvotes. Me pareció que funcionó muy bien el almacenamiento en caché de imágenes de Flickr mío. Usted debe ser capaz de adaptarlo para su uso.

No ha configurado la etiqueta de imagen cuando envía a la clase de cargador lento.

  Bitmap cachedImage = null; try { cachedImage = imageLoader.loadImage(pro.smallImageUrl, new ImageLoadedListener() { public void imageLoaded(Bitmap imageBitmap) { image.setImageBitmap(imageBitmap); notifyDataSetChanged(); } }); } catch (MalformedURLException e) { Log.e(TAG, "Bad remote image URL: " + pro.smallImageUrl, e); } 

Qué es privado ImageThreadLoader imageLoader = new ImageThreadLoader (); ? ¿Puedo ver esa clase?

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.