2013-01-15 2 views
2

호출하는 프래그먼트가 일시 중지/제거 될 때 비동기 작업은 어떻게됩니까? 나는 그 일이 끝났다고 가정하고 있지만 그것은 누군가를 잘 확인할 수있을 것이다. 내 충돌에 대한 해결책을 찾고 있습니다.비동기 Backbutton에서 충돌이 발생했습니다.

재귀 이미지 로더 인 비동기 작업이 있습니다. 이미지 로더는 이미지를로드하는 listFragment의 내부 클래스입니다. 이미지 로더는 모든 이미지를로드하기 전에 뒤로 버튼을 누르지 않으면 완벽하게 작동합니다. 모든 이미지가 완료되기 전에 뒤로 버튼을 누르면 응용 프로그램이 충돌합니다. 이미지 로더가 어댑터에 액세스 할 수 없지만이 문제를 올바르게 공격하고 있는지 확실하지 않습니다. 내 비동기 작업 내에서이 문제를 해결하는 방법을 잘 모르겠습니다. 누군가 나를 도울 수 있다면. 심지어 내 생각을 다르게 생각하게하기 위해 아이디어를 내 머리에서 튕겨 내라.

도움이 될 것입니다. 봐 주셔서 감사합니다.

하여 ImageLoader

private class ImageLoaderTask extends 
     AsyncTask<HashMap<String, Object>, Void, HashMap<String, Object>> { 

    @Override 
    protected HashMap<String, Object> doInBackground(
      HashMap<String, Object>... hm) { 
     InputStream in = null; 

     String url = (String) hm[0].get("image"); 
     int pos = (Integer) hm[0].get("pos"); 
     url = "http://kzfr.org/u/img/small/" + url; 
     URL mUrl; 

     try { 
      mUrl = new URL(url); 
      URLConnection urlConnect = (URLConnection) mUrl 
        .openConnection(); 
      in = urlConnect.getInputStream(); 

      File cacheDirectory = getSherlockActivity().getBaseContext() 
        .getCacheDir(); 

      File tmp = new File(cacheDirectory.getPath() + "/kzfr_small" 
        + pos + ".png"); 

      FileOutputStream fOut = new FileOutputStream(tmp); 

      Bitmap b = BitmapFactory.decodeStream(in); 
      b.compress(Bitmap.CompressFormat.PNG, 100, fOut); 
      fOut.flush(); 
      fOut.close(); 

      HashMap<String, Object> hmBmp = new HashMap<String, Object>(); 
      hmBmp.put("blank_start", tmp.getPath()); 
      hmBmp.put("pos", pos); 
      return hmBmp; 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    @Override 
    protected void onPostExecute(HashMap<String, Object> result) { 
     // this is the img path that leads to a local image that was just 
     // saved on the phone. 
     String imgPath = (String) result.get("blank_start"); 
     // the position of the image in the listview 
     int position = (Integer) result.get("pos"); 
     // local adapter 
     SimpleAdapter adapter = (SimpleAdapter) getListAdapter(); 
     // hashmap entry from the local adapter at the position of the image 
     // that we just loaded. 
     HashMap<String, Object> hm = (HashMap<String, Object>) adapter 
       .getItem(position); 
     // replace the actual blank image with the image path that we just 
     // loaded 
     hm.put("blank_start", imgPath); 
     // update listview 
     adapter.notifyDataSetChanged(); 
     // we are done with the current position increment position and move 
     // on. 
     position++; 
     // this while loop finds the next position in the adapter that does 
     // not have false for an image path. False indicates that there is 
     // no image and i should load a default image. 
     while (position < adapter.getCount()) { 
      hm = (HashMap<String, Object>) adapter.getItem(position); 
      imgPath = (String) hm.get("image"); 

      if (!imgPath.equalsIgnoreCase("false")) { 
       break; 
      } 
      position++; 
     } 

     // checks to make sure that the position is not out of bounds on the 
     // adapter. If in bounds then there might be more images to load. 
     // Start a new ImageLoader. This is a recursive Class. 
     if (position < adapter.getCount()) { 
      ImageLoaderTask imageLoader = new ImageLoaderTask(); 

      hm.put("pos", (position)); 
      imageLoader.execute(hm); 
     } 

    } 

스택 트레이스

호출 단편이 일시 정지 된 비동기 작업에 어떻게됩니까
01-14 20:09:28.752: E/AndroidRuntime(6069): FATAL EXCEPTION: main 
01-14 20:09:28.752: E/AndroidRuntime(6069): java.lang.NullPointerException 
01-14 20:09:28.752: E/AndroidRuntime(6069):  at com.appdomum.doublea.ListFrag$ImageLoaderTask.onPostExecute(ListFrag.java:272) 
01-14 20:09:28.752: E/AndroidRuntime(6069):  at com.appdomum.doublea.ListFrag$ImageLoaderTask.onPostExecute(ListFrag.java:1) 
01-14 20:09:28.752: E/AndroidRuntime(6069):  at android.os.AsyncTask.finish(AsyncTask.java:417) 
01-14 20:09:28.752: E/AndroidRuntime(6069):  at android.os.AsyncTask.access$300(AsyncTask.java:127) 
01-14 20:09:28.752: E/AndroidRuntime(6069):  at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429) 
01-14 20:09:28.752: E/AndroidRuntime(6069):  at android.os.Handler.dispatchMessage(Handler.java:99) 
01-14 20:09:28.752: E/AndroidRuntime(6069):  at android.os.Looper.loop(Looper.java:130) 
01-14 20:09:28.752: E/AndroidRuntime(6069):  at android.app.ActivityThread.main(ActivityThread.java:3806) 
01-14 20:09:28.752: E/AndroidRuntime(6069):  at java.lang.reflect.Method.invokeNative(Native Method) 
01-14 20:09:28.752: E/AndroidRuntime(6069):  at java.lang.reflect.Method.invoke(Method.java:507) 
01-14 20:09:28.752: E/AndroidRuntime(6069):  at  com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 
01-14 20:09:28.752: E/AndroidRuntime(6069):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 
01-14 20:09:28.752: E/AndroidRuntime(6069):  at dalvik.system.NativeStart.main(Native Method) 
+1

어떤 줄이 272입니까? 활동이 끝났기 때문에 더 이상 존재하지 않는 것을 참조하고 싶다. –

+0

라인 272는'string imgPath = (String) result.get ("blank_start");'out of onPostExecute이다. 그것은 DoIn 백그라운드에서 전달되기 때문에 Image Loader 클래스 내부에 있어야하는 것을 참조합니다. – doubleA

+0

먼저 result.hasKey ("blank_start")를 확인해야합니다. 해당 키에 대한 항목이 없어서 null이 반환되는 것처럼 보입니다. –

답변

4

나는 올바른 길을 가고 있다고 생각합니다.

많은 개발자가 사용자 지정 AsyncTask을 작성할 때 작업 취소를 처리해야한다는 사실을 잊어 버립니다. 단순히 작업을 취소한다고해서 그 시간에 해제 될 수있는 자원 (예 : Activity/Fragment)에서 해당 코드가 실행되지 않는다는 의미는 아닙니다. 이는 일반적으로 다음 단계에서 수행됩니다.

  1. 작업을 생성 한 후에 참조를 저장하십시오.
  2. Activity/Fragment이 완료되면 실행중인 모든 작업을 취소하십시오. 일반적으로 Activity.onDestroy()/Fragment.onDestroy()에서 이루어집니다. 취소 된 작업에 대한 모든 참조를 제거하십시오.작업의 코드에서
  3. 는 : doInBackground()에서
    1. 주기적 경우 isCancelled()을 확인합니다. 그렇다면 정리하고 더 이상 실행을 중단하십시오.
    2. 결국 취소 처리는 onCancelled() (UI 스레드에서 실행)입니다.
    3. onPostExecute() (취소 된 작업 처리 중 이 실행 됨)은 작업이 취소 된 경우 null이 결과로으로 실행됩니다.
+0

그래서 숫자 3은'onPostExecute()'에 null 결과를 설명합니다. 왜냐하면 뒤로 버튼을 누르면 프래그먼트가 제거되기 때문입니다. 나는 내가 추적 할 수 없기 때문에 너무 많은 문제가 있었기 때문에 쇼/숨기기를 사용하지 않고있다. – doubleA

+0

이것은 완벽합니다. 필요한 정보가 내가 다루고있는 것을 이해하는 방식으로 설명되었습니다. 고맙습니다 andr. 나는 이행하기 위해 벗어났다. – doubleA

+0

Fragment/Activity가 파기 된 후 작업이 실행되면 NPE 또는 다른 오류의 원인이 더 많을 수 있습니다. 그냥 신중해야한다. 아, 그리고'onPostExecute()'(예를 들어)에 중단 점을 추가하고 변수 탭에서 변수 값을 볼 수 있다는 것을 기억하십시오. 때로는 많은 도움이됩니다. – andr

1

/제거? 나는 그 일이 끝났다고 가정하고 있지만 그것은 누군가를 잘 확인할 수있을 것이다.

잘못된 설명입니다. 프레임 워크는 백그라운드 스레드에서 수행중인 작업을 취소하여 작업을 수행하지 않습니다. onPause()onResume()과 같은 콜백이 호출되는 이유는 Service과 같이 수명이 긴 구성 요소에없는 실행중인 작업을 정리하고 취소해야하기 때문입니다.

이 경우 취소하지 않으면 작업이 계속 실행됩니다. 이 클래스는 정적이 아닌 내부 클래스로 정의되기 때문에 Fragment에 대한 암시 적 참조가 보유되어 있고 작업이 실행중인 스레드에 연결되어 있으므로 임시 메모리 누수가 발생했음을 의미합니다. 회원들)은 onDestroy() 후에도 가비지 수집이 가능합니다.

AsyncTask을 구현하면 취소 플래그가 있는지 확인하여 onPause() 또는 이와 유사한 콜백에서 수동으로 작업을 취소 할 수 있습니다.

관련 문제