1 导入 SDK
比如想要使用百度的定位工具,需要先把对应的 SDK 开发包下载好,解压过后通常会有一个 libs
目录,其中 jar
后缀的文件是 Java 层使用到的,而其他 so
文件是 Native 层要使用到的。此时就需要将各个文件放置到正确的位置。
打开原有的项目结构,在 app
模块下有一个 libs
目录,这里用来存放所有的 Jar 包,把对应的 Jar 文件复制到这里来。然后打开 src/main
目录,新建一个 jniLibs
目录用来放置 so
文件。
另外,在 app/build.gradle
文件中都会默认配置一下声明:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
这表示会将 libs
目录下的所有 jar
文件添加到当前的项目引用中,而在复制完文件后,就必须手动点击 AS 顶部工具栏中的 Sync
按钮。
2 定时任务
Android 中的定时任务一般有两种实现方式,一种是使用 Java API 中的 Timer
类,一种是使用 Android 中的 Alarm
机制。而 Timer
有一短板就是:每个手机都会有自己的休眠策略,在手机长时间不操作的情况下会自动让 CPU 进入睡眠状态,这就可能导致 Timer
中的定时任务无法正常运行,而 Alarm
机制则具有唤醒 CPU 的功能。
Alarm
机制主要借助 AlarmManager
类实现的,与 NotificationManager
类似,通过调用 Context
的 getSystemService()
方法可以获取到实例,此时需要传入的参数是 Context.ALARM_SERVICE
,然后调用 set()
方法就可以设置一个定时任务了,它接受三个参数:
AlarmManager
的工作类型,分别是:ELAPSED_REALTIME
:定时任务的触发时间从系统开机开始算起,但不会唤醒 CPUELAPSED_REALTIME_WAKEUP
:同上,但会唤醒 CPURTC
:定时任务的触发时间从1970-01-01
的 0 点开始算起,但不会唤醒 CPURTC_WAKEUP
:同上,但会唤醒 CPU
- 定时任务的延迟毫秒数
PendingIntent
例子代码如下:
public class LongRunningService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
// 这里执行具体逻辑操作,之所以在子线程中执行逻辑操作
// 是因为逻辑操作也是需要耗时的,如果放置到主线程中可能会对定时任务的准确性有影响
}).start();
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
int anHour = 60*60*1000; // 间隔一小时
long triggerAtTime = SystemClock.elapsedRealtime() + anHour;
Intent i = new Intent(this, LongRunningService.class);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
// 设置定时任务,现在的逻辑就是循环定时任务
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
return super.onStartCommand(intent, flags, startId);
}
}
使用
SystemClock.elapsedRealtime()
方法可以获取到系统开机执行所经历的毫秒数,System.currentTimeMillis()
方法可以获取当前时间戳
在 Android 4.4 系统中,系统会自动检测目前有多少 Alarm
任务存在,然后将触发事件相近的几个任务放在一起执行,从而大幅度地减少 CPU 被唤醒的次数,所以导致定时任务的时间变得不准确,解决方案是使用 AlarmManager
的 setExact()
方法代替 set
方法。
而在 Android 6 或以上的系统,又有一个 Doze
模式,当设备未接电源,屏幕关闭一段时间,就会进入 Doze
模式,此时系统会 CPU、网络、Alarm
等活动进行限制,不过系统并不会一直处于 Doze
模式,它会间歇地退出模式一段时间,用于完成它的同步操作、Alarm
任务等,随着设备进入 Doze
模式的时间越长,间隔退出 Doze
模式的时间也就会越长。
此时如果想要 Alarm
任务在 Doze
模式也执行,可以调用 AlarmManager
的 setAndAllowWhileIdle()
或 setExactAndAllowWhileIdle()
方法(这两个方法对比 set()
和 setExact()
方法)。