1. 程式人生 > >Android保持裝置喚醒狀態

Android保持裝置喚醒狀態

當Android裝置空閒時,螢幕會變暗,然後關閉螢幕,最後會停止CPU的執行,這樣可以防止電池電量掉的快。在休眠過程中自定義的Timer、Handler、Thread、Service等都會暫停。但有些時候我們需要改變Android系統預設的這種狀態:比如玩遊戲時我們需要保持螢幕常亮,比如一些下載操作不需要螢幕常亮但需要CPU一直執行直到任務完成。

保持螢幕常亮

遊戲開發時,要保持遊戲介面一直亮著。
常用方法:在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); } }

這個方法的好處是不像喚醒鎖(wake locks),需要一些特定的許可權(permission)。並且能正確管理不同app之間的切換,不用擔心無用資源的釋放問題。
另一種方式:另一個方式是在佈局檔案中使用android:keepScreenOn屬性。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:keepScreenOn="true">
    ...
</LinearLayout>

android:keepScreenOn =”true“的作用和FLAG_KEEP_SCREEN_ON一樣。第一種方式好處是你允許你在需要的地方關閉螢幕。
注意:一般不需要人為的去掉FLAG_KEEP_SCREEN_ON的flag,windowManager會管理好程式進入後臺回到前臺的的操作。如果確實需要手動清掉常亮的flag,使用getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)

保持cpu執行

需要使用PowerManager這個系統服務的喚醒鎖(wake locks)特徵來保持CPU處於喚醒狀態。
喚醒鎖可劃分為並識別四種使用者喚醒鎖:
這裡寫圖片描述
注意:自 API 等級 17 開始,FULL_WAKE_LOCK 將被棄用。 應用應使用 FLAG_KEEP_SCREEN_ON。
第一步就是新增喚醒鎖許可權:

<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();

注意:在不需要的時候release。

但推薦的方式是使用WakefulBroadcastReceiver:使用廣播和Service(典型的IntentService)結合的方式可以讓你很好地管理後臺服務的生命週期。
WakefulBroadcastReceiver是BroadcastReceiver的一種特例。它會為你的APP建立和管理一個PARTIAL_WAKE_LOCK 型別的WakeLock。WakefulBroadcastReceiver把工作交接給service(通常是IntentService),並保證交接過程中裝置不會進入休眠狀態。如果不持有WakeLock,裝置很容易在任務未執行完前休眠。

使用WakefulBroadcastReceiver

第一步就是在Manifest中註冊:
java<receiver android:name=".MyWakefulReceiver"></receiver>

使用startWakefulService()方法來啟動服務,與startService()相比,在啟動服務的同時,並啟用了喚醒鎖。

    @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);  
    }
}

當後臺服務的任務完成,要呼叫MyWakefulReceiver.completeWakefulIntent()來釋放喚醒鎖。

    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);    
    }
}

WakefulBroadcastReceiver原始碼分析

 public static ComponentName startWakefulService(Context context, Intent intent) {
        synchronized (mActiveWakeLocks) {
            int id = mNextId;
            mNextId++;
            if (mNextId <= 0) {
                mNextId = 1;
            }

            intent.putExtra(EXTRA_WAKE_LOCK_ID, id);
            ComponentName comp = context.startService(intent);
            if (comp == null) {
                return null;
            }

            PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
            PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                    "wake:" + comp.flattenToShortString());
            wl.setReferenceCounted(false);
            wl.acquire(60*1000);
            mActiveWakeLocks.put(id, wl);
            return comp;
        }
    }

它裡面啟動了一個60秒的鎖,在需要釋放的時候呼叫completeWakefulIntent(Intent intent)方法

public static boolean completeWakefulIntent(Intent intent) {
        final int id = intent.getIntExtra(EXTRA_WAKE_LOCK_ID, 0);
        if (id == 0) {
            return false;
        }
        synchronized (mActiveWakeLocks) {
            PowerManager.WakeLock wl = mActiveWakeLocks.get(id);
            if (wl != null) {
                wl.release();
                mActiveWakeLocks.remove(id);
                return true;
            }
            // We return true whether or not we actually found the wake lock
            // the return code is defined to indicate whether the Intent contained
            // an identifier for a wake lock that it was supposed to match.
            // We just log a warning here if there is no wake lock found, which could
            // happen for example if this function is called twice on the same
            // intent or the process is killed and restarted before processing the intent.
            Log.w("WakefulBroadcastReceiver", "No active wake lock id #" + id);
            return true;
        }
    }

採用定時重複的Service開啟

利用Android自帶的定時器AlarmManager實現:

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);
    // 鬧鐘在系統睡眠狀態下會喚醒系統並執行提示功能
    alarm.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 1000, 2000, pi);// 確切的時間鬧鐘//alarm.setExact(…);
    //alarm.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pi);
}

該定時器可以啟動Service服務、傳送廣播、跳轉Activity,並且會在系統睡眠狀態下喚醒系統。所以該方法不用獲取電源鎖和釋放電源鎖。
注意:在19以上版本,setRepeating中設定的頻繁只是建議值(6.0 的原始碼中最小值是60s),如果要精確一些的用setWindow或者setExact。

總結

  • 關鍵邏輯的執行過程,就需要Wake Lock來保護,如斷線重連重新登陸。
  • 休眠的情況下喚醒cpu來執行任務用AlarmManager,如推送訊息的獲取。

最後附一張微信的圖
這裡寫圖片描述

相關推薦

Android保持裝置喚醒狀態

當Android裝置空閒時,螢幕會變暗,然後關閉螢幕,最後會停止CPU的執行,這樣可以防止電池電量掉的快。在休眠過程中自定義的Timer、Handler、Thread、Service等都會暫停。但有些時候我們需要改變Android系統預設的這種狀態:比如玩遊戲時

Android保持裝置喚醒

Contents 保持裝置喚醒... 1 使用wakelock之外的選擇... 1 保持螢幕亮... 1 保持CPU執行... 2 用BroadcastReceiver保持裝置喚醒... 2   保持裝置喚醒 為了避免電量流失,Android裝置進入閒置狀態

Android應用程式 --- WakeLock 保持後臺喚醒狀態

一些手機app(如微信、QQ等)有新訊息來到達,手機螢幕即使在鎖屏狀態下也會亮起,並提示使用者有新訊息。但是,一般情況下手機鎖屏後,Android系統為了省電以及減少CPU消耗,在一段時間後會使系統進

Android 保持螢幕喚醒不熄滅

這兩天工作比較忙,沒有時間更新部落格。今天難得閒下來,總結一下之前寫的一個Demo,用到了兩個小知識點:一是使用Thread加Handler實現計時,二是控制螢幕喚醒不熄滅。 首先是計時,首先我使用單純的Handler來實現計時,程式碼如下: Handler handle

Android保持螢幕常亮喚醒狀態

在開發過程中有時會用到保持螢幕常亮,主要用電源控制來實現,具體實現如下: 第一步:  首先新增許可權: <uses-permission android:name="android.permiss

Android保持螢幕常亮喚醒狀態

第一步:  首先新增許可權: <uses-permission android:name="android.permission.WAKE_LOCK"></uses-permissi

mono for android 用ISharedPreferences 進行狀態保持 會話保持 應用程式首選項儲存

由於專案需要 要保持使用者登入狀態 要進行狀態保持 用途就好像asp.net的session一樣  登入的時候進行儲存 ISharedPreferences shared = GetSharedPreferences("UserName", FileCreationMode.Private);

Android 獲得裝置狀態資訊、Mac地址、IP地址

前言 在我們APP開發時,經常會遇到要獲取手機狀態資訊的場景,像升級時獲取版本號,像發生異常時要收集手機資訊等等。有些軟體還要根據Mac地址來判定當前使用者以前是否登入過。也有些需要通過不同的IMEI對APP進行管理。下面將一一介紹獲取這些手機狀態資訊的方法。 1.獲得Mac地址

android學習筆記之客戶端與服務端保持session登入狀態

剛進公司不久,也沒有具體專案任務,只有一個混合開發模式,使用AppCan開發的專案。 雖然混合開發很便捷、很高效,使用html和js就可以完成。 但我依然對android原生開發有著極高的熱情,尤其是在體驗了Android 5.0版本之後,更是對原生體驗著迷。 所以,我利用

android保持服務不休眠(持續執行)以及喚醒螢幕的方法

假設有這樣一個應用場景,一個服務一直在默默的工作(比如即時地獲取伺服器的訊息),即使在螢幕已經因為長時間無操作而關閉,或者使用者按了電源鍵讓螢幕關閉,手機進入休眠狀態,他必須依然在工作中。一旦從伺服器獲取到訊息,他能點亮螢幕,然後進行一些處理工作。 1、讓服務持續執行而不

Android WebView 與登入狀態保持一致,建立SESSION會話

在登陸介面獲取驗證碼的時候: new Thread(){ @Override public void run() {

android 保持螢幕常亮和喚醒螢幕的方式

一、引言 Android開發中會用到將應用的螢幕保持常亮,比如播放視訊、音樂等,如果總是使用者去觸控式螢幕幕來保持螢幕常亮,那麼使用者體驗會很差; 二、實現方式 通過設定Window Flag(最簡單,推薦) 通過PowerManager 第一種方式:

Delphi XE10 Android Splash裝置自適應和沉浸式狀態

  再次提筆寫部落格,已經相隔7年,原來的CSDN賬號需要手機驗證,而我的手機又捆綁到這個賬號了,就用新賬號吧,不想折騰了。  原賬號的帖子,有研究DICOM3.0的可以看下:http://blog.csdn.net/ruanxundianzi/article/details

Android保持螢幕喚醒的方法

最近在解一個 bug 時,用到了這個知識點。在這裡總結一下: bug 是這樣描述的: 在 Camera 切換到攝像時,攝像過程大概持續2,3分鐘,就自動進鎖屏了 有時也會持續很長時間進鎖屏。 這是一個概率性的問題(即隨機出現)。 從原理上分析上來看,肯定是螢幕被鎖住了。

Android獲取裝置寬高,以及狀態列高度

//獲取裝置寬度和高度 DisplayMetrics dm=new DisplayMetrics();WindowManager manager= (WindowManager) this.getSystemService(this.WINDOW_SERVICE);mana

Android bluetooth裝置狀態監聽

public class BluetoothHeadsetBroadcastReceiver extends BroadcastReceiver { public BluetoothHeadsetBroadcastReceiver() { } p

Unity 安卓環境下保持裝置螢幕喚醒

我們都知道在遊戲中都應該有保持螢幕喚醒這一功能,不然你的遊戲在玩家的裝置上難免會出現長時間不操作螢幕自動睡眠,這不論是對玩家而言是一大槽點,對遊戲開發者而言也是一個低階錯誤。 我們知道,在android開發中,只要在配置檔案中加段程式碼就能保證螢幕長時間喚醒,那麼在Unit

Android 沈浸式狀態

測試 分離 fit style port border size art 1.0 效果圖 android 5.0 以上 android 4.4 API 19 以上都是原生安卓系統的效果,具體到國內的各種各樣改過的系統可能會有細微差別,測試過

記一次錯誤的系統參數設置導致無法保持登錄狀態

linux如題,某天用xshell登錄華為雲(Centos 7),發現每間隔15分鐘自動斷開連接。百度後,備份並修改了/etc/profile,將TMOUT鍵值由900修改為1h。 保存後,source /etc/profile 使之生效,發現ssh剛連接進來1秒即斷開。不僅ssh登錄,從華為雲的遠程控制臺登

App保持登錄狀態的常用方法

技術 ice 策略 前端技術 打開 問題 有效 廣泛 感覺 我們在使用App時,一次登錄後App如果不主動退出登錄或者清除數據,App會在很長一段時間內保持登錄狀態,或者讓用戶感覺到登錄一次就不用每次都輸入用戶密碼才能進行登錄。銀行、金融涉及到支付類的App一般不支持這種長