首页 编程 软件学院 查看内容

android计时与系统休眠

2015-3-5 22:03 951 0

摘要: TIP:可能写的有点仓促,具体的可以联系我(*^__^*) 一.摘要:       之前做项目的时候,修改一个倒计时秒表,本来以为比较简单,但是发现很多有趣的...
关键词: nbsp android import AlarmManager 休眠 Intent PendingIntent 一个 sendIntent SystemClock

TIP:可能写的有点仓促,具体的可以联系我(*^__^*) 一.摘要:       之前做项目的时候,修改一个倒计时秒表,本来以为比较简单,但是发现很多有趣的东西。我们项目里面用的是Timer计时的方法,但是,当系统休眠的时 候,Timer也是处于休眠状态的。后来,我改进了几个方法,一个是handle+message的方法,还有一个是handle+runnable的方 法,还有handle+Thread的方法。但是同样发现系统休眠的时候,这些同样是处于休眠状态的。后来上网查找了一下,这和android的架构有 关: 二.原理         Android手机有两个处理器,一个叫Application Processor(AP),一个叫Baseband Processor(BP)。AP是ARM架构的处理器,用于运行Linux+Android系统;BP用于运行实时操作系统(RTOS),通讯协议栈运 行于BP的RTOS之上。非通话时间,BP的能耗基本上在5mA左右,而AP只要处于非休眠状态,能耗至少在50mA以上,执行图形运算时会更高。另外 LCD工作时功耗在100mA左右,WIFI也在100mA左右。一般手机待机时,AP、LCD、WIFI均进入休眠状态,这时Android中应用程序的代码也会停止执行。 Android为了确保应用程序中关键代码的正确执行,提供了Wake Lock的API,AlarmManager这个类使用的是BP的芯片,使得应用程序有权限通过代码阻止AP进入休眠状态。但如果不领会Android设 计者的意图而滥用Wake Lock API,为了自身程序在后台的正常工作而长时间阻止AP进入休眠状态,就会成为待机电池杀手。       首先,完全没必要担心AP休眠会导致收不到消息推送。通讯协议栈运行于BP,一旦收到数据包,BP会将AP唤醒,唤醒的时间足够AP执行代码完成对收到的 数据包的处理过程。其它的如Connectivity事件触发时AP同样会被唤醒。那么唯一的问题就是程序如何执行向服务器发送心跳包的逻辑。你显然不能 靠AP来做心跳计时。Android提供的Alarm Manager就是来解决这个问题的。Alarm应该是BP计时(或其它某个带石英钟的芯片,不太确定,但绝对不是AP),触发时唤醒AP执行程序代码。 那么Wake Lock API有啥用呢?比如心跳包从请求到应答,比如断线重连重新登陆这些关键逻辑的执行过程,就需要Wake Lock来保护。而一旦一个关键逻辑执行成功,就应该立即释放掉Wake Lock了。两次心跳请求间隔5到10分钟,基本不会怎么耗电。除非网络不稳定,频繁断线重连,那种情况办法不多。       网上有说使用AlarmManager,因为AlarmManager 是Android 系统封装的用于管理 RTC 的模块,RTC (Real Time Clock) 是一个独立的硬件时钟,可以在 CPU 休眠时正常运行,在预设的时间到达时,通过中断唤醒 CPU。   三.实验       后来,本人使用AlarmManager,但是又碰到不准的问题,而且当系统繁忙的时候(比如刚开机前一分钟),更为明显,后来查看官方的API说明。因为我之前使用的方法大致是下面的原理: [java] view plaincopyprint? AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);   Intent intent = new Intent("com.liu.alarm.ACTION_SEND");   PendingIntent sendIntent = PendingIntent.getBroadcast(this, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT);   am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,SystemClock.elapsedRealtime() + 1000,1000, sendIntent); 然后注册一个广播接收器接收 public void onReceive(final Context context, Intent intent) {   需要的操作;}       我们看看官方给出的API说明:Note: as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whosetargetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.意思大概是说19或者19以后,为了优化电池,该计时操作不准确了(可能在定义时间之后响应),但是19之前的任然准确。 If your application has strong ordering requirements there are other APIs that you can use to get the necessary behavior; see setWindow(int, long, long, PendingIntent) andsetExact(int, long, PendingIntent).意思是虽然19(包括)之后可能不准确,但是android保留了两个接口,这两个接口是准确的。本人于是使用了这其中一个。 方法如下    TIP:前提是确保你的API是19的或更高,否则做下判断 public static boolean isKitKatOrLater() {  return Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2; } [java] view plaincopyprint? AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);   Intent intent = new Intent("com.liu.alarm.ACTION_SEND");   PendingIntent sendIntent = PendingIntent.getBroadcast(this, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT);</span>   [java] view plaincopyprint? if(isKitKatOrLater(){ am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,SystemClock.elapsedRealtime() + 1000, sendIntent); }else{ am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,SystemClock.elapsedRealtime() + 1000, sendIntent); } 然后注册一个广播接收器接收 [java] view plaincopyprint? public void onReceive(final Context context, Intent intent) { if(isKitKatOrLater(){ am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,SystemClock.elapsedRealtime() + 1000, sendIntent);  }else{ am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,SystemClock.elapsedRealtime() + 1000, sendIntent); }   [java] view plaincopyprint? if(isKitKatOrLater(){ am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,SystemClock.elapsedRealtime() + 1000, sendIntent);    需要的操作;}        但是后来有发现,即使使用了精确的时间计时,但是在系统刚开机的一分钟内计时,仍然会有不及时响应的情况,所以,后来自己想了一下,毕竟是两块芯片,多 进程多线程还要考虑好多同步的问题,两块芯片也不可能配合的那么天衣无缝,假如一块特别繁忙的时候。所以,后来我参考源码的方法:正常情况下使用线程或者 Timer计时,并且使用AlarmManager设定一个计时结束的时间,当执行Activity的Onpause的时候使用AlarmManager的计时响应。当Onresume的时候,根据走过的时间刷新界面。下面是我全部的代码 [java] view plaincopyprint?/**  * 2014-12-05 BenMin FEIXUN_DESKCLOCK_BENMIN_001  *     modify PWEUN-4141 to remind the user when the timing is over.  * 2014-12-17 BenMin FEIXUN_DESKCLOCK_BENMIN_002  *     modify to ensure the fragment attached to Activity when using getResources() function.  * 2014-12-26 BenMin FEIXUN_DESKCLOCK_BENMIN_003  *     modify PLGN-489 to stop the ring when press the back menu.  */  package com.phicomm.keyer;    import java.util.Timer;  import java.util.TimerTask;    import android.R.integer;  import android.app.AlarmManager;  import android.app.AlertDialog;  import android.app.PendingIntent;  import android.content.BroadcastReceiver;  import android.content.Context;  import android.content.DialogInterface;  import android.content.Intent;  import android.content.IntentFilter;  import android.media.MediaPlayer;  import android.os.Build;  import android.os.Bundle;  import android.os.Handler;  import android.os.Message;  import android.os.SystemClock;  import android.util.Log;  import android.view.LayoutInflater;  import android.view.View;  import android.view.ViewGroup;  import android.view.View.OnClickListener;  import android.widget.Button;  import android.widget.LinearLayout;  import android.widget.NumberPicker;  import android.widget.NumberPicker.Formatter;  import android.widget.NumberPicker.OnValueChangeListener;  import android.widget.TextView;    import com.phicomm.deskclock.DeskClockFragment;  import com.phicomm.deskclock.FxDeskClock;  import com.phicomm.deskclock.R;    public class FxKeyerFragment extends DeskClockFragment implements          OnClickListener, Formatter, OnValueChangeListener {        private NumberPicker keyerHour;      private NumberPicker keyerMinute;      private NumberPicker keyerSecond;        private Button kbtnStart;      private Button kbtnPause;      private Button kbtnReset;      private LinearLayout time;      private TextView hour;      private TextView minute;  
  • 声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

    路过

    雷人

    握手

    鲜花

    鸡蛋

    最新评论

    返回顶部