新建一个Service来模拟后台执行的程序,PollingService.java:

package com.ryantang.rtpollingdemo;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
/**
* Polling service
* @Author Ryan
* @Create 2013-7-13 涓婂崍10:18:44
*/
public class PollingService extends Service { public static final String ACTION = "com.ryantang.service.PollingService"; private Notification mNotification;
private NotificationManager mManager; @Override
public IBinder onBind(Intent intent) {
return null;
} @Override
public void onCreate() {
initNotifiManager();
} @Override
public void onStart(Intent intent, int startId) {
new PollingThread().start();
}
//初始化通知栏配置
private void initNotifiManager() {
mManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
int icon = R.drawable.ic_launcher;
mNotification = new Notification();
mNotification.icon = icon;
mNotification.tickerText = "New Message";
mNotification.defaults |= Notification.DEFAULT_SOUND;
mNotification.flags = Notification.FLAG_AUTO_CANCEL;
}
//弹出Notification
private void showNotification() {
mNotification.when = System.currentTimeMillis();
//Navigator to the new activity when click the notification title
Intent i = new Intent(this, MessageActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, i,
Intent.FLAG_ACTIVITY_NEW_TASK);
mNotification.setLatestEventInfo(this,
getResources().getString(R.string.app_name), "You have new message!", pendingIntent);
mManager.notify(0, mNotification);
} /**
* Polling thread
* 模拟向Server轮询的异步线程
* @Author Ryan
* @Create 2013-7-13 涓婂崍10:18:34
*/
int count = 0;
class PollingThread extends Thread {
@Override
public void run() {
System.out.println("Polling...");
count ++;
//当计数能被5整除时弹出通知
if (count % 5 == 0) {
showNotification();
System.out.println("New message!");
}
}
} @Override
public void onDestroy() {
super.onDestroy();
System.out.println("Service:onDestroy");
} }

别望了在AndroidManifest.xml中注册Service:

<service android:name="com.ryantang.rtpollingdemo.PollingService">
<intent-filter>
<action android:name="com.ryantang.service.PollingService"/>
</intent-filter>
</service>

当计数能被5整除时弹出通知,点击通知后进入MessageActivity.java:

package com.ryantang.rtpollingdemo;

import android.app.Activity;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Bundle; public class MessageActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_message);
System.out.println("新的activity");
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); manager.cancelAll();
}
}

使用AlarmManager封装已给PollingUtils.java来执行Service的启动和停止,PollingUtils.java:

package com.ryantang.rtpollingdemo;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
/**
* Polling Tools
* @Author Ryan
* @Create 2013-7-13 涓婂崍10:14:43
*/
public class PollingUtils { /**开启轮询服务
* @param context
* @param seconds 定期执行的时间间隔
* @param cls
* @param action
*/
public static void startPollingService(Context context, int seconds, Class<?> cls,String action) {
//获取AlarmManager系统服务
AlarmManager manager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
//包装需要执行Service的Intent
Intent intent = new Intent(context, cls);
intent.setAction(action);
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
//触发服务的起始时间
long triggerAtTime = SystemClock.elapsedRealtime();
//使用AlarmManager的setRepeating方法设置定期执行时间间隔(seconds秒)和需要执行的Service
manager.setRepeating(AlarmManager.ELAPSED_REALTIME, triggerAtTime,
seconds * 1000, pendingIntent);//第二个参数与第一个参数有对应的关系,ELAPSED_REALTIME对应的为SystemClock.elapsedRealTime,RTC对应的为System.currentTimeMills()
} /**
* 停止轮询服务
* @param context
* @param cls
* @param action
*/
public static void stopPollingService(Context context, Class<?> cls,String action) {
//获取AlarmManager系统服务
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, cls);
intent.setAction(action);//需要与启动的action一致,负责无法取消定时任务
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
//取消正在执行的服务
manager.cancel(pendingIntent);
}
}

最后在主程序中执行,MainActivity.java:

package com.ryantang.rtpollingdemo;

