Android中经常会遇到这样一种情况,有些操作需要在未来的某个时间执行1次或者多次,我们就需要完成这样的定时功能,我总结了几种具有这种功能的方法,以及他们的适合使用的场景:
第一种方法:使用定时器Timer
Timer timer = new Timer();
timer.schedule();
public void schedule(TimerTask task, long delay)
public void schedule(TimerTask task, long delay, long period)
这个可以看到schedule()方法需要传入两个参数或者传入三个参数 :
1.第一个参数:TimerTask是一个抽象类,它里面有个抽象的run()方法
public abstract void run();
public class MyTimerTask extends TimerTask {
@Override
public void run() {
doSomething();//在这里执行你的任务 这个run()方法可不是在主线程中执行的哦!
}
}
我们的任务就是在这个run()方法里面完成的
2.第二个参数是一个long类型,表示会在你给的这个数值毫秒后第一次执行任务,如果想立刻执行 这个参数可以给0。
3. 第三个参数也是一个long类型,它表示会在第一次执行完该任务后,每次经过多长时间去循环的执行任务,如果你的任务只想执行一次,这个参数可以不传。
Timer的使用场景和注意事项:
Timer的使用可能会给程序带来线程安全方面的问题,比如Timer的工作线程中要使用共享数据,就要进行正确的同步。
第二种方法:使用Android的Alarm机制 (AlarmManager)
使用步骤:
(1)首先获取AlarmManager的实例
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
(2)通过调用AlarmManager.set()方法就可以设置一个定时任务
public void set(int type, long triggerAtMillis, PendingIntent operation) {}
这里需要传入3个参数 我们来分析一个这3个参数的含义:
(1)第一个参数是一个整型参数,用于指定 AlarmManager 的工作类型,有四种值可选,分别是: ELAPSED_REALTIME、ELAPSED_REALTIME_WAKEUP、RTC 和 RTC_WAKEUP。
ELAPSED_REALTIME : 表示让定时任务的触发时间从系统开机开始算起,但不会唤醒CPU。
ELAPSED_REALTIME_WAKEUP : 同样表示让定时任务的触发时间从系统开机开始算起,但会唤醒CPU。
RTC : 表示让定时任务的触发时间从 1970 年 1 月 1 日 0点开始算起,但不会唤醒CPU。
RTC_WAKEUP : 同样表示让定时任务的触发时间从 1970 年 1 月 1 日 0点开始算起,但会唤醒CPU。
使用 SystemClock.elapsedRealtime()方法可以获取到系统开机至今所经历时间的毫秒数,使用 System.currentTimeMillis()方法可以获取到 1970 年 1 月 1 日 0 点至今所经历时间的毫秒数。
(2)第二个参数是一个long类型的参数,表示定时任务触发的时间,以毫秒为单位。
(3)第三个参数是一个PendingIntent,相信做过Notification的朋友对这个肯定不会陌生,
getService(Context context, int requestCode, Intent intent, int flags)
getActivity(Context context, int requestCode, Intent intent, int flags)
getBroadcast(Context context, int requestCode, Intent intent, int flags)
可以看到它即可以启动一个activity,也可以发出一个广播,还可以启动一个服务。
这里我们里我们一般会调用 getBroadcast()方法来获取一个能够执行广播的 PendingIntent。这样当定时任务被触发的时候,广播接收器的 onReceive()方法就可以得到执行。
举一个例子:
创建一个广播接收者
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context,MyService.class);
context.startService(i);
}
}
//在服务里面执行任务
public class MyService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
//这里用来执行你的任务
doSomething();
}
}).start();
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
int delay = 10 * 1000 ;//每隔10秒执行一次任务
long triggerAtTime = SystemClock.elapsedRealtime() + delay;
Intent i = new Intent(this,MyReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, i, 0);
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pendingIntent);
return super.onStartCommand(intent, flags, startId);
}
}
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, LongRunningService.class);
startService(intent);
}
}
可以看到这个例子是在后台服务里面开启一个线程去执行定时任务的,每隔十秒就会去执行一次这个任务,最后别忘了广播和服务都需要在清单文件中进行配置哦!
第三种方法: 使用Handler的postDelayed()方法来完成定时任务,其实就是发了一个延时广播 ,如果想知道这个方法的具体实现流程,可以去看Handler的源码。
public final boolean postDelayed(Runnable r, long delayMillis);
public class MainActivity extends AppCompatActivity {
Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler.postDelayed(new MyRunnable(),2000);
}
public class MyRunnable implements Runnable{
@Override
public void run() {
String name = Thread.currentThread().getName();
Log.i("fqLog","threadName:"+name); // I/fqLog: threadName:main
mHandler.postDelayed(this,2000);
}
}
}
可以看到这里的run()是执行在主线程的 , 如果该任务是个耗时操作,则需要开一个线程去执行。