2010-12-13 13 views
0

私はAndroid用の単純なアプリケーションを開発しており、アプリケーションに必要なFTPコールとXML解析にasynctaskを使用するように切り替えようとしました(これは天気アプリのFYIです)。アンドロイドのasynctaskの潜在的なバグ

残念ながら、私はアプリで非常に奇妙な動作に気付き始めました。私はデバッグし、doInBackground()メソッド内のコードが順不同で実行されていることを私の恐怖に発見しました!

簡潔にするために、以下のコードは簡略化されています(ただし、catchステートメントはロールバックされます)。 asynctaskはonResume()で呼び出され、次にftpサーバーを呼び出し、ファイルをダウンロードして解析します。何が起こっているのですか(私はあなたが以下に見ることができるデバッグステートメントを通して非常にはっきりと見ることができます)、ファイルのダウンロードが完了する前に解析呼び出しが行われています。だから、デバッグ文の観点から、順序がしばしばある:

  1. GETファイル
  2. 前に解析ファイルの前
  3. エラーと解析ファイルの後に(ファイルがまだダウンロードしていないと!)
  4. ファイルを取得した後

私はもっと多くのコード(必要な場合はすべて!)を提供してくれることを嬉しく思います。

@Override 
    public void onResume() 
    { 
     if(!inOnResume) 
     { 
      inOnResume = true; 
      super.onResume(); 
      File file = new File(getFilesDir(), selectedCity); 
      new GetBOMWeatherData().execute(file); 
     } 
    } 

    private class GetBOMWeatherData extends AsyncTask<File, Void, Void> 
    { 
     boolean fileDownloaded = false; 

     @Override 
     protected void onPreExecute() 
     { 
      showDialog(PROGRESS_KEY); 
      super.onPreExecute(); 
     } 

     @Override 
     protected Void doInBackground(File... params) 
     { 
      FileOutputStream fos = null; 

      try 
      { 
       fos = new FileOutputStream(params[0]); 
      } 
      catch (FileNotFoundException e) 
      { 
       Log.e("ApiException", "There was an error opening the file output stream.", e); 
       cancel(false); 
      } 

      try 
      { 
       Log.d("Before get file", "Before get file"); 
       DataRetriever.getPageContent(selectedCity, fos); 
       Log.d("After get file", "After get file"); 
       fileDownloaded = true; 
      } 
      catch (ApiException e) 
      { 
       Log.d("After get file with error", "After get file with error"); 
       Log.e("ApiException", "There was an error opening the file output stream.", e); 
       cancel(false); 
      } 
      finally 
      { 
       Log.d("After get file finally", "After get file finally"); 
      } 

      try 
      { 
       Log.d("Before parse file", "Before parse file"); 
       forecasts = parseXML(selectedCity); 
       Log.d("After parse file", "After parse file"); 
       lastDownloaded.put(selectedCity, new Date()); 
      } 
      catch (FactoryConfigurationError e) 
      { 
       Log.d("After parse file with error", "After parse file with error"); 
       Log.e("XMLParsingException", "There was an error in the factory configuration.", e); 
       cancel(false); 
      } 
      finally 
      { 
       Log.d("After parse file finally", "After parse file finally"); 
      } 
      return null; 
     } 

     @Override 
     protected void onPostExecute(Void file) 
     { 
      inOnResume = false; 
      super.onPostExecute(file); 
      dismissDialog(PROGRESS_KEY); 
      updateView(); 
     } 

     @Override 
     protected void onCancelled() 
     { 
      super.onCancelled(); 
      showDialog(FAILURE_KEY); 
     } 
    } 

編集:奇妙なエラーが発生し始めたことが、順不同で実行されていたという理由が判明しました。メインのUIスレッドですべてを実行すると、それは動作しますが、asynctaskにすべて入れるとすぐにXML解析エラーが発生します。この問題は、アプリケーションが解析しようとしたときにファイルが完全にダウンロードされていないことが原因です。

+1

'私はデバッグステートメントで非常にはっきりとわかります。順序が変更される可能性があります。ログがプッシュされる遅延はさまざまです...実際にアプリケーションをデバッグしようとしましたか? – WarrenFaith

+0

はい、私はそれを実行すると、順番に実行されているように見えます(ログ・ステートメントでさえもデバッグしています)。私はおそらく、私がコードラインを一歩進んだりするのにかかる時間の増加をデバッグすると、すべてが順番に起こることを意味するのではないかと思う。 – chesterm8

+0

エミュレータでアプリケーションをデバッグしていますか?場合によっては、エミュレータはonResumeメソッドを複数回実行するように見えることがあります。新しいスレッドを開始する前に、スレッドが実行中であるかどうかを確認するためにロックを行ってください。 – Janusz

答えて

1

おそらく、複数のスレッドが実行されている可能性があります。あなたは前のものからの解析ログが終わっているのを見ていて、新しいものがダウンロードに入っています。おそらく一度に1つだけ必要なので、2つが同時に実行されないようにするには、何らかのロックを使用する必要があります。

+0

これは本当に良い点ですが、発生を防ぐためにロックを追加しました。しかし、それは私の問題を解決しません:( – chesterm8

0
DataRetriever.getPageContent(selectedCity, fos); 

これは別のスレッドで実行され、ブロックされません。したがって、ここでクラッシュするのは正常に正常であり、メインスレッドではクラッシュしません。これを使わないでください。

SAXParser parseur = SAXParserFactory.newInstance().newSAXParser(); 

parseur.parse(uri, DefaultHandler); 
      // On récupère directement la liste des feeds 
      ArrayList<Object> entries = ((DefaultHandler) handler).getData(); 

これはもちろん、XMLファイルをメモリに保存しない場合のみです。次に、DefaultHandlerを実装しているクラスで解析するだけです。

詳細については、docを参照してください。

ありがとうございます。

関連する問題