N.B. 앱이 비트 맵용 기본 백업 메모리를 모두 사용하지 않고 있다면이 방법이 도움이되지 않습니다. 비트 맵, 특히 사전 허니 콤에 대해 설명하기 어려운 문제가있는 경우 Dalvik 힙과 기본 백업 메모리의 관계를 이해하는 것이 중요하다는 것을 과장 할 수 없습니다. 미스터 Dubroy의 토론은 나를 위해 매우 유익했습니다 - 끝까지 듣기에 가치가있었습니다. Dubroy's Heap Presentation
위의 질문에 대한 답변을 시도했습니다. . . 나는 그것을 증명할 수는 없지만 스레드로부터 안전하지 않다는 강한 의구심을 갖고 있습니다. 나는 페칭 후에 이미지 조작을 할 때 이것을 명중한다. 위의 예에서와 같이 하나 이상의 이미지 파일을 요청하고 도착한 파일을 처리하면 OutOfMemory
오류가 발생하여 힙과 사용 가능한 기본 백업 메모리가 모두 양호하다는 것을 알게됩니다 (> 100k 및 > 100M). 그리고 때로는 가져 오기가 (당신이 설명하는 것처럼) 작동하지만 때로는 그렇지 않을 수도 있습니다. 일부 장치에서는 다른 장치보다 견고합니다. 왜 그런지 이야기 해 달라는 요청을 받았을 때 OS의 네이티브 라이브러리가 스스로 사용할 수 있거나 사용하지 않을 수도있는 일부 장치에는 이미지 처리 하드웨어 (예 : jpg 인코더)가있을 수 있다고 생각합니다. 그런 다음, 즉시 스레드 안전성이 없다는 이유로 하드웨어 병목 현상을 탓하기 시작합니다.이 모든 것이 증거를 닮은 것 중 가장 작은 조각이없는 것입니다. 어쨌든, 내 테스트에서 안정적으로 (약 12 개) 신뢰성있게 모든 장치에서 작동하는 유일한 접근 방법은 비트 맵 조작 부분과 단일 스레드를 분리하는 것입니다.
위의 예에서 여전히 네트워크에서 실제로 파일을 가져 와서 임의의 위치 (원시 바이트 스트림)에 파일을 쓰려면 AsyncTask
을 사용합니다. AsyncTask
이 완료되면 (즉, 의 대표를 호출하면) 아래의 내 포스터 클래스와 같은 작업을 수행 할 수 있습니다. 초기화 후
public ExecutorService mImagePipelineTask = null; // Thread to use for pipelining images (overlays, etc.)
그리고 :
(나는 여러 다운로드 요청을) 내 활동에
, 나는 UI 스레드에서 처음 인스턴스화 클래스의 글로벌 실행기를 만들
mImagePipelineTask = Executors.newSingleThreadExecutor();
그런 다음 Thread
풀의 스레드 수를 제어하려면 AsyncTask
을 사용하지 않아도됩니다. 내 비동기 비트는 다음과 같이 보입니다.
public class PosterImage extends HashMap<String, Object> {
private final String TAG = "DEBUG -- " + ClassUtils.getShortClassName(this.getClass());
private PosterImageDelegate mPosterDelegate = null;
private Drawable mBusyDrawable = null;
private Drawable mErrorDrawable = null;
private ExecutorService mImagePipelineTask = null;
/*
* Globals
*/
Context mContext = null;
/*
* Constructors
*/
public PosterImage() {
}
public PosterImage(PlaygroundActivity aContext) {
mContext = aContext;
mImagePipelineTask = aContext.mImagePipelineTask;
mBusyDrawable = mContext.getResources().getDrawable(R.drawable.loading);
mErrorDrawable = mContext.getResources().getDrawable(R.drawable.load_error);
}
그런 다음 일부 비트는 별 관심이 없습니다. . .다음
public void setPosterDelegate(PosterImageDelegate aPosterDelegate) {
mPosterDelegate = aPosterDelegate;
}
그리고, 이미지 조작을 비트, 그리고 부작용대로를 사용하고 일부 초기화 물건, 어떻게 우리의 대리자를 설정하려면 (당신은 물론, PosterImageDelegate 인터페이스를 원할 것입니다) BitmapFactory
(및 Drawable
) 클래스입니다. 이를 사용하려면는 PosterImage 개체를 인스턴스화 대리인으로 자신을 설정 한 다음이 동료를 호출이 반환합니다 (UI 스레드에서) 호출하는 객체가 '바쁜'그릴 수있다
public Drawable getPreformattedFileAsync() {
if(mFetchFileTask == null) {
Log.e(TAG, " -- Task is Null!!, Need to start an executor");
return(mErrorDrawable);
}
Runnable job = new Runnable() {
public void run() {
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
Thread.currentThread().yield();
if(mPosterDelegate != null) {
Drawable retDrawable = getPreformattedFile();
if(retDrawable != null) {
mPosterDelegate.onDrawableRequest(retDrawable);
} else {
mPosterDelegate.onDrawableRequest(mErrorDrawable);
}
}
}
};
mImagePipelineTask.execute(job);
return(mBusyDrawable);
}
public Drawable getPreformattedFile() {
Drawable ret = null;
try {
FileInputStream in = new FileInputStream(preformattedFileName());
ret = Drawable.createFromStream(in, null);
// do something interesting with the Drawable
} catch(OutOfMemoryError e) {
System.gc();
e.printStackTrace();
// Will return null on its own
} catch(Exception e) {
Log.e(TAG, "Trouble reading PNG file ["+e+"]");
}
return(ret);
}
. 델리게이트가 호출되면 (파일 다운로드 후이 스레드에 의해 Drawable로 변환되면, 사용자가 지정한 Drawable 수신기에로드 할 준비가 됨) 모든 이미지를 병렬로 다운로드 할 수 있으므로 백그라운드 스레드 것입니다 한 번에 오직 과정 하나의 이미지. 다행히도, 그렇습니다 자체를 설정 하지
이 (NB는 여전히 호출 클래스의 Handler
을 필요로하는 영상 처리를 수행하려면 UI 스레드를 묶어 (하나 델리게이트 UI 스레드가 실제로 드로어 블 을에 수신 View
/Layout
/뭐든 넣습니다.) 시도의 완성도는 다음과 같을 수 있습니다.
mHandler.post(new Runnable() {
@Override
public void run() {
aItem.getButton().setBackgroundDrawable(aDrawable);
aItem.getButton().postInvalidate();
}
});
아마도이 모든 것이 도움이 될 수 있습니다. 하지만 나는 을 사랑해 당신이 제기 한 훌륭한 질문에 대한 확실한 답을 듣고 싶습니다.
아마이 기사는 http://foo.jasonhudgins.com/2010/05/limitations-of-asynctask.html에서 약간의 빛을 비춰 줄 수도 있지만 4 개의 이미지 만있는 경우에는 거의 적용 할 수 없다. override run()) 및이 경우에는 runOnUiTread –