android 自动任务,Android定时任务

前言

最近项目上有这么一个需求,实时监控车辆信息,要求每隔3秒钟刷新一次地图上的车辆位置信息。我的想法是先定时从服务端获取数据存储到SharedPreferences中,然后再定时从SharedPreferences中获取数据显示到地图。对这个逻辑我不满意,但是一时也找不到别的方法,望大神指教。

在使用定时任务的时候,最开始想到的是Timer。无意中看到一种Handler加Runnable方法,觉得还是有必要记录一下。

Timer方法

Timer一般结合TimerTask使用。先看TimerTask,它是一个抽象类,里面有一个run()方法。

public abstract class TimerTask implements Runnable {

......

/**

* The action to be performed by this timer task.

*/

public abstract void run();

......

}

查看TimerTask的源码,可以看到TimerTask其实就是实现了Runnable方法,也就是说,通过Timer执行定时任务,其实就是通过一个线程做到的。

再看Timer,它其实就是一个线程管理器,通过schedule方法来开启一个线程,并实现任务调度。Timer工作机制下篇文章再撸,这里简单理解并记录使用方法。

/**

* A facility for threads to schedule tasks for future execution in a

* background thread. Tasks may be scheduled for one-time execution, or for

* repeated execution at regular intervals.

......

*

After the last live reference to a Timer object goes away

* and all outstanding tasks have completed execution, the timer's task

* execution thread terminates gracefully (and becomes subject to garbage

* collection). However, this can take arbitrarily long to occur. By

* default, the task execution thread does not run as a daemon thread,

* so it is capable of keeping an application from terminating. If a caller

* wants to terminate a timer's task execution thread rapidly, the caller

* should invoke the timer's cancel method.

......

*

This class is thread-safe: multiple threads can share a single

* Timer object without the need for external synchronization.

*

*

This class does not offer real-time guarantees: it schedules

* tasks using the Object.wait(long) method.

......

*/

截几段源码注释

当所有TimerTask任务完成,并且Timer引用为空的时候,会被GC回收。

一般程序退出时,TimerTask任务会跟随着终止,主动结束则用Timer的cancel方法。

多个线程可共用一个Timer,也就是多个TimerTask可以共用一个Timer。

Timer不能保证实时任务,所有的任务都得等待调度。

说人话,来个比喻。Timer是一个码头大哥(简称T老大),手底下有一帮小弟(Thread,简称w)跟一个管家(schedule,简称S管家)。TimerTask是一个商人(简称K老板),手底下有一帮业务经理(实例化的timerTask,负责某个具体的任务,简称p经理)。他有一批货要在码头卸载。于是乎,K老板找到了T老大。

商人:T老大,我有一批货要在贵码头卸载,能不能帮帮忙,价钱好商量!

老大:路过的都是朋友,好说!好说!

商人:我这批货很急,能不能立马就下?(想要实时)

老大:先来后到,这是规矩啊!能不能马上卸货,就要看K老板您的运气了。要是运气好,就能立马卸货,要是运气不好,等个一年半载都有可能啊。哈哈哈、、、还望海涵!(无法保证实时)

商人:那就只能等T老大的好消息了。

商人就只能在码头排队等候了。某天,轮到K老板卸货了。

老大:K老板久等了!接下来在下静候吩咐。

商人:岂敢!只是鄙人的货有点杂,需要送到不同的地方,还要麻烦T老大啊。

老大:小事一桩!只管说给我的S管家听,保证K老板满意!(多个任务可共用一个Timer)

管家:K老板只管吩咐,老夫一定保质保量完成。

商人:那就多谢S管家!具体的任务我让我的经理们给您汇报。

得到老板的指示,S管家跟p经理们开始干活了。一个经理代表一个具体的任务,一个w代表一个线程。

schedule的四个方法

schedule(task, date),指定时间执行一次

经理1:S管家,这批布匹要晚上6点往城东的布衣店送去。

管家:w1,你来,把这个送到城东的布衣店去。晚上6点就去。

schedule(task, delay), 从现在起,delay毫秒后,执行一次

经理2:S管家,这批水果过两个小时往城东的水果店送去。

管家:w2,你来,两个小时后,开始往城东的水果店送。

schedule(task, firstTime, period),firstTime时刻开始,每隔period毫秒执行一次

经理3:S管家,这批黄金要明天凌晨4点开始,每隔1小时往城南的金铺送一次。

管家:w3,你来,明天早起,凌晨4点开始干活,没喊停,就一直干。

schedule(task, delay, period),现在开始,delay毫秒后,每隔period毫秒执行一次

经理4:S管家,这批书要往城北的陈家送去,2个小时后他们家才有人,每隔一个小时送一次。

管家:w4,你来,吃点东西,2个小时后往陈家送书,一个小时送一次,没喊停,就一直干。

若干天后,S管家没有收到K老板的支付款,便向T老大汇报。

管家:老大,K老板不守信用啊,款项没有及时到账,如何处理?

老大:不守规矩,以后不跟他玩了,让他找别人。(cancel方法,主动结束timerTask)

商人:那我不得重新找码头了?T老大,通融通融吧。

老大:没门儿!(一旦取消,要想继续只能重新new一个Timer)

待K老板交足款项后,只能重新排队等待卸货。某天,海啸来了,码头被毁(程序退出),一切都没了(timerTask被动结束)。

啰嗦了半天,不知道说明白没有。还是上代码,直观显示。

......

private Timer timer = new Timer();

......

private void useTimer() {

//多个任务可共享一个timer

timer.schedule(new MarkerTask(), 1000, 2000);

timer.schedule(new MapTask(), 1000, 3000);

}

......

@Override

public void onClick(View v) {

switch (v.getId()) {

case R.id.stopRefresh://取消定时任务

Log.d("MainActivity", "onClick: stopRefresh");

timer.cancel();

break;

case R.id.continueRefresh://继续定时任务

Log.d("MainActivity", "onClick: continueRefresh");

Timer timer1 = new Timer();

timer1.schedule(new MarkerTask(), 1000, 2000);

timer1.schedule(new MapTask(), 1, 3000);

break;

default:

break;

}

}

......

private class MapTask extends TimerTask {

@Override

public void run() {

refreshMapViewDetail();

}

}

private class MarkerTask extends TimerTask {

@Override

public void run() {

randomMarkerDetail();

}

}

......

Handler加Runnable方法

这个方法的核心思想就是在Runnable内部,将本runnable继续插入主线程队列中。理解了Handler的工作机制,这个方法就更好理解,这里直接贴代码。

......

mapRefreshRun = new Runnable() {

@Override

public void run() {

//更新地图上的数据

refreshMapViewDetail();

//将本runnable继续插入主线程中,再次执行。

handler.postDelayed(this, 3000);

}

};

handler.postDelayed(mapRefreshRun, 1);

......

@Override

public void onClick(View v) {

switch (v.getId()) {

case R.id.stopRefresh:

Log.d("MainActivity", "onClick: stopRefresh");

handler.removeCallbacks(mapRefreshRun);

break;

case R.id.continueRefresh:

Log.d("MainActivity", "onClick: continueRefresh");

handler.postDelayed(mapRefreshRun, 1);

break;

default:

break;

}

}

......

要取消任务直接用Handler的removeCallbacks方法,要继续任务,则将任务继续插入主线程中。

总结

Timer方法是新建子线程,在子线程中执行想要的动作,故不可以直接更改UI;

Handler方法是在主线程中,插入Runnable,可以直接更改UI。对界面的操作,比如点击、滑动这些都是要在主线程中排队进行的,如果我们这个定时任务的period太短,比如设为0,会否影响用户的操作响应速度呢?在这个简单的Demo中,试了下,没有太明显的感觉,但这个问题还是要留意。

本Demo的代码请移步:GitHub

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值