2

AJAX呼び出しを使用してサーバーから定期的にデータを取得し、それに応じてUIを更新するには、Androidアプリが必要です(でTextView更新する必要がある一連のsのみsetText())。これには 2 つのタスクが含まれることに注意してください。

  1. AJAX 呼び出しを行い、応答を受信したら UI を更新します。これには単純なを使用しAsyncTaskます。
  2. 上記を一定間隔で繰り返し行います。

上記のポイント 2 を達成するエレガントな方法がわかりません。現在、からタスク自体を実行しているだけですOnPostExecute()SO のこのスレッドを読みましたが、AsyncTask オブジェクトに関する限り、ガベージ コレクションについて心配する必要はありません。

しかし、期限が切れた後に AsyncTask を起動するタイマーをどのように設定するかについては、まだわかりません。任意のポインタをいただければ幸いです。これが私のコードです:

public class MyActivity extends Activity {


    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        new AjaxRequestTask().execute(MY_REST_API_URL);

    }

    private void updateReadings(String newReadings) {
           //Update the UI
        }

    class AjaxRequestTask extends AsyncTask<String, Integer, String> {

        @Override
        protected String doInBackground(String... restApiUrl) {
                    //Do AJAX Request
                }

        @Override
        protected void onPostExecute(String result) {
            updateReadings(result);
                     /*Is there a more elegant way to achieve this than create a new AsyncTask object every 10 seconds?  Also, How can I update the UI if I create a timer here? */
            new AjaxRequestTask().execute(MY_REST_API_URL);
        }

    }

}

前もって感謝します

編集:回答を投稿しようとしましたが、8時間以内に回答するという評判がないため、投稿できませんでした.

さて、私は解決策を見つけました。しかし、私は確信していません。

protected void onPostExecute(String result) {

            updateReadings(result);
            // super.onPostExecute(result);
            new Timer().schedule(
                    new TimerTask() {
                        @Override
                        public void run() {
                            new AjaxRequestTask().execute(MY_REST_API_URL);
                        }
                    }, 
                    TIMER_ONE_TIME_EXECUTION_DELAY
            );
        }
  1. これを使用する際に知っておくべき裏返しはありますか? 特に、LogCat で多くの GC が発生しています。また、が完了しない限り、どのようAsyncTaskにGCの候補になるのでしょうか?onPostExecute()

  2. どうすれば更新を「停止」できますか? 私が考えた 1 つの方法は、最初のAsyncTaskインスタンスを のメンバー変数として作成することでしたActivity。そうすれば、それを呼び出しcancel(true)て、これがタスクを「停止」することを期待できます。


解決策:

誰かが同様のものを探している場合に備えて、ここで言及した解決策はどれも満足に機能しません。彼らは皆、問題に苦しんでOutOfMemoryいます。OOM の詳細についてはデバッグしませんでしたが、再帰が原因であるか、HTTP 関連のオブジェクトを のメンバーとしてではAsyncTaskなくメンバー変数として持つことが原因であると思われますActivity(基本的には、HTTP を再利用せず、他のオブジェクト)。

私は別のアプローチのためにこのアプローチを破棄しましdoInBackground()AsyncTask。で UI を更新しonProgressUpdate()ます。そうすれば、UI を更新するためにあまりにも多くのスレッドまたは を維持することによるオーバーヘッドも回避Handlerできます (UI は で更新できることを思い出してonProgressUpdate()ください)。

Timerこのアプローチではs とs の必要もなくなり、代わりTimerTaskに を使用することができThread.sleep()ます。SO のこのスレッドには、詳細とコード スニペットもあります。

4

5 に答える 5

1

特定の遅延の後にメイン アプリケーション スレッドで実行されるコードの塊をスケジュールするには、postDelayed()anyを呼び出します。Viewでこれを実行して、別onPostExecute()AsyncTaskを作成して実行しますAsyncTask

他の人が引用したように、を使用することもできますがAlarmManager、純粋にアクティビティ内で発生するタイミングについては、少しやり過ぎのように感じることに同意します。

そうは言っても、アクティビティが存在するかどうかに関係なく AJAX 呼び出しが発生する必要がある場合は、 と への切り替えを必ず検討しAlarmManagerIntentServiceください。

于 2011-06-30T13:56:36.953 に答える
0

繰り返しタスクを実行するための推奨される方法は、 Scythe が示唆しているように、 AlarmManagerを使用することです。基本的には、ブロードキャスト リスナーを設定し、選択した間隔で AlarmManager がそのリスナーに対してインテントを起動するようにする必要があります。次に、ブロードキャスト リスナーにアクティビティを呼び出して AsyncTask を実行させます。非常にタイトなタイマー (5 秒未満の呼び出し) が必要な場合は、サービス内でタイマーを使用し、AIDL を使用してアクティビティにコールバックすることをお勧めします。

ブロードキャスト インテントから直接話す代わりに、突くことができる IntentService をセットアップし、AIDL を使用してアクティビティを更新することもできます。

于 2011-06-30T12:59:02.863 に答える
0

これが私が最終的にそれを達成した方法です。AsyncTask cancel(true) メソッドは、再帰のため、私のシナリオでは役に立たないことに注意してください。@CommonsWareが提案したものを使用しました-フラグを使用して、さらにタスクを実行する必要があるかどうかを示しました。

public class MyActivity extends Activity {

    /*Flag which indicates whether the execution should be halted or not.*/
    private boolean mCancelFlag = false;

    private AjaxRequestTask mAjaxTask;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        if(mAjaxTask == null){
            mAjaxTask = new AjaxRequestTask();
        }
        mAjaxTask.execute(MY_REST_API_URL);

    }
@Override
    protected void onResume() {
        super.onResume();
        mCancelFlag = false; /*when we resume, we want the tasks to restart. Unset cancel flag*/

        /* If the main task is Finished, create a new task and execute it.*/

        if(mAjaxTask == null || mAjaxTask.getStatus().equals(AsyncTask.Status.FINISHED)){
            new AjaxRequestTask().execute(TLS_REST_API_URL);
        }

    }       
    @Override
    protected void onPause() {
        mCancelFlag = true; /*We want the execution to stop on pause. Set the cancel flag to true*/
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        mCancelFlag = true;/*We want the execution to stop on destroy. Set the cancel flag to true*/
        super.onDestroy();
    }

    private void updateReadings(String result) {
          //Update the UI using the new readings.
    }

    class AjaxRequestTask extends AsyncTask<String, Integer, String> {

        private AjaxRequestTask mChainAjaxRequest;
        private Timer mTimer;
        private TimerTask mTimerTask;


        @Override
        protected String doInBackground(String... restApiUrl) {
            //Do AJAX call and get the response
            return ajaxResponse;
        }

        @Override
        protected void onPostExecute(String result) {
            Log.d(TAG, "Updating readings");
            updateReadings(result);
            // super.onPostExecute(result);
            if(mTimer == null){
                mTimer = new Timer();
            }

            if(!mCancelFlag){/*Check if the task has been cancelled prior to creating a new TimerTask*/
                if(mTimerTask == null){
                    mTimerTask = new TimerTask() {
                        @Override
                        public void run() {
                            if(!mCancelFlag){/*One additional level of checking*/
                                if(mChainAjaxRequest == null){
                                    mChainAjaxRequest = new AjaxRequestTask();
                                }
                                    mChainAjaxRequest.execute(MY_REST_API_URL);
                            }

                        }
                    };
                }
                mTimer.schedule(mTimerTask,TIMER_ONE_TIME_EXECUTION_DELAY);

            }

        }

    }
}
于 2011-07-01T05:41:39.393 に答える
0

これを行うAndroidの方法はAlarmManagerを使用していると思います。または、基本的な Java タイマーも使用できます。AlarmManager をお勧めします。

カスタム アクションでインテントを送信するように設定し、ブロードキャストレシーバーを登録します。

于 2011-06-30T12:43:52.757 に答える