android

Android: Help in adapting ListView adapter with an ImageLoader Class (LazyList)

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();
    }

}

the custom list view adapter from the LazyList project:

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;
    }
}

and here’s my custom ListView adapter: ProjectAdapter class

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;
    }

}

UPDATED: ProjectList Activity

    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;
        }
    }



}

UPDATED Here’s my 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)

Main.java

public class Main extends Activity { /** Called when the activity is first created. */

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)

Similar Posts:

    None Found

Leave a Reply

Your email address will not be published. Required fields are marked *