안녕하세요.
회사에서 돈주고 만든 앱보면 리스트 뿌려주는데 속도가 완전 빠릅니다.
제가 준비해서 2탄은 제가 해야하는 입장인데....... 동기화 처리 소스 삽입을해도 이미지 리스트뷰를 열면 속도가 너무 느립니다.
ImageLoader, Utils 클레스는 제가 만든것은 아니고 인터넷에 돌아다니는 소스 입니다....
제가 안드로이드 경험이 없고 자바 지식도 얇아서........ 속도차이가 너무 큽니다.......
저희는 100% 서버단의 XML을 파싱해서 뿌려주는게 전부입니다.
어뎁터를 만들때 제 알고리즘이 이상한건지.......... 지적 부탁 드리겠습니다.......... 감사합니다.
어뎁터 소스 ****************************************************
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) convertView = inflater.inflate(layoutId, parent, false);
dateData = dateDatas.get(position);
try {
URL url = new URL(dateData.getImgSrc());
conn = (HttpURLConnection)url.openConnection();
if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){
stream = conn.getInputStream();
image = BitmapFactory.decodeStream(stream);
if(image != null){
ImageView picture = (ImageView)convertView.findViewById(R.id.date_list_list_image);
// ((ImageView)convertView.findViewById(R.id.date_list_list_image)).setImageBitmap(image);
imageLoader.DisplayImage(dateDatas.get(position).getImgSrc(), (Activity)context, picture);
}
}
} catch (MalformedURLException e) {
}catch (IOException e) {
}
// 비동기 방식으로 Image Loading
((TextView)convertView.findViewById(R.id.date_list_list_datename)).setText(dateData.getDateName());
((TextView)convertView.findViewById(R.id.date_list_list_datename_content)).setText(dateData.getThemeName());
return convertView;
}
ImageLoader ********************************************************
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.*;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;
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.btn_star;
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();
}
}
Utils **************************************
import java.io.InputStream;
import java.io.OutputStream;
public class Utils {
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){}
}
}




소스를 다보진 않았지만 대충보니 제가 비슷한 이유로 애먹은 기억이 있네요.
제기억엔 이 소스에서 캐시 부분이 제대로 작동을 안한것 같아요. 그래서 캐시를 따로 써서 해결했거든요.
이유는 잘 모르겠습니다. 분석할 만큼 시간적 여유가 있지 않았기 때문에..ㅎㅎㅎ
결론은, 캐시만 해결하면 괜찮을거에요.