2

我需要我的 Android 应用程序使用 AJAX 调用定期从服务器获取数据,并相应地更新 UI(只是一堆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. 如何“停止”更新?我想到的一种方法是将第一个AsyncTask实例作为Activity. 这样,我可以调用cancel(true)它并希望这将“停止”任务。


解决方案

如果有人正在寻找类似的东西 - 我在这里提到的解决方案都不能令人满意。他们都饱受OutOfMemory问题之苦。我没有调试 OOM 的细节,但我怀疑这可能是因为递归,或者因为 HTTP 相关对象作为成员变量AsyncTask而不是成员Activity(基本上是因为没有重用 HTTP 和其他对象)。

我放弃了这种方法,换了一种方法——使我的 Ajax 调用无休止地出现在doInBackground()我的AsyncTask; 并在onProgressUpdate(). 这样我也避免了维护太多线程或Handler更新 UI 的开销(记住 UI 可以在 中更新onProgressUpdate())。

这种方法也消除了对Timers 和TimerTasks 的需要,而倾向于使用 of Thread.sleep()SO上的这个线程也有更多细节和代码片段。

4

5 回答 5

1

调用postDelayed()anyView以安排一大块代码在一定延迟后在主应用程序线程上运行。执行此操作onPostExecute()AsyncTask创建和执行另一个AsyncTask.

正如其他人所引用的那样,您可以使用AlarmManager,但我同意您的观点,对于纯粹发生在活动中的时间,感觉有点矫枉过正。

话虽如此,如果无论活动是否存在都应该发生 AJAX 调用,请务必考虑切换AlarmManagerIntentService.

于 2011-06-30T13:56:36.953 回答
0

我认为执行此操作的 android 方法是使用AlarmManager。或者您也可以使用基本的 java Timer。我推荐AlarmManager。

将其设置为使用自定义操作发送一些意图,并为其注册广播接收器。

于 2011-06-30T12:43:52.757 回答
0

如果仅在活动中执行 ajax 调用,则可以在启动任务的活动中使用计时器。

否则,使用使用 AlarmManager 并通过广播连接到 gui 的服务。

于 2011-06-30T12:46:51.153 回答
0

执行重复任务的推荐方法是通过AlarmManager,正如 Scythe 所暗示的那样。基本上,它涉及设置广播侦听器,并让 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 回答