2013-01-15 97 views
2

當調用片段被暫停/刪除時,異步任務會發生什麼?我假設任務完成了,但是有人可以證實這一點會很棒。我正試圖找到修復我的崩潰。按下後退按鈕時異步任務崩潰。

我有一個異步任務是一個遞歸圖像加載器。圖像加載器是加載圖像的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」);'outPostExecute。這是引用了一些應該是Image Loader類內部的東西,因爲它是從DoIn Background傳入的。 – doubleA

+0

您應該首先檢查result.hasKey(「blank_start」)。它看起來沒有該鍵的項目,所以它返回null。 –

回答

4

我認爲你在這裏的正確軌道上。

編寫自定義AsyncTask時,許多開發人員忘記了,有必要處理任務取消。簡單地取消任務並不意味着它的代碼不會在(例如)Activity/Fragment資源上執行,這些資源可能在當時被釋放。這通常在以下步驟中完成:

  1. 創建任務後,保存對其的引用。
  2. Activity/Fragment完成後取消所有正在運行的任務。這通常在Activity.onDestroy()/Fragment.onDestroy()中完成。刪除對取消任務的所有引用。
  3. 在任務代碼:
    1. doInBackground()定期檢查它是否isCancelled()。如果是這樣,整理並中止進一步執行。
    2. 最終在onCancelled()中處理取消(在UI線程上運行)。
    3. 執行onPostExecute()(其中執行,如果任務被取消時的結果爲null)中取消的任務的任何處理。
+0

因此,第3號解釋'onPostExecute()'中的空結果,因爲當我按下後退按鈕時,片段被移除。我沒有使用show/hide,因爲我有太多的問題,我無法追查。 – doubleA

+0

這是完美的。確切地說,我需要的信息可以解釋我所處理的情況。 Thankyou andr。我即將實施。 – doubleA

+0

的確如此,但是如果在片段/活動被銷燬後執行任務,則NPE或其他錯誤可能會有更多原因。只要謹慎:)哦,並且記住,你仍然可以在'onPostExecute()'(例如)中添加斷點,並在'Variables'選項卡中查看變量值。這有時可以幫助*很多*。 – andr

1

恰巧當主叫片段被暫停異步任務是什麼/刪除嗎?我假設任務完成了,但是有人可以證實這一點會很棒。

這是不正確的;該框架通過取消您在後臺線程中執行的工作來解決您的問題。回調像onPause()onResume()原因被稱爲是通知您的應用程序需要清理和取消所有正在運行的工作,是不是像一個Service長壽命組件。

在這種情況下,如果您不取消任務,則繼續運行。由於這個類被定義爲一個非靜態的內部類,它也意味着你已經創建了一個臨時內存泄漏,因爲AsyncTask持有對Fragment的隱式引用,並且由於該任務被附加到正在運行的線程,所以對象(或他們的成員)甚至可以在onDestroy()之後被垃圾收集。

您需要實施AsyncTask,以便它將檢查取消標誌,您可以手動取消onPause()或類似回調的作業。

相關問題