开发者

Lazy Loading List - need a little help here

So basically everyone at one point needs to do this,load some images from web or cache to a listview.I find a really good example of Lazy List by Fedor and I'm trying to make it to do what I need,but I have some problems with it.The images in my case are encrypted.So I need to encrypt them on the device and show them in a listview.For now I got this code :

private Bitmap getBitmap(String src) {
    Bitmap myBitmap = null;
        try {

            //Decryption
            try {
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec keySpec = new SecretKeySpec("01234567890abcde".getBytes(), "AES");
            IvParameterSpec ivSpec = new IvParameterSpec("fedcba9876543210".getBytes());
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

            AssetManager is = this.getAssets();        
            InputStream input = is.open(src); //open file in asset manager
            CipherInputStream cis = new CipherInputStream(input, cipher);

            myBitmap = BitmapFactory.decodeStream(cis);

            }
            catch(Exception e){
                e.printStackTrace();
                Log.v("ERROR","Error : "+e);
            }


            return myBitmap;


        } catch (IOException e) {
            e.printStackTrace();
            Log.v("ERROR","Error : "+e);

            return null;
        }
    }

As I know,it's not correct (I can't understand why,that's why I need help).Here is the Exception that I get :

08-11 13:38:51.163: WARN/System.err(4731): java.lang.NullPointerException
08-11 13:38:51.163: WARN/System.err(4731):     at android.content.ContextWrapper.getAssets(ContextWrapper.java:74)
08-11 13:38:51.163: WARN/System.err(4731):     at com.custom.lazylist.ImageLoader.getBitmap(ImageLoader.java:79)
08-11 13:38:51.163: WARN/System.err(4731):     at com.custom.lazylist.ImageLoader.access$0(ImageLoader.java:70)
08-11 13:38:51.163: WARN/System.err(4731):     at com.custom.lazylist.ImageLoader$PhotosLoader.run(ImageLoader.java:200)

and here is the whole code of ImageLoader class :

package com.custom.lazylist;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Stack;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import com.fedorvlasov.lazylist.R;
import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.widget.ImageView;

public class ImageLoader extends Activity {

    //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.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 src) {
        Bitmap myBitmap = null;
            //Decryption
            try {
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec keySpec = new SecretKeySpec("01234567890abcde".getBytes(), "AES");
            IvParameterSpec ivSpec = new IvParameterSpec("fedcba9876543210".getBytes());
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

            AssetManager is = this.getAssets();        
            InputStream input = is.open(src); //open file in asset manager
            CipherInputStream cis = new CipherInputStream(input, cipher);

            myBitmap = BitmapFactory.decodeStream(cis);

            }
            catch(Exception e){
                e.printStackTrace();
                Log.v("ERROR","Error : "+e);
            }


            return myBitmap;
        }

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



}

Hope someone can help me to fix this,cuz I really wanna understand how to use Lazy Loading List.

P.S. Actually I realize that I'm extending Activity without Overriding onCreate,but this is the only way to do this : AssetManager is = is.getAssets();. Otherwise if I remov extend I'ts showing me an error : The method getAssets() is undefined for the type ImageLoader


There are two things wrong:

  1. If ImageLoader isn't an Activity then you shouldn't extend Activity (as you acknowledged). Every time you find yourself needing to extend Activity in an object that shouldn't be an activity you need a Context. Usually it's sufficient to save off context as a member variable private Context mContext; and then change the line you're having problems with to AssetManager is = this.mContext.getAssets().
  2. That is not going to work in your case. You need to either use AsyncTask or turn your ImageLoader into a Service. The problem is you need the Context in your background thread. But, if the Activity that created the ImageLoader (and hence background thread) goes away, mContext may not be a valid context when your background thread makes the call to getAssetManager(). If you turn it into a Service, then your service will be a valid Context and provide you with access to your asset manager.

The exact steps to creating a service are outside the scope of this answer, but you can start at the Android documentation on services and go from there: http://developer.android.com/guide/topics/fundamentals/services.html

EDIT: Code to back up comment (below)

...

// ***** ADDITION *****
private AssetManager mAssetManager;

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);
    // ***** ADDITION *****
    mAssetManager = context.getAssets();

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

private Bitmap getBitmap(String src) {
    Bitmap myBitmap = null;
        //Decryption
        try {
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        SecretKeySpec keySpec = new SecretKeySpec("01234567890abcde".getBytes(), "AES");
        IvParameterSpec ivSpec = new IvParameterSpec("fedcba9876543210".getBytes());
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

        // ***** CHANGE *****
        InputStream input = mAssetManager.open(src); //open file in asset manager
        CipherInputStream cis = new CipherInputStream(input, cipher);

        myBitmap = BitmapFactory.decodeStream(cis);

        }
        catch(Exception e){
            e.printStackTrace();
            Log.v("ERROR","Error : "+e);
        }


        return myBitmap;
    }
....
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