如何在固定时间间隔后重复执行异步任务
Posted
技术标签:
【中文标题】如何在固定时间间隔后重复执行异步任务【英文标题】:How to execute Async task repeatedly after fixed time intervals 【发布时间】:2011-09-25 19:02:33 【问题描述】:如何让异步任务像定时器一样在一段时间间隔后重复执行...实际上我正在开发一个应用程序,它将自动从服务器下载所有最新的未读问候语,为此我必须检查来自服务器的更新经过一些固定的时间间隔......我知道这可以通过计时器轻松完成,但我想使用我认为对 android 应用程序更有效的异步任务。
【问题讨论】:
【参考方案1】:public void callAsynchronousTask()
final Handler handler = new Handler();
Timer timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask()
@Override
public void run()
handler.post(new Runnable()
public void run()
try
PerformBackgroundTask performBackgroundTask = new PerformBackgroundTask();
// PerformBackgroundTask this class is the class that extends AsynchTask
performBackgroundTask.execute();
catch (Exception e)
// TODO Auto-generated catch block
);
;
timer.schedule(doAsynchronousTask, 0, 50000); //execute in every 50000 ms
【讨论】:
Async Task 无论如何都在它自己的线程中运行。为什么要在处理程序上运行它? 是的,异步任务确实在单独的线程上运行,但不能从 UI 线程以外的其他线程启动。我猜,处理程序是为了允许这样做。 如果启动这些 AsyncTask 的 Activity 被终止(通过方向更改或操作系统中断,如电话呼叫),此技术会留下悬空引用。因此,如果您对自己的程序在这些时候崩溃感到满意,那么请务必使用此方法。 @ScottBiggs 哪种技术会更好/不会崩溃? @colti:还没有找到好的解决方案。除了非常简单的东西外,我已经放弃了 ASyncTasks。对于更复杂的操作,我使用服务(是的,我知道,开销是一个痛苦的$$,但至少它不会崩溃那么多。小心清理,不要留下悬空的服务) .【参考方案2】: //Every 10000 ms
private void doSomethingRepeatedly()
Timer timer = new Timer();
timer.scheduleAtFixedRate( new TimerTask()
public void run()
try
new SendToServer().execute();
catch (Exception e)
// TODO: handle exception
, 0, 10000);
【讨论】:
对于android文档developer.android.com/reference/java/util/Timer.html中的所有新代码,建议优先使用ScheduledThreadPoolExecutor而不是Timer【参考方案3】:你可以只是一个处理程序:
private int m_interval = 5000; // 5 seconds by default, can be changed later
private Handle m_handler;
@Override
protected void onCreate(Bundle bundle)
...
m_handler = new Handler();
Runnable m_statusChecker = new Runnable()
@Override
public void run()
updateStatus(); //this function can change value of m_interval.
m_handler.postDelayed(m_statusChecker, m_interval);
void startRepeatingTask()
m_statusChecker.run();
void stopRepeatingTask()
m_handler.removeCallback(m_statusChecker);
但我建议你检查一下这个框架:http://code.google.com/intl/de-DE/android/c2dm/ 是一种不同的方法:服务器会在准备就绪时通知手机(从而节省一些带宽和性能:))
【讨论】:
非常感谢。实际上我只是在开发应用程序的客户端。服务器端已经在为 iphone 开发的相同应用程序工作,我必须为 android 使用相同的服务器 我是 android 线程的新手。你在哪里将 runnable 传递给处理程序? 回答@DheeB,回答者在这里没有提到,虽然它应该在像这样的实例化过程中 m_handler = new Handler(m_statusChecker);该解决方案可能不起作用的另一个原因,因为问题清楚地表明将有网络操作“自动从服务器下载所有最新的未读问候语”。但是,尽管您使用的是处理程序,但此处理程序/可运行文件仍在运行在仍然阻塞的 UI 线程中。您需要手动在单独的线程中启动它。【参考方案4】:通过警报管理器创建服务并安排它不是更有效吗?
【讨论】:
创建一个服务是一件很痛苦的事,所以要在一个服务上处理很多事情。我宁愿只使用计时器。 服务易于启动和停止。另外,它们不依赖于 UI 线程。所以是的,我会使用服务。 @IgorGanapolsky 是的。但是它们也很麻烦,如果它们没有意义并且一切都将通过服务完成,为什么还要为较小的操作创建异步任务、计时器和这些模块? @tony9099 AsyncTask 用于在完成后更新 UI 线程。服务不是。至于 Timer - 它既不存在也不存在 - 它与 AsyncTask 和 Service 之间的比较无关...... 我同意伊戈尔的观点。由于在设备旋转时(以及其他时间)如何杀死活动的问题,除非非常仔细地处理(在这些示例中没有),否则 AsyncTask 肯定会崩溃。真正的解决方案是咬紧牙关(是的,我知道,这很痛苦)并提供服务。【参考方案5】:接受的答案有问题。 使用 TimerTask() 通过处理程序激活异步任务是一个坏主意。在方向更改时,您必须记住取消计时器和处理程序调用。如果不是,它将在每次轮换时一次又一次地调用异步任务。 这将导致应用程序炸毁服务器(如果这是休息 http get 请求)而不是 X 时间 - 最终调用将是每秒实例多次调用。 (因为根据屏幕旋转的次数会有很多定时器)。如果在后台线程中运行的活动和任务很重,它可能会破坏应用程序。 如果您使用计时器,则将其设为类 memebr 并在 onStop() 上取消它:
TimerTask mDoAsynchronousTask;
@Override
public void onStop()
super.onStop();
mDoAsynchronousTask.cancel();
mHandler.removeCallbacks(null);
...
public void callAsynchronousTask(final boolean stopTimer)
Timer timer = new Timer();
mDoAsynchronousTask = new TimerTask()
@Override
public void run()
mHandler.post(new Runnable()
...
而是尽量避免异步任务,如果您必须使用调度程序服务来运行异步任务。或应用程序类,例如这个好主意: https://fattybeagle.com/2011/02/15/android-asynctasks-during-a-screen-rotation-part-ii/
或者使用简单的处理程序(没有计时器,只使用 postDelayed),也很好的做法是调用取消异步任务 onStop()。此代码使用 postDelayed 可以正常工作:
public class MainActivity extends AppCompatActivity
MyAsync myAsync = new MyAsync();
private final Handler mSendSSLMessageHandler = new Handler();
private final Runnable mSendSSLRunnable = new Runnable()
..
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected())
mSendSSLMessageHandler.post(mSendSSLRunnable);
else
..
@Override
public void onStop()
super.onStop();
if ( progressDialog!=null && progressDialog.isShowing() )
progressDialog.dismiss();
mSendSSLMessageHandler.removeCallbacks(mSendSSLRunnable);
myAsync.cancel(false);
private final Runnable mSendSSLRunnable = new Runnable()
@Override
public void run()
try
myAsync = new MyAsync();
myAsync.execute();
catch (Exception e)
// TODO Auto-generated catch block
mSendSSLMessageHandler.postDelayed(mSendSSLRunnable, 5000);
;
class MyAsync extends AsyncTask<Void, Void, String>
boolean running = true;
@Override
protected void onPreExecute()
super.onPreExecute();
progressDialog = ProgressDialog.show
(MainActivity.this, "downloading", "please wait");
@Override
protected String doInBackground(Void... voids)
if (!running)
return null;
String result = null;
try
URL url = new URL("http://192...");
HttpURLConnection urlConnection = (HttpURLConnection)
url.openConnection();
InputStream in = new BufferedInputStream (urlConnection.getInputStream());
result = inputStreamToString(in);
catch(Exception e)
e.printStackTrace();
return result;
@Override
protected void onCancelled()
boolean running = false;
@Override
protected void onPostExecute(String s)
super.onPostExecute(s);
progressDialog.dismiss();
try
..
catch (JSONException e)
textView.append("json is invalid");
e.printStackTrace();
【讨论】:
以上是关于如何在固定时间间隔后重复执行异步任务的主要内容,如果未能解决你的问题,请参考以下文章