Android:使用 AsyncTask 进行重复 Ajax 调用的含义
我需要我的 Android 应用程序使用 AJAX 调用定期从服务器获取数据,并相应地更新 UI(只是一堆需要使用 setText()
TextView ) >)。请注意,这涉及 2 个任务:
- 进行 AJAX 调用,并在收到响应后更新 UI - 为此我使用一个简单的
AsyncTask
。 - 定期重复执行上述操作。
我还没有找到一个优雅的方法来实现上面的第 2 点。目前,我只是从 OnPostExecute() 执行任务本身。我在这个线程上读到,我不必担心垃圾收集涉及 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
);
}
使用此功能时有什么需要注意的方面吗?特别是,我看到 LogCat 中发生了很多 GC。 除非
onPostExecute()
完成,否则AsyncTask
如何成为 GC 的候选者?如何“停止”更新?我想到的一种方法是将第一个
AsyncTask
实例作为Activity
的成员变量。这样,我可以对其调用cancel(true)
并希望这将“停止”任务。
解决方案:
如果有人正在寻找类似的东西 - 我在这里提到的解决方案都不能令人满意。它们都受到 OutOfMemory
问题的困扰。我没有调试 OOM 的细节,但我怀疑这可能是因为递归,或者是因为将 HTTP 相关对象作为 AsyncTask 中的成员变量而不是作为Activity
(主要是因为不重用 HTTP 和其他对象)。
我放弃了这种方法,转而采用另一种方法 - 在 AsyncTask
的 doInBackground()
中无休止地进行 Ajax 调用;并在 onProgressUpdate()
中更新 UI。这样我还可以避免维护太多线程或处理程序来更新 UI 的开销(请记住 UI 可以在 onProgressUpdate() 中更新)。
这种方法还消除了对 Timer 和 TimerTask 的需求,而是使用 Thread.sleep() 。 这个帖子有更多细节和代码也有片段。
I need my Android app to periodically fetch data from a server using AJAX calls, and update the UI accordingly (just a bunch of TextView
s that need to be updated with setText()
). Note that this involves 2 tasks:
- Making an AJAX call, and updating the UI once I receive a response - I use a simple
AsyncTask
for this. - Doing the above repeatedly, at regular intervals.
I haven't figured out an elegant way to achieve Point 2 above. Currently, I am simply executing the task itself from OnPostExecute()
. I read on this thread at SO that I need not worry about garbage collection as far as the AsyncTask objects are concerned.
But I'm still unsure as to how I set up a timer that will fire my AsyncTask after it expires. Any pointers will be appreciated. Here is my code:
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);
}
}
}
Thanks in advance
EDIT:
I tried posting an answer but couldn't do it since I don't have the reputation to answer within 8 hours.
Well, so I found a solution. I'm not convinced however.
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
);
}
Are there any flip sides that I should be aware of when I use this? In particular, I am seeing lots of GCs happening in the LogCat. Also, I am wondering how an
AsyncTask
can be candidate for GC unless theonPostExecute()
completes?How can I "stop" the updates? One way I thought of was to make the very first
AsyncTask
instance as a member variable of theActivity
. That way, I can invokecancel(true)
on it and hope that this will "stop" the tasks.
SOLUTION:
In case anyone is looking for something similar - none of the solutions I mentioned here work satisfactorily. They all suffer from OutOfMemory
issues. I did not debug into the details of the OOM, but I suspect it could either be because of the recursion, or because of having HTTP-related objects as member variables in the AsyncTask
rather than as members of the Activity
(basically because of NOT reusing HTTP and other objects).
I discarded this approach for a different one - making my Ajax Calls endlessly in the doInBackground()
of my AsyncTask
; and updating the UI in onProgressUpdate()
. That way I also avoid the overhead of maintaining too many threads or Handler
s for updating the UI (remember UI can be updated in onProgressUpdate()
).
This approach also eliminates the need for Timer
s and TimerTask
s, favoring the use of Thread.sleep()
instead. This thread on SO has more details and a code snippet too.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
在任何
View
上调用postDelayed()
来安排一段代码在一定延迟后在主应用程序线程上运行。在AsyncTask
的onPostExecute()
中执行此操作,以创建并执行另一个AsyncTask
。您可以使用
AlarmManager
,正如其他人所引用的那样,但我同意您的观点,对于纯粹在活动中发生的计时来说,感觉有点矫枉过正。也就是说,如果无论 Activity 是否存在都应该发生 AJAX 调用,那么一定要考虑切换到
AlarmManager
和IntentService
。Call
postDelayed()
on anyView
to schedule a hunk of code to be run on the main application thread after a certain delay. Do this inonPostExecute()
of theAsyncTask
to create and execute anotherAsyncTask
.You could use
AlarmManager
, as others have cited, but I would agree with you that it feels a bit like overkill for timing that occurs purely within an activity.That being said, if the AJAX calls should be occurring regardless of whether the activity exists, definitely consider switching to
AlarmManager
and anIntentService
.我认为android的方法是使用AlarmManager。或者您也可以使用基本的 java 计时器。我推荐 AlarmManager。
将其设置为使用自定义操作发送一些意图,并为其注册一个广播接收器。
I think the android way to do this is using AlarmManager. Or you can user a basic java Timer as well. I'd recommend AlarmManager.
Set it up to send some intent with a custom Action, and register a broadcastreceiver for it.
如果ajax调用仅在活动中执行,您可以在启动任务的活动中使用计时器。
否则,请使用使用 AlarmManager 并通过广播连接到 GUI 的服务。
If the ajax calls are only executed in the activity you can just use a timer in the activity which starts the tasks.
Otherwise use a service which uses the AlarmManager and which connects to the gui via a broadcast.
执行重复任务的推荐方法是通过 AlarmManager,如所提到的通过镰刀。基本上,它涉及设置一个广播侦听器,并让 AlarmManager 以您选择的任何时间间隔向该侦听器发出意图。然后,您可以让广播侦听器调用该活动来运行 AsyncTask。如果您需要一个非常严格的计时器(我想说少于 5 秒的调用),那么您最好在服务中使用计时器,并使用 AIDL 回调活动。
您还可以设置一个可以戳的 IntentService,并使用 AIDL 来更新活动,而不是直接从广播意图中进行对话。
The recommended way to do a repeated task, is via AlarmManager, as alluded to by Scythe. Basically it involves setting up a broadcast listener, and having AlarmManager fire off an intent to that listener at whatever interval you choose. You then would have your broadcast listener call out to the activity to run the AsyncTask. If you need a very tight timer (less than 5s calls I'd say), then you're better off using a Timer within a Service, and using AIDL to call back to the activity.
Instead of talking directly from the broadcast intent, you could also setup an IntentService which you can poke, and use AIDL to update the activity.
这就是我最终实现的方法。请注意,由于递归,AsyncTask cancel(true) 方法在我的场景中没有用。我使用了 @CommonsWare 的建议 - 使用一个标志来指示是否应该执行更多任务。
This is how I achieved it finally. Note that the AsyncTask cancel(true) method is useless in my scenario because of the recursion. I used what @CommonsWare suggested - used a flag to indicate whether any more tasks should be executed.