I'm tryin to get encrypted files from assets folder,decrypt it in application and show it as a content in list view.I'm using a well known Fedor's Lazy List Loading implementation.As you can see, I changed his getBitmap method with my own method :
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();
}
//MY METHOD
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();
}
}
.....but the problem is that I'm getting this Exception :
08-11 11:11:45.293: WARN/System.err(1073): java.lang.NullPointerException
08-11 11:11:45.293: WARN/System.err(1073): at android.content.ContextWrapper.getAssets(ContextWrapper.java:74)
08-11 11:11:45.293: WARN/System.err(1073): at com.custom.lazylist.ImageLoader.getBitmap(ImageLoader.java:79)
08-11 11:11:45.293: WARN/System.err(1073): at com.custom.lazylist.ImageLoader.access$0(ImageLoader.java:70)
08-11 11:11:45.293: WARN/System.err(1073): at com.custom.lazylist.ImageLoader$PhotosLoader.run(ImageLoader.java:200)
this is how I use LazyAdapter in my main class :
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
list=(ListView)findViewById(R.id.list);
adapter=new LazyAdapter(this, mStrings);
list.setAdapter(adapter);
list.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> a, View v, int position, long id)
{
Intent i = new Intent(v.getContext(), Cards.class);
startActivity(i);
}
});
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(listener);
/* adapter.imageLoader.clearCache();
adapter.notifyDataSetChanged();*/
}
@Override
public void onDestroy()
{
adapter.imageLoader.stopThread();
list.setAdapter(null);
super.onDestroy();
}
public OnClickListener listener=new OnClickListener(){
@Override
public void onClick(View arg0) {
adapter.imageLoader.clearCache();
adapter.notifyDataSetChanged();
}
};
private String[] mStrings={
"card1_encrypted.jpg",
"card1_encrypted.jpg",
"card2_encrypted.jpg",
"card1_encrypted.jpg",
"card3_encrypted.jpg",
"card1_encrypted.jpg",
"card1_encrypted.jpg",
"card3_encrypted.jpg",
"card3_encrypted.jpg",
"card2_encrypted.jpg",
"card4_encrypted.jpg",
"card5_encrypted.jpg",
"card3_encrypted.jpg",
"card2_encrypted.jpg",
"card5_encrypted.jpg",
"card1_encrypted.jpg"
};
So any ideas how to fix that?An last thing: at line 79 I have this:
AssetManager is = this.getAssets();
Thanks in advance!
If the first class is not really an activity, doen't extend activity just to use this.getAssets()
, pass the context (i.e. your activity) when instantiating the class, and use this instance to call getAssets()
You need an onCreate() method.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AssetManager am = getAssets();//this should not get a nullpointerexception
}
Or do the following:
In your Activity (whichever one calls image loader) write this:
ImageLoader il = new ImageLoader(this);//this being the context.
Then in your ImageLoader class you can use
AssetManager am = context.getAssets();//context being the activity which called this class.
精彩评论