로 컬 앨범 그림 을 효율적으로 불 러 오 는 ImageLoader 클래스
17133 단어 그림.
1.Lru 알고리즘 을 사용 하여 그림 을 캐 시 하여 유창 성 을 확보 하고 OOM 을 피한다.
2.이미지 로드 는 반드시 비동기 적 으로 진행 되 어야 합 니 다.그러면 다 중 스 레 드 의 병행 과 관련 되 고 스 레 드 탱크 를 사용 하여 작업 을 스케줄 링 합 니 다.
3.안 드 로 이 드 내부 의 비동기 메시지 메커니즘 Looper+Handler 를 사용 하여 taskQueue 에 대해 폴 링 을 수행 합 니 다.
1.이미지 로 더,task 작업 열 이 자주 호출 되 기 때문에 하나의 예 모드 로 이미지 로 더 류 를 만 들 고 필요 한 구성원 변 수 를 설명 합 니 다.
/**
* @author Administrator
* ,task ,
*/
public class ImageLoader {
private static ImageLoader instance;
/**
*
*/
private LruCache<String, Bitmap> mLruCache;
/**
*
*/
private ExecutorService mThreadPool;
private static final int DEFAULT_THREAD_COUNT=1;
/**
*
*/
private static Type mType=Type.LIFO;
/**
*
*/
private LinkedList<Runnable> mTaskQueue;
/**
*
*/
private Thread mPoolThread;
private Handler mPoolThreadHandler;
/**
*UI Handler
*/
private Handler mUIHandler;
//
public enum Type{
FIFO,LIFO;
}
/**
* ImageLoader
* @return
*/
public static ImageLoader getInstance(){
// if ,
// ,
//
if(instance==null){
synchronized (ImageLoader.class) {
if(instance==null){
instance=new ImageLoader(DEFAULT_THREAD_COUNT,mType);
}
}
}
return instance;
}
2.멤버 변수 초기 화
private ImageLoader(int threadCount,Type type){
init(threadCount,type);
}
private Semaphore mSemaphorePoolThreadHandler=new Semaphore(0);
private Semaphore mSemaphoreThreadPool;
/**
*
* @param threadCount
* @param type
*/
private void init(int threadCount,Type type) {
//
mPoolThread=new Thread(){
@Override
public void run() {
Looper.prepare();// mtaskQueue
mPoolThreadHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
//
mThreadPool.execute(getTask());
}
};
mSemaphorePoolThreadHandler.release();//handler ,
Looper.loop();
}
};
//
mPoolThread.start();
mTaskQueue=new LinkedList<Runnable>();//
mThreadPool=Executors.newFixedThreadPool(threadCount);//
int maxSize=(int) Runtime.getRuntime().maxMemory();
int cacheSize=maxSize/8;
mLruCache=new LruCache<String, Bitmap>(cacheSize){
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes()*value.getHeight();
}
};
mType=type;
mSemaphoreThreadPool=new Semaphore(threadCount);
}
3.작성 및 새로운 방법 loadImage()
/**
*
* @param path
* @param imageView
*/
public void loadImage(final String path,final ImageView imageView){
imageView.setTag(path);// ,
mUIHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
ImageHolder holder=(ImageHolder) msg.obj;
Bitmap bitmap=holder.mBitmap;
ImageView imageView=holder.mImageView;
String url=holder.path;
if(imageView.getTag().toString().equals(url)){
imageView.setImageBitmap(bitmap);
}
}
};
Bitmap mBitmap=getBitmapFromLruCache(path);
if(mBitmap!=null){
refreshHandler(path, imageView, mBitmap);
}
else{
addTask(imageView,path);
}
}
private void addTask(final ImageView imageView,final String path) {
mTaskQueue.add(new Runnable() {
@Override
public void run() {
//
//1. ImageView
ImageSize imageSize = getImageSize(imageView);
//2.
Bitmap mBitmap = compressBitmap(imageSize,path);
//3. LruCache
if(mLruCache.get(path)!=null){
mLruCache.put(path, mBitmap);
}
// , UiHandler imageview
refreshHandler(path, imageView, mBitmap);
// , ,
mSemaphoreThreadPool.release();
}
});
try {
if(mPoolThreadHandler==null){
mSemaphorePoolThreadHandler.acquire();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
// ,
mPoolThreadHandler.sendEmptyMessage(0X110);
}
/**
* ImageView path Bitmap handler
* @param path
* @param imageView
* @param mBitmap
*/
private void refreshHandler(final String path, final ImageView imageView, Bitmap mBitmap) {
Message message=Message.obtain();
ImageHolder holder=new ImageHolder();
holder.mBitmap=mBitmap;
holder.mImageView=imageView;
holder.path=path;
message.obj=holder;
mUIHandler.sendMessage(message);
}
/**
*
* @return
*/
private Bitmap compressBitmap(ImageSize imageSize,String path){
BitmapFactory.Options option=new BitmapFactory.Options();
option.inJustDecodeBounds=true;// ,
BitmapFactory.decodeFile(path, option);
int outWidth = option.outWidth;
int outHeight = option.outHeight;
int width=imageSize.width;
int height=imageSize.height;
int inSimpleSize=1;
if(outHeight>height||outWidth>height){
int widthRadio=Math.round(outWidth*1.0f/width);
int heightRadio=Math.round(outHeight*1.0f/height);
inSimpleSize=Math.max(widthRadio, heightRadio);
}
option.inJustDecodeBounds=false;
option.inSampleSize=inSimpleSize;
return BitmapFactory.decodeFile(path, option);
}
/**
* ImageView
* @param iv
* @return
*/
private ImageSize getImageSize(ImageView iv){
LayoutParams lp = iv.getLayoutParams();
//
DisplayMetrics dm = iv.getContext().getResources().getDisplayMetrics();
int width=iv.getWidth();
if(width<=0){
width=lp.width;
}
if(width<=0){
// ImageView MaxWidth MaxHeight
width=getMaxValueFromInvoke(iv,"mMaxWidth");
}
if(width<=0){
width=dm.widthPixels;
}
int height=iv.getHeight();
if(height<=0){
height=lp.width;
}
if(height<=0){
height=getMaxValueFromInvoke(iv,"mMaxHeight");
}
if(height<=0){
height=dm.heightPixels;
}
return new ImageSize(width, height);
}
/**
* ImageView MaxWidth MaxHeight
* @param obj
* @param fieldName
* @return
*/
private int getMaxValueFromInvoke(Object obj,String fieldName){
int value=0;
try {
Field field = ImageView.class.getDeclaredField(fieldName);
field.setAccessible(true);
int fieldValue = field.getInt(obj);
if(fieldValue>0&&fieldValue<Integer.MAX_VALUE){
value=fieldValue;
}
} catch (Exception e) {
e.printStackTrace();
}
return value;
}
/**
*
* @author Administrator
*
*/
private class ImageSize{
int width;
int height;
public ImageSize(int width,int height){
this.width=width;
this.height=height;
}
}
//handler msg.obj
private class ImageHolder{
Bitmap mBitmap;
ImageView mImageView;
String path;
}
//
private Bitmap getBitmapFromLruCache(String key) {
return mLruCache.get(key);
}
ImageView 의 최대 너비 와 높이 를 가 져 올 때 낮은 버 전 을 호 환 하기 위해 getMaxWidth()라 는 api 를 사용 하지 않 고 반사 적 으로 가 져 온 것 입 니 다.
그 중에서 배경 폴 링 스 레 드 가 mThreadPoolHandler 를 초기 화하 지 않 았 을 때 mThreadPoolHandler 는 loadImage()방법 에서 호출 될 수 있 기 때문에 빈 포인터 의 위험 이 존재 합 니 다.
병발 위험 을 확보 하기 위해 자바 가 제공 하 는 병발 신 호 량 의 클래스 Semaphore 초기 화 할 때 구조 방법 에 몇 개의 허가증 을 지정 합 니 다.
두 가지 방법 이 있다.
1.acquire()는 실행 할 때마다 하나의 허가증 을 소모 하지만 허가증 이 0 일 때 스 레 드 를 차단 합 니 다.Semaphore 까지. release()를 다시 호출 하여 허가증 을 얻 고 차단 을 끝 냅 니 다.
2.release()를 실행 할 때마다 허가증 을 받 습 니 다.
다음은 제 가 모든 종류의 코드 를 다 붙 여 드릴 게 요.
package com.example.fandayimageloader.imageloader;
import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.util.DisplayMetrics;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
/**
* mPoolThreadHandler , addTask mTaskQueue , null painter exception
* java Semaphore, 。 , 。 , acquire(),
* 。 release() , 。 , ,Semaphore ,
* 。 , 。 acquire() release() 。
* acquire() , release() , 0 , acquire()
* public class SemaphoreTest {
*
* public static void main(String[] args) {
* //
* ExecutorService exec = Executors.newCachedThreadPool();
* // 5
* final Semaphore semp = new Semaphore(5);
* // 20
* for (int index = 0; index < 20; index++) {
* final int NO = index;
* Runnable run = new Runnable() {
* public void run() {
* try {
* //
* semp.acquire();
* System.out.println("Accessing: " + NO);
* Thread.sleep((long) (Math.random() * 10000));
* // , , , 5 ,
* semp.release();
* } catch (InterruptedException e) {
* }
* }
* };
* exec.execute(run);
* }
* //
* exec.shutdown();
* }
* }
*/
/**
* @author Administrator
* ,task ,
*/
public class ImageLoader {
private static ImageLoader instance;
/**
*
*/
private LruCache<String, Bitmap> mLruCache;
/**
*
*/
private ExecutorService mThreadPool;
private static final int DEFAULT_THREAD_COUNT=1;
/**
*
*/
private static Type mType=Type.LIFO;
/**
*
*/
private LinkedList<Runnable> mTaskQueue;
/**
*
*/
private Thread mPoolThread;
private Handler mPoolThreadHandler;
/**
*UI Handler
*/
private Handler mUIHandler;
//
public enum Type{
FIFO,LIFO;
}
/**
* ImageLoader
* @return
*/
public static ImageLoader getInstance(){
// if ,
// ,
//
if(instance==null){
synchronized (ImageLoader.class) {
if(instance==null){
instance=new ImageLoader(DEFAULT_THREAD_COUNT,mType);
}
}
}
return instance;
}
private ImageLoader(int threadCount,Type type){
init(threadCount,type);
}
private Semaphore mSemaphorePoolThreadHandler=new Semaphore(0);
private Semaphore mSemaphoreThreadPool;
/**
*
* @param threadCount
* @param type
*/
private void init(int threadCount,Type type) {
//
mPoolThread=new Thread(){
@Override
public void run() {
Looper.prepare();// mtaskQueue
mPoolThreadHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
//
mThreadPool.execute(getTask());
}
};
mSemaphorePoolThreadHandler.release();//handler ,
Looper.loop();
}
};
//
mPoolThread.start();
mTaskQueue=new LinkedList<Runnable>();//
mThreadPool=Executors.newFixedThreadPool(threadCount);//
int maxSize=(int) Runtime.getRuntime().maxMemory();
int cacheSize=maxSize/8;
mLruCache=new LruCache<String, Bitmap>(cacheSize){
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes()*value.getHeight();
}
};
mType=type;
mSemaphoreThreadPool=new Semaphore(threadCount);
}
/**
* Type
* @return
*/
public Runnable getTask(){
try {
// , ,
mSemaphoreThreadPool.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
if(mType==Type.FIFO){
return mTaskQueue.removeFirst();
}
else if(mType==Type.LIFO){
return mTaskQueue.removeLast();
}
return null;
}
/**
*
* @param path
* @param imageView
*/
public void loadImage(final String path,final ImageView imageView){
imageView.setTag(path);// ,
mUIHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
ImageHolder holder=(ImageHolder) msg.obj;
Bitmap bitmap=holder.mBitmap;
ImageView imageView=holder.mImageView;
String url=holder.path;
if(imageView.getTag().toString().equals(url)){
imageView.setImageBitmap(bitmap);
}
}
};
Bitmap mBitmap=getBitmapFromLruCache(path);
if(mBitmap!=null){
refreshHandler(path, imageView, mBitmap);
}
else{
addTask(imageView,path);
}
}
private void addTask(final ImageView imageView,final String path) {
mTaskQueue.add(new Runnable() {
@Override
public void run() {
//
//1. ImageView
ImageSize imageSize = getImageSize(imageView);
//2.
Bitmap mBitmap = compressBitmap(imageSize,path);
//3. LruCache
if(mLruCache.get(path)!=null){
mLruCache.put(path, mBitmap);
}
// , UiHandler imageview
refreshHandler(path, imageView, mBitmap);
// , ,
mSemaphoreThreadPool.release();
}
});
try {
if(mPoolThreadHandler==null){
mSemaphorePoolThreadHandler.acquire();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
// ,
mPoolThreadHandler.sendEmptyMessage(0X110);
}
/**
* ImageView path Bitmap handler
* @param path
* @param imageView
* @param mBitmap
*/
private void refreshHandler(final String path, final ImageView imageView, Bitmap mBitmap) {
Message message=Message.obtain();
ImageHolder holder=new ImageHolder();
holder.mBitmap=mBitmap;
holder.mImageView=imageView;
holder.path=path;
message.obj=holder;
mUIHandler.sendMessage(message);
}
/**
*
* @return
*/
private Bitmap compressBitmap(ImageSize imageSize,String path){
BitmapFactory.Options option=new BitmapFactory.Options();
option.inJustDecodeBounds=true;// ,
BitmapFactory.decodeFile(path, option);
int outWidth = option.outWidth;
int outHeight = option.outHeight;
int width=imageSize.width;
int height=imageSize.height;
int inSimpleSize=1;
if(outHeight>height||outWidth>height){
int widthRadio=Math.round(outWidth*1.0f/width);
int heightRadio=Math.round(outHeight*1.0f/height);
inSimpleSize=Math.max(widthRadio, heightRadio);
}
option.inJustDecodeBounds=false;
option.inSampleSize=inSimpleSize;
return BitmapFactory.decodeFile(path, option);
}
/**
* ImageView
* @param iv
* @return
*/
private ImageSize getImageSize(ImageView iv){
LayoutParams lp = iv.getLayoutParams();
//
DisplayMetrics dm = iv.getContext().getResources().getDisplayMetrics();
int width=iv.getWidth();
if(width<=0){
width=lp.width;
}
if(width<=0){
// ImageView MaxWidth MaxHeight
width=getMaxValueFromInvoke(iv,"mMaxWidth");
}
if(width<=0){
width=dm.widthPixels;
}
int height=iv.getHeight();
if(height<=0){
height=lp.width;
}
if(height<=0){
height=getMaxValueFromInvoke(iv,"mMaxHeight");
}
if(height<=0){
height=dm.heightPixels;
}
return new ImageSize(width, height);
}
/**
* ImageView MaxWidth MaxHeight
* @param obj
* @param fieldName
* @return
*/
private int getMaxValueFromInvoke(Object obj,String fieldName){
int value=0;
try {
Field field = ImageView.class.getDeclaredField(fieldName);
field.setAccessible(true);
int fieldValue = field.getInt(obj);
if(fieldValue>0&&fieldValue<Integer.MAX_VALUE){
value=fieldValue;
}
} catch (Exception e) {
e.printStackTrace();
}
return value;
}
/**
*
* @author Administrator
*
*/
private class ImageSize{
int width;
int height;
public ImageSize(int width,int height){
this.width=width;
this.height=height;
}
}
//handler msg.obj
private class ImageHolder{
Bitmap mBitmap;
ImageView mImageView;
String path;
}
//
private Bitmap getBitmapFromLruCache(String key) {
return mLruCache.get(key);
}
}
마지막 으로 ImageLoader 를 외부 에서 호출 할 때 Type 속성 과 스 레 드 탱크 의 최대 스 레 드 개 수 를 지정 하려 면 getInstance 방법 을 추가 하여 다시 불 러 올 수 있 습 니 다.
/**
* ImageLoader
* @return
*/
public static ImageLoader getInstance(int threadCount,Type type){
// if ,
// ,
//
if(instance==null){
synchronized (ImageLoader.class) {
if(instance==null){
instance=new ImageLoader(threadCount,type);
}
}
}
return instance;
}
프로젝트 원본 다운로드 주소:원본 다운로드
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[전] 자바 로 pdf 를 jpg 그림 으로 변환 하 는 코드이 코드 는 pdf 를 jpg 그림 으로 변환 할 수 있 습 니 다. 그림 이 뚜렷 하 지 는 않 지만 충분히 사용 할 수 있 습 니 다. 표지 의 그림 만 문서 의 미리 보기 그림 을 만 들 고 싶 기 때 문 입 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.