3

다음과 같은 비동기 작업이 있는데, 주어진 URL에서 이미지를로드해야합니다. 이미지가 존재하고 나는 그러나 때때로 bm가 null로 반환됩니다, 그BitmapFactory.decodeStream 스레드로부터 안전합니까? 때로는 비동기 작업이 완료되기 전에 완료됩니다.

private class FetchVehicleImage extends AsyncTask<String, Integer, Bitmap> 
    { 

     private ProgressBar mSpinner; 
     private ImageView mImage; 
     private String imagesBaseUrl = "http://mywebsite.net/images/"; 
     private URL url = null; 

     @Override 
     protected void onPreExecute() 
     { 
      mImage = (ImageView) findViewById(R.id.vehicle_image); 
      mSpinner = (ProgressBar) findViewById(R.id.vehicle_image_progress_bar); 
      mSpinner.setIndeterminate(true); 
      mSpinner.setVisibility(View.VISIBLE); 
      mImage.setVisibility(View.GONE); 
     } 

     @Override 
     protected Bitmap doInBackground(String... strings) 
     { 
      Bitmap bm = null; 

      try 
      { 
       url = new URL(imagesBaseUrl + strings[0]); 

       HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
       conn.setDoInput(true); 
       conn.connect(); 
       InputStream is = conn.getInputStream(); 
       bm = BitmapFactory.decodeStream(is); 
      } 
      catch (Exception e) 
      { 
       e.printStackTrace(); 
      } 
      return bm; 
     } 

     protected void onPostExecute(final Bitmap result) 
     { 
      if (result != null) 
      { 
       mImage.setImageBitmap(result); 
      } 
      mImage.setVisibility(View.VISIBLE); 
      mSpinner.setVisibility(View.GONE); 
     } 
    } 

나는 doInBackground에서 예외를 볼 수 없을에 액세스 할 수 있지만, 매우 간헐적. 4 개의 이미지가 있습니다. 3 번로드가 완벽 할 때마다 완벽하게로드되지만, bm 할당에서 중단 점을 맞히면 하나만로드됩니다. 작업을 수행하는 데 충분한 시간이 필요하다고 생각하십니까?

나는 doInBackground이 배경 스레드에서 실행되어야한다고 생각 했으므로 항상 이미지를 가져 오거나 예외가 발생해야합니까?

+0

아마이 기사는 http://foo.jasonhudgins.com/2010/05/limitations-of-asynctask.html에서 약간의 빛을 비춰 줄 수도 있지만 4 개의 이미지 만있는 경우에는 거의 적용 할 수 없다. override run()) 및이 경우에는 runOnUiTread –

답변

2

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

아마도이 모든 것이 도움이 될 수 있습니다. 하지만 나는 을 사랑해 당신이 제기 한 훌륭한 질문에 대한 확실한 답을 듣고 싶습니다.

관련 문제