后臺(tái)任務(wù) - 保持設(shè)備喚醒狀態(tài)

當(dāng)Android設(shè)備空閑時(shí)呜叫,屏幕會(huì)變暗空繁,然后關(guān)閉屏幕,最后會(huì)停止CPU的運(yùn)行朱庆,這樣可以防止電池電量掉的快盛泡。在休眠過(guò)程中自定義的Timer、Handler娱颊、Thread傲诵、Service等都會(huì)暫停凯砍。但有些時(shí)候我們需要改變Android系統(tǒng)默認(rèn)的這種狀態(tài):比如玩游戲時(shí)我們需要保持屏幕常亮,比如一些下載操作不需要屏幕常亮但需要CPU一直運(yùn)行直到任務(wù)完成拴竹。

保持屏幕常亮

  • 最好的方式是在Activity中使用FLAG_KEEP_SCREEN_ON 的Flag悟衩。
      public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
      }
}

這個(gè)方法的好處是不像喚醒鎖(wake locks),需要一些特定的權(quán)限(permission)栓拜。并且能正確管理不同app之間的切換座泳,不用擔(dān)心無(wú)用資源的釋放問(wèn)題。

  • 另一個(gè)方式是在布局文件中使用android:keepScreenOn屬性:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true">
...
</RelativeLayout>

android:keepScreenOn = ” true “的作用和FLAG_KEEP_SCREEN_ON一樣幕与。使用代碼的好處是你允許你在需要的地方關(guān)閉屏幕挑势。

注意:一般不需要人為的去掉FLAG_KEEP_SCREEN_ON的flag,windowManager會(huì)管理好程序進(jìn)入后臺(tái)回到前臺(tái)的的操作啦鸣。如果確實(shí)需要手動(dòng)清掉常亮的flag潮饱,使用:

getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)

保持CPU運(yùn)行

需要使用PowerManager這個(gè)系統(tǒng)服務(wù)的喚醒鎖(wake locks)特征來(lái)保持CPU處于喚醒狀態(tài)。喚醒鎖允許程序控制宿主設(shè)備的電量狀態(tài)诫给。創(chuàng)建和持有喚醒鎖對(duì)電池的續(xù)航有較大的影響香拉,所以,除非是真的需要喚醒鎖完成盡可能短的時(shí)間在后臺(tái)完成的任務(wù)時(shí)才使用它蝙搔。比如在Acitivity中就沒(méi)必要用了缕溉。如果需要關(guān)閉屏幕,使用上述的FLAG_KEEP_SCREEN_ON吃型。

只有一種合理的使用場(chǎng)景证鸥,是在使用后臺(tái)服務(wù)在屏幕關(guān)閉情況下hold住CPU完成一些工作。 要使用喚醒鎖勤晚,如果不使用喚醒鎖來(lái)執(zhí)行后臺(tái)服務(wù)枉层,不能保證因CPU休眠未來(lái)的某個(gè)時(shí)刻任務(wù)會(huì)停止,這不是我們想要的赐写。 (有的人可能認(rèn)為我以前寫(xiě)的后臺(tái)服務(wù)就沒(méi)掉過(guò)鏈子呀運(yùn)行得挺好的鸟蜡,1.可能是你的任務(wù)時(shí)間比較短;2.可能CPU被手機(jī)里面很多其他的軟件一直在喚醒狀態(tài)挺邀。)揉忘。下面是很多網(wǎng)友有同樣的問(wèn)題:

image.png

喚醒鎖可劃分為并識(shí)別四種用戶喚醒鎖:

image.png

請(qǐng)注意,自 API 等級(jí) 17 開(kāi)始端铛,F(xiàn)ULL_WAKE_LOCK 將被棄用泣矛。應(yīng)用應(yīng)使用 FLAG_KEEP_SCREEN_ON

  • 第一步就是添加喚醒鎖權(quán)限:

    <uses-permission android:name="android.permission.WAKE_LOCK" />
    
  • 直接使用喚醒鎖:

    PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
    
    WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakelockTag");
    
    wakeLock.acquire();
    

注意:在使用該類的時(shí)候禾蚕,必須保證acquire和release是成對(duì)出現(xiàn)的您朽。

但推薦的方式是使用WakefulBroadcastReceiver:使用廣播和Service(典型的IntentService)結(jié)合的方式可以讓你很好地管理后臺(tái)服務(wù)的生命周期。

WakefulBroadcastReceiver是BroadcastReceiver的一種特例换淆。它會(huì)為你的APP創(chuàng)建和管理一個(gè)PARTIAL_WAKE_LOCK 類型的WakeLock哗总。WakefulBroadcastReceiver把工作交接給service(通常是IntentService)几颜,并保證交接過(guò)程中設(shè)備不會(huì)進(jìn)入休眠狀態(tài)。如果不持有WakeLock讯屈,設(shè)備很容易在任務(wù)未執(zhí)行完前休眠蛋哭。最終結(jié)果是你的應(yīng)用不知道會(huì)在什么時(shí)候能把工作完成,相信這不是你想要的涮母。

  • 使用WakefulBroadcastReceiver第一步就是在Manifest中注冊(cè):

    <receiver android:name=".MyWakefulReceiver"></receiver>
    
  • 使用startWakefulService()方法來(lái)啟動(dòng)服務(wù)具壮,與startService()相比,在啟動(dòng)服務(wù)的同時(shí)哈蝇,并啟用了喚醒鎖。

    public class MyWakefulReceiver extends WakefulBroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {        
    // Start the service, keeping the device awake while the service is        
          // launching. This is the Intent to deliver to the service.        
    Intent service = new Intent(context, MyIntentService.class);        
    startWakefulService(context, service);  
      }
      }
    
  • 當(dāng)后臺(tái)服務(wù)的任務(wù)完成攘已,要調(diào)用MyWakefulReceiver.completeWakefulIntent()來(lái)釋放喚醒鎖炮赦。

    public class MyIntentService extends IntentService {
    public static final int NOTIFICATION_ID = 1;
    private NotificationManager mNotificationManager;
      NotificationCompat.Builder builder;
    
      public MyIntentService() {
    super("MyIntentService");
      }
    
    @Override
    protected void onHandleIntent(Intent intent) {
          Bundle extras = intent.getExtras();        
      // Do the work that requires your app to keep the CPU running.        
      // ...        
      // Release the wake lock provided by the WakefulBroadcastReceiver.        
    MyWakefulReceiver.completeWakefulIntent(intent);    
        }
    }
    

采用定時(shí)重復(fù)的Service開(kāi)啟:

  • 1、利用Android自帶的定時(shí)器AlarmManager實(shí)現(xiàn)

    Intent intent = new Intent(mContext, ServiceTest.class);
    PendingIntent pi = PendingIntent.getService(mContext, 1, intent, 0);
    AlarmManager alarm = (AlarmManager)getSystemService(Service.ALARM_SERVICE);
    if(alarm != null)
    {
      alarm.cancel(pi);
    // 鬧鐘在系統(tǒng)睡眠狀態(tài)下會(huì)喚醒系統(tǒng)并執(zhí)行提示功能
      alarm.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+1000, 2000, pi);// 確切的時(shí)間鬧鐘//alarm.setExact(…);
    //alarm.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pi);
      }
    
  • 2样勃、該定時(shí)器可以啟動(dòng)Service服務(wù)吠勘、發(fā)送廣播、跳轉(zhuǎn)Activity峡眶,并且會(huì)在系統(tǒng)睡眠狀態(tài)下喚醒系統(tǒng)剧防。所以該方法不用獲取電源鎖和釋放電源鎖。
    注意:在19以上版本辫樱,setRepeating中設(shè)置的頻繁只是建議值(6.0 的源碼中最小值是60s)峭拘,如果要精確一些的用setWindow或者setExact。

首先Android手機(jī)有兩個(gè)處理器狮暑,一個(gè)叫Application Processor(AP)鸡挠,一個(gè)叫Baseband Processor(BP)。AP是ARM架構(gòu)的處理器搬男,用于運(yùn)行Linux+Android系統(tǒng)拣展;BP用于運(yùn)行實(shí)時(shí)操作系統(tǒng)(RTOS),通訊協(xié)議棧運(yùn)行于BP的RTOS之上缔逛。非通話時(shí)間备埃,BP的能耗基本上在5mA左右,而AP只要處于非休眠狀態(tài)褐奴,能耗至少在50mA以上按脚,執(zhí)行圖形運(yùn)算時(shí)會(huì)更高。另外LCD工作時(shí)功耗在100mA左右歉糜,WIFI也在100mA左右乘寒。一般手機(jī)待機(jī)時(shí),AP匪补、LCD伞辛、WIFI均進(jìn)入休眠狀態(tài)烂翰,這時(shí)Android中應(yīng)用程序的代碼也會(huì)停止執(zhí)行。

Android為了確保應(yīng)用程序中關(guān)鍵代碼的正確執(zhí)行蚤氏,提供了Wake Lock的API甘耿,使得應(yīng)用程序有權(quán)限通過(guò)代碼阻止AP進(jìn)入休眠狀態(tài)。但如果不領(lǐng)會(huì)Android設(shè)計(jì)者的意圖而濫用Wake Lock API竿滨,為了自身程序在后臺(tái)的正常工作而長(zhǎng)時(shí)間阻止AP進(jìn)入休眠狀態(tài)佳恬,就會(huì)成為待機(jī)電池殺手。比如前段時(shí)間的某應(yīng)用于游,比如現(xiàn)在仍然干著這事的某應(yīng)用毁葱。

那么Wake Lock API有啥用呢?比如心跳包從請(qǐng)求到應(yīng)答贰剥,比如斷線重連重新登陸這些關(guān)鍵邏輯的執(zhí)行過(guò)程倾剿,就需要Wake Lock來(lái)保護(hù)。而一旦一個(gè)關(guān)鍵邏輯執(zhí)行成功蚌成,就應(yīng)該立即釋放掉Wake Lock了前痘。兩次心跳請(qǐng)求間隔5到10分鐘,基本不會(huì)怎么耗電担忧。除非網(wǎng)絡(luò)不穩(wěn)定芹缔,頻繁斷線重連,那種情況辦法不多瓶盛。

AlarmManager 是Android 系統(tǒng)封裝的用于管理 RTC 的模塊最欠,RTC (Real Time Clock) 是一個(gè)獨(dú)立的硬件時(shí)鐘,可以在 CPU 休眠時(shí)正常運(yùn)行蓬网,在預(yù)設(shè)的時(shí)間到達(dá)時(shí)窒所,通過(guò)中斷喚醒 CPU。(極光推送就是利用這個(gè)來(lái)做的帆锋。)

總結(jié):

    1. 關(guān)鍵邏輯的執(zhí)行過(guò)程吵取,就需要Wake Lock來(lái)保護(hù)。如斷線重連重新登陸
    1. 休眠的情況下如何喚醒來(lái)執(zhí)行任務(wù)锯厢?用AlarmManager皮官。如推送消息的獲取
本人做android開(kāi)發(fā)多年,以后會(huì)陸續(xù)更新關(guān)于android高級(jí)UI,NDK開(kāi)發(fā),性能優(yōu)化等文章,更多請(qǐng)關(guān)注我的微信公眾號(hào):謝謝!
android的那點(diǎn)事.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市实辑,隨后出現(xiàn)的幾起案子捺氢,更是在濱河造成了極大的恐慌,老刑警劉巖剪撬,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摄乒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)馍佑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)斋否,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人拭荤,你說(shuō)我怎么就攤上這事茵臭。” “怎么了舅世?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵旦委,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我雏亚,道長(zhǎng)缨硝,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任罢低,我火速辦了婚禮追葡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘奕短。我一直安慰自己,他們只是感情好匀钧,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布翎碑。 她就那樣靜靜地躺著,像睡著了一般之斯。 火紅的嫁衣襯著肌膚如雪日杈。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天佑刷,我揣著相機(jī)與錄音莉擒,去河邊找鬼。 笑死瘫絮,一個(gè)胖子當(dāng)著我的面吹牛涨冀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播麦萤,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鹿鳖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了壮莹?” 一聲冷哼從身側(cè)響起翅帜,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎命满,沒(méi)想到半個(gè)月后涝滴,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年歼疮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了杂抽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡腋妙,死狀恐怖默怨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情骤素,我是刑警寧澤匙睹,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站济竹,受9級(jí)特大地震影響痕檬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜送浊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一梦谜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧袭景,春花似錦唁桩、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至与殃,卻和暖如春单山,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背幅疼。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工米奸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人爽篷。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓悴晰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親逐工。 傳聞我的和親對(duì)象是個(gè)殘疾皇子膨疏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容