Android系统在用户长时间不操作时,为了节省资源,系统会选择休眠。在休眠过程中自定义的Timer、Handler、Thread、Service等都会暂停。而有时候这种机制会影响到我们程序的正常运行。
1、获取电源锁,并在执行完毕释放电源锁
public class WakeLockUtil
{
public static WakeLock wakeLock = null;
public static void acquireWakeLock(Activity myActivity)
{
if (null == wakeLock)
{
PowerManager pm = (PowerManager) myActivity.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.ON_AFTER_RELEASE | PowerManager.PARTIAL_WAKE_LOCK, "wakeLockUtil");
// PARTIAL_WAKE_LOCK:保持CPU 运转,屏幕和键盘灯有可能是关闭的 -- 最常用,保持CPU运转
// SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯
// SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯
// FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度
// ACQUIRE_CAUSES_WAKEUP:强制使屏幕亮起,这种锁主要针对一些必须通知用户的操作.
// ON_AFTER_RELEASE:当锁被释放时,保持屏幕亮起一段时间
if (null != wakeLock)
{
wakeLock.acquire(); // 立即获取电源锁
// wakeLock.acquire(2000); // 2秒后获取电源锁
}
}
}
public static void releaseWakeLock(Activity myActivity)
{
if (null != wakeLock)
{
wakeLock.release();
wakeLock = null;
}
}
}
2、
利用系统闹钟定时启动service
在service的onStartCommand方法中,定时10分钟后启动自己。
如果该service进程被系统杀死,闹钟事件可能不会触发,所以将此service设置为独立进程,并加入系统自启动中。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("LocationService","onStartCommand");
AlarmManager alarmService = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent alarmIntent = new Intent(this, LocationService.class);
//四个参数Flags:Flags为0代表该PendingIntent不带数据
//Flags为FLAG_CANCEL_CURRENT :如果AlarmManager管理的PendingIntent已经存在,那么将会取消当前的PendingIntent,从而创建一 个新的PendingIntent
//Flags为PendingIntent.FLAG_UPDATE_CURRENT,要通过extra数据来区分intent,应采用PendingIntent.FLAG_UPDATE_CURRENT,且每次num不一样
PendingIntent intentService = PendingIntent.getService(this, REQUESTCODE, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
//(1)set(int type,long startTime,PendingIntent pi);该方法用于设置一次性闹钟,第一个参数表示闹钟类型,第二个参数表示闹钟执行时间,第三个参数表示闹钟响应动作。
//(2)setRepeating(int type,long startTime,long intervalTime,PendingIntent pi);该方法用于设置重复闹钟,第一个参数表示闹钟类型,第二个参数表示闹钟首次执行时间,第三个参数表示闹钟两次执行的间隔时间,第三个参数表示闹钟响应动作。
//(3)setInexactRepeating(int type,long startTime,long intervalTime,PendingIntent pi);该方法也用于设置重复闹钟,与第二个方法相似,不过其两个闹钟执行的间隔时间不是固定的而已。
alarmService.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+10*60*1000,intentService);
// startLoc();
return super.onStartCommand(intent, flags, startId);
}
type: 闹钟的类型,有五种:
AlarmManager.ELAPSED_REALTIME表示闹钟在手机睡眠状态下不可用,该状态下闹钟使用相对时间(相对于系统启动开始);
AlarmManager.ELAPSED_REALTIME_WAKEUP表示闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟也使用相对时间;
AlarmManager.RTC表示闹钟在睡眠状态下不可用,该状态下闹钟使用绝对时间,即当前系统时间(
让定时任务的触发时间从1970年1月1日0点开始算起);
AlarmManager.RTC_WAKEUP表示闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟使用绝对时间,状态值为0;
AlarmManager.POWER_OFF_WAKEUP表示闹钟在手机关机状态下也能正常进行提示功能,所以是5个状态中用的最多的状态之一,该状态下闹钟也是用绝对时间;不过本状态好像受SDK版本影响,某些版本并不支持;
intervalTime:闹钟的第一次执行时间,以毫秒为单位,它必须和type相对应,比如type是AlarmManager.ELAPSED_REALTIME_WAKEUP类型,代表是使用的是相对时间,所以intervalTime必须也得是相对时间:
SystemClock.elapsedRealtime()。
SystemClock.elapsedRealtime()方法可以获取到系统开机至今所经历时间的毫秒数,
System.currentTimeMillis()方法可以获取到1970年1月1日0点至今所经历时间的毫秒数
同时定义开机广播接收和网络状态改变广播接收,启动service,来确保关机等因素导致闹钟动作不执行
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//收到开机广播
Intent intentService = new Intent();
intentService.setClass(context,LocationService.class);
context.startService(intentService);
}
}
public class NetworkConnectChangedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
ConnectivityManager manager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
Log.e("ConnectChangedReceiver", "CONNECTIVITY_ACTION");
NetworkInfo activeNetwork = manager.getActiveNetworkInfo();
if (activeNetwork != null) { // connected to the internet
if (activeNetwork.isConnected()) {
if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
// connected to wifi
Log.e("ConnectChangedReceiver", "当前WiFi连接可用 ");
FileHelper fHelper = new FileHelper(context);
fHelper.writeTxtToFile("当前为WiFi连接", "快递定位/", "location.txt");
Intent intentService = new Intent();
intentService.setClass(context,LocationService.class);
context.startService(intentService);
} else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
// connected to the mobile provider's data plan
Log.e("ConnectChangedReceiver", "当前移动网络连接可用 ");
FileHelper fHelper = new FileHelper(context);
fHelper.writeTxtToFile("当前移动网络连接", "快递定位/", "location.txt");
Intent intentService = new Intent();
intentService.setClass(context,LocationService.class);
context.startService(intentService);
}
} else {
Log.e("ConnectChangedReceiver", "当前没有网络连接,请确保你已经打开网络 ");
FileHelper fHelper = new FileHelper(context);
fHelper.writeTxtToFile("当前没有网络连接", "快递定位/", "location.txt");
}
Log.e("ConnectChangedReceiver", "info.getTypeName()" + activeNetwork.getTypeName());
Log.e("ConnectChangedReceiver", "getSubtypeName()" + activeNetwork.getSubtypeName());
Log.e("ConnectChangedReceiver", "getState()" + activeNetwork.getState());
Log.e("ConnectChangedReceiver", "getDetailedState()"
+ activeNetwork.getDetailedState().name());
Log.e("ConnectChangedReceiver", "getDetailedState()" + activeNetwork.getExtraInfo());
Log.e("ConnectChangedReceiver", "getType()" + activeNetwork.getType());
} else { // not connected to the internet
Log.e("ConnectChangedReceiver", "当前没有网络连接,请确保你已经打开网络 ");
FileHelper fHelper = new FileHelper(context);
fHelper.writeTxtToFile("当前没有网络连接", "快递定位/", "location.txt");
}
}
}
}