import android.app.Activity;
import android.os.Bundle; public class MainActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Start polling service
System.out.println("Start polling service...");
PollingUtils.startPollingService(this, 30, PollingService.class,PollingService.ACTION);// PollingService.ACTION与AndroidManifest.xml一一对应
} @Override
protected void onDestroy() {
super.onDestroy();
// Stop polling service
System.out.println("Stop polling service...");
PollingUtils.stopPollingService(this, PollingService.class,PollingService.ACTION);
} }

Android之AlarmManager(全局定时器/闹钟)指定时长或以周期形式执行某项操作

(1)在指定时长后执行某项操作

//操作:发送一个广播,广播接收后Toast提示定时操作完成
Intent intent =new Intent(Main.this, alarmreceiver.class);
intent.setAction("short");
PendingIntent sender=
PendingIntent.getBroadcast(Main.this, 0, intent, 0); //设定一个五秒后的时间
Calendar calendar=Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 5); AlarmManager alarm=(AlarmManager)getSystemService(ALARM_SERVICE);
alarm.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender);
//或者以下面方式简化
//alarm.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+5*1000, sender);
//注意:receiver记得在manifest.xml注册,使用的是静态的广播消息机制
public static class alarmreceiver extends BroadcastReceiver{ @Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if(intent.getAction().equals("short")){
Toast.makeText(context, "short alarm", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(context, "repeating alarm",Toast.LENGTH_LONG).show();
}
}
}
//AndroidManifest.xml中需要注册广播接收器
<receiver android:name="" >
<intent-filter >
<action android:name="short"><action />
</intent-filter>
</receiver>

AlarmManager类型如下:

AlarmManager.RTC,硬件闹钟,不唤醒手机(也可能是其它设备)休眠;当手机休眠时不发射闹钟。

AlarmManager.RTC_WAKEUP,硬件闹钟,当闹钟发射时唤醒手机休眠;

AlarmManager.ELAPSED_REALTIME,真实时间流逝闹钟,不唤醒手机休眠;在指定的延时过后,发送广播,但不唤醒设备。

AlarmManager.ELAPSED_REALTIME_WAKEUP,真实时间流逝闹钟,当闹钟发射时唤醒手机休眠;

RTC闹钟和ELAPSED_REALTIME最大的差别就是前者可以通过修改手机时间触发闹钟事件,后者要通过真实时间的流逝,即使在休眠状态,时间也会被计算。

(2)周期性的执行某项操作

Intent intent =new Intent(Main.this, alarmreceiver.class);
intent.setAction("repeating");
PendingIntent sender=PendingIntent
.getBroadcast(Main.this, 0, intent, 0);
//开始时间
long firstime=SystemClock.elapsedRealtime();
AlarmManager am=(AlarmManager)getSystemService(ALARM_SERVICE);
 //5秒一个周期,不停的发送广播
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstime, 5*1000, sender);

AlarmManager的setRepeating()相当于Timer的Schedule(task,delay,peroid);有点差异的地方时Timer这个方法是指定延迟多长时间以后开始周期性的执行task;

AlarmManager的取消:(其中需要注意的是取消的Intent必须与启动Intent保持绝对一致才能支持取消

Intent intent =new Intent(Main.this, alarmreceiver.class);
intent.setAction("repeating");
PendingIntent sender=PendingIntent
.getBroadcast(Main.this, 0, intent, 0);
AlarmManager alarm=(AlarmManager)getSystemService(ALARM_SERVICE);
alarm.cancel(sender);

当然还需要写一个静态的广播接收器。

*****************************************2015-09-07 08:21:18***************************************************

周期性执行选用的闹钟类型推荐AlarmManager.RTC_WAKEUP,经测试还是定时时间还是比较准确的,SystemClock.elapsedRealTime()指的的从计算机起始时间1970-1-1算1起,而System.currentTimeMills()指的是系统开机时间算起。

***********************************更新:2015-09-06 08:53:15*******************************************

Android的碎片化严重,定制的ROM被国内厂商修改了很多,对于定时任务MIUI作为代表,开发者遇到到很多这样的情况,定时任务偏离,多半的原因是考虑到了系统休眠、降低CUP运行效率等等以达到省电的效果,这里就介绍另一种方法解决:PowerManager.WakeLock来实现要求的功能。

PowerManager:给予控制设备电量状态的权限

PowerManager.WakeLock:让系统知道你需要设置在工作状态上

Android中通过各种Lock锁对电源进行控制,需要注意的是加锁和解锁必须成对出现

首先获取权限:

<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.DEVICE_POWER"/>

有时候Eclipse会提示系统应用才能需要这个权限,解决的办法是将项目Clean下即可。WakeLock的设置是Activity级别的,不是针对整个Application应用的。

package com.eyu.wake_lock;  

import android.app.Activity;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock; public class Wake_lockActivity extends Activity { private boolean iswakeLock = true;// 是否常亮
private WakeLock wakeLock; /** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); } @Override
protected void onResume() {
// TODO Auto-generated method stub
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
| PowerManager.ON_AFTER_RELEASE, "DPA"); if (iswakeLock) {
wakeLock.acquire();
}
super.onResume(); } @Override
protected void onPause() {
// TODO Auto-generated method stub
super.onDestroy();
if (wakeLock != null) {
wakeLock.release();
}
android.os.Process.killProcess(android.os.Process.myPid());
} }

通常在onRusume方法中将获得到的锁使用acquire()方法来保持唤醒,在onPause方法中使用release()方法来释放掉该锁,利用Activity的生命周期来巧妙的使这两种方法成对的出现。

PowerManager和WakeLock的操作步骤
  1. PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);通过 Context.getSystemService().方法获取PowerManager实例。
  2. 然后通过PowerManager的newWakeLock((int flags, String tag)来生成WakeLock实例。int Flags指示要获取哪种WakeLock,不同的Lock对cpu 、屏幕、键盘灯有不同影响。
  3. 获取WakeLock实例后通过acquire()获取相应的锁,然后进行其他业务逻辑的操作,最后使用release()释放(释放是必须的)。

关于int flags

  各种锁的类型对CPU 、屏幕、键盘的影响:

  PARTIAL_WAKE_LOCK:保持CPU 运转,屏幕和键盘灯有可能是关闭的。

  SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯

  SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯

  FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度

  ACQUIRE_CAUSES_WAKEUP:正常唤醒锁实际上并不打开屏幕,但是,一旦打开就会一直保持。当获得wakelock,这个标志会使屏幕或/和键盘立即打开。一个典型的使用就是可以立即看到那些对用户重要的通知。

  ON_AFTER_RELEASE:设置了这个标志,当wakelock释放时用户activity计时器会被重置,导致照明持续一段时间。

***********************************更新:2015-09-15 20:24:29*******************************************

使用AlarmManager就不需要设备锁了,测试过有时候还会导致程序报错,测试手机小米2S,先后试过MIUI、Lewa等第三方Rom,后来刷入Android4.0.3启动定时任务,毫秒不差 。

                                     

最新文章

  1. Failed deleting my ephemeral node
  2. Java 命令行运行参数大全
  3. linux下logrotate 配置和理解
  4. Windbg 线程状态笔记
  5. QT中实现中文的显示与国际化
  6. 13test02:信用卡校验
  7. 中文变英文字母(ios)
  8. Windows 窗体启动和关闭的事件顺序
  9. [Webpack 2] Maintain sane file sizes with webpack code splitting
  10. SetTimer 和 OnTimer 的使用
  11. c 中可变参数的实现
  12. 开心菜鸟系列----变量的解读(javascript入门篇)
  13. linxu添加定时任务
  14. win9x_win2k下对物理磁盘的操作
  15. python_爬校花图片
  16. Django URL (路由系统)
  17. Linux协议栈-netfilter-conntrack
  18. Remove Duplicate Letters(Java 递归与非递归)
  19. mac os x lipo 工具
  20. phalcon安装-遇坑php-config is not installed 解决方法

热门文章

  1. assert.strictEqual()
  2. SpringBoot02 Controller的使用、数据库操作、事物管理、修改banner
  3. 8、非root权限下安装perl以及perl模块
  4. 6.7 通过终端连接jboss,连接数据库
  5. Spring入门第三十课
  6. Umbraco Examine Search (Lucene.net) french accent
  7. uva 1614奇怪的股市(归纳法证明,贪心)
  8. 清北刷题冲刺 10-29 a.m
  9. 洛谷P1275 魔板
  10. bzoj2055: 80人环游世界(可行流)