2012-01-17 1 views
1

私は30 * 1000ミリ秒ごとにWebサーバーをプルする簡単なAndroidプログラムを作成しようとしています。私は自分のアプリケーションにサービスを捧げて - PollerServiceAndroidサービスでスケジュールされたAsynTaskは1回だけ正しく実行されます

Android Manifest.xml: 
<application android:icon="@drawable/icon" android:label="@string/app_name"> 
    <activity android:name=".PullServerAndListenActivivty" 
     android:label="@string/app_name"> 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN" /> 
      <category android:name="android.intent.category.LAUNCHER" /> 
     </intent-filter> 
    </activity> 
    <service android:name=".PollerService" /> 
</application> 

クラスが予定さexecutorを作成し、ためにサーバを引っ張るエンジンを呼び出しを開始するために、そのタイマータスクを登録します。

PollerService.java: 

public class PollerService extends Service { 
public static final int INTERVAL = 20*1000; 
private ScheduledExecutorService executor; 

public void onCreate() { 
    super.onCreate(); 
    executor = Executors.newSingleThreadScheduledExecutor(); 
    executor.scheduleAtFixedRate(new TimerTask() { 
     public void run() { 
      Engine.tick();    
     } 
    }, 0, INTERVAL, TimeUnit.MILLISECONDS); 
} 

public void onDestroy() { 
    executor.shutdownNow(); 
} 

public IBinder onBind(Intent arg0) { 
    return null; 
}; 
} 

エンジンは、GUIスレッドでAsyncTaskサブクラスインスタンスを作成して実行するだけです。 onPostExecuteは、Activityで割り当てられたUIコンポーネントを呼び出すコンソールに行を書き込みます。

public class Engine { 
private static Console console; //Assigned in Activity onCreate 
private static Activity context;//Assigned in Activity onCreate 
    ... 
public static void tick() { 
    final String requestURL = String.format(urlFormat, serverURL); 
    try { 
     context.runOnUiThread(
       new Runnable() { 
        public void run() { 
         new RequestTask().execute(requestURL);      
        }; 
       } 
     ); 
    } 
    catch (Throwable e) { 
     Log.e("SBOX", e.getMessage(), e); 
    } 
} 

public static void processCommand(String result) { 
    try { 
     final Command command = fromJSONToCommand(result); 
     context.runOnUiThread(new Runnable() { 
      public void run() { 
       console.writeLine("Receieved command: " + command); 
      } 
     }); 
    } catch (Exception e) { 
     Log.e ("SBOX", e.getMessage(), e);  
    } 
} 

ヤク、私はシンプルなRequestTaskインスタンスの作成から始め、私はそれはそれ自体でUIスレッド上で実行するが、私は最終的に役に立たない、まだ、このアプローチに来て問題を解決しようとするだろうという印象の下にありました。ちょうど私がここでたくさん試したと言いたい。

RequestTaskこの、単純なHTTP呼び出しのようになります。

class RequestTask extends AsyncTask<String, Void, String>{ 

@Override 
protected String doInBackground(String... uri) { 
    HttpClient httpclient = new DefaultHttpClient(); 
    HttpResponse response; 
    String responseString = null; 
    try { 
     response = httpclient.execute(new HttpGet(uri[0])); 
     StatusLine statusLine = response.getStatusLine(); 
     if(statusLine.getStatusCode() == HttpStatus.SC_OK){ 
      ByteArrayOutputStream out = new ByteArrayOutputStream(); 
      response.getEntity().writeTo(out); 
      out.close(); 
      responseString = out.toString(); 
     } else{ 
      response.getEntity().getContent().close(); 
      throw new IOException(statusLine.getReasonPhrase()); 
     } 
    } catch (Exception e) { 
     Log.e("SBOX", e.getMessage(), e); 
    } 
    return responseString; 
} 

@Override 
protected void onPostExecute(String result) { 
    super.onPostExecute(result); 
    Engine.processCommand (result); 
} 
} 

だから、問題は、それが一度だけ正常に実行されることで、タイマーのスケジュール、エンジンの最初の時間を呼び出し、それを取得、それはサーバーを引っ張る、RequestTaskを実行します応答し、コンソールに表示します。しかし、それはタイマーの方法に入ってから、サービスから生命の兆候が現れません。 LogCatで例外は発生せず、RequestTaskのログは出力されません。

もちろん、デバッグには時間がかかるでしょうが、おそらく誰かがこの苦痛から私を救い、コードにエラーを表示できますか? Executor自体は、Engine.tick()呼び出しをコメントするために完全に連続して動作します。

解決の手がかりとして非常に役立ちます。それは、スレッドに関連する規則を次のようになりますAsyncTaskのドキュメントで

答えて

2

:(第二の実行が試行された場合、例外がスローされます)

タスクは一度だけ実行することができ

これは、使用するたびにクラスの新しいインスタンスを作成する必要があることを意味します。言い換えれば、それはこのように行われている必要があります

new DownloadFilesTask().execute(url1, url2, url3); 
new DownloadFilesTask().execute(url4, url5, url6); 

あるいは逆に、あなたは次の操作を行うことはできません。

DownloadFilesTask dfTask = new DownloadFilesTask(); 
dfTask().execute(url1, url2, url3); 
dfTask().execute(url4, url5, url6); 
+0

Engine.tick() - new RequestTask()。execute(requestURL);これは実際に私が行うことです。 – kirhgoff

+0

新しいRequestTask()を実行しようとしましたか?execute(requestURL); requestURLはおそらくrequestURL1,2などに変更されます。 –

+1

これはどうやって助けてくれるのか分かりません。 @CommonsWareによる返事をチェックしてください。彼のアプローチはもっとAndroidに似ています。 – kirhgoff

7

私は、すべてのWebサーバーを引く簡単なAndroidのプログラムを作成しようとしています30 * 1000ミリ秒。

あなたは確かに難しい方法です。

ステップ1:アクティビティとサービスの間に実際の通信チャネルを設定します。メモリリークの可能性があるため、静的なデータメンバを使用しないでください。候補者はたくさんあります(createPendingResult()Messengerなど)。この回答のために、私はあなたがブロードキャストIntentを使用しようとしているので、いくつかのユニークなアクションストリングを選択し、あなたのアクティビティのonResume()BroadcastReceiverを設定して、そのようなブロードキャストを聴く(受信者をonPause()で削除する) 。

ステップ#2:あなたのRequestTaskからごdoInBackground()方法からコードを持っているあなたのサービスでpollServer()メソッドを作成します。しかし、文字列を返すのではなく、文字列を余分に使ってブロードキャストIntentを送ってもらうようにしてください。

Engine.tick()ではなく、ScheduledExecutorServiceからpollServer()に電話してください。

ステップ4:EngineRequestTaskを完全に削除します。

+0

ありがとう、非常に合理的な音、私はこのアプローチを試して、それが役立つかどうかを知らせる – kirhgoff

関連する問題