Android:使用AsyncTask进行重复Ajax调用的含义

时间:2011-06-30 12:35:53

标签: android android-asynctask timertask

我需要我的Android应用程序使用AJAX调用定期从服务器获取数据,并相应地更新UI(只需要使用TextView更新一堆setText())。请注意,这涉及2个任务:

  1. 进行AJAX调用,并在收到回复后更新用户界面 - 我为此使用简单的AsyncTask
  2. 定期反复执行上述操作。
  3. 我还没有想出一个优雅的方法来实现上面的第2点。目前,我只是从OnPostExecute()执行任务。我在this thread at 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完成,否则onPostExecute()如何成为GC的候选者?

    2. 如何“停止”更新?我想到的一种方法是将第一个AsyncTask实例作为Activity的成员变量。这样,我可以在其上调用cancel(true)并希望这将“停止”任务。


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

      我放弃了另一种方法 - 在我Activity的{​​{1}}中无休止地调用我的Ajax;并更新doInBackground()中的用户界面。这样我也可以避免维护太多线程或AsyncTask来更新UI的开销(请记住UI可以在onProgressUpdate()中更新)。

      这种方法也消除了对HandleronProgressUpdate()的需求,而更倾向于使用TimerThis thread on SO还有更多详细信息和代码段。

5 个答案:

答案 0 :(得分:1)

在任何postDelayed()上调用View以安排在一段延迟后在主应用程序线程上运行的代码块。在onPostExecute()的{​​{1}}中执行此操作,以创建并执行另一个AsyncTask

你可以使用AsyncTask,正如其他人所引用的那样,但我同意你的看法,就像在一项活动中纯粹出现的时间感觉有点过分。

话虽如此,如果AJAX调用应该发生而不管活动是否存在,那么一定要考虑切换到AlarmManagerAlarmManager

答案 1 :(得分:0)

我认为这样做的方法是使用AlarmManager。或者您也可以使用基本的Java Timer。我推荐使用AlarmManager。

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

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

执行重复任务的推荐方法是通过AlarmManager,正如Scythe所暗示的那样。基本上它涉及设置广播监听器,并让AlarmManager以您选择的任何间隔触发对该监听器的意图。然后,您可以让广播侦听器调用该活动来运行AsyncTask。如果你需要一个非常紧张的计时器(我会说不到5秒的电话),那么你最好在服务中使用一个计时器,并使用AIDL回叫活动。

您可以设置一个可以戳戳的IntentService,并使用AIDL来更新活动,而不是直接与广播意图交谈。

答案 4 :(得分: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);

            }

        }

    }
}