簡體   English   中英

屏幕關閉/鎖定后手機振動停止工作

[英]Phone vibration stops working after screen is off / locked

我有一項服務可以檢查我網站上的更新,我希望它能夠在找到更新時引起振動,即使屏幕關閉或鎖定也是如此。

目前僅當屏幕未關閉/鎖定時振動才有效。 即使屏幕關閉/鎖定,所有其他功能也能正常工作。

Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
   long[] pattern = new long[]{0, 400, 200, 400};
   if (Build.VERSION.SDK_INT >= 26) { // New API
     vibrator.vibrate(VibrationEffect.createWaveform(pattern,0));
   } else { // Old API
     vibrator.vibrate(pattern, 0);
}

即使手機屏幕關閉,如何振動手機? 我嘗試使用WakeLock但這似乎不是問題?

我設置了所有權限,因為它在屏幕打開時工作。

鑒於這種:

我有一項服務可以檢查我網站上的更新,我希望它能夠在找到更新時引起振動,即使屏幕關閉或鎖定也是如此。

和這個:

即使手機屏幕關閉,如何振動手機? 我嘗試使用 WakeLock 但這似乎不是問題?

我得出的結論是,當您的應用程序在前台時,您的服務可以正常工作,但在后台時不會出現問題。 因此,您的目標 Android API 很可能是26或更高。

在這種情況下,由於操作系統施加的背景限制,您的更新服務會在一段時間后停止工作。 由於更新服務不再運行,顯然它無法啟動任何振動。

API >= 26 的后台執行限制

從 Android 8.0 開始,對在后台運行的應用程序有限制。 因此,您的服務將工作一段時間,然后它將被系統殺死,如文檔中所述(請在此處閱讀更多信息):

當一個應用程序進入后台時,它有一個幾分鍾的 window ,它仍然可以創建和使用服務。 在 window 結束時,應用程序被認為是空閑的。 這時,系統會停止應用程序的后台服務,就像應用程序調用了服務的 Service.stopSelf() 方法一樣。

因此,如果您希望您的服務在應用程序處於后台時繼續運行,您仍然可以選擇。 其中一些如下

工作經理

WorkManager API 可以輕松安排可延遲的異步任務,即使應用程序退出或設備重新啟動,這些任務也會運行。

WorkManager替換您的服務,它會定期運行以查詢您的服務器。

作業調度器

好吧,如果您使用WorkManager ,您實際上並不需要它。 如果您的設備 API 為23及更高版本, WorkManager將在內部使用它。

前台服務

將您的服務轉換為前台服務,以便在執行期間將應用程序視為前台。 但在這種情況下,它必須在您執行更新檢查的整個過程中都處於活動狀態,所以它可能不是最好的解決方案。 在此處閱讀更多內容。

結論

請記住,從 API 26開始,應將后台服務替換為WorkManagerForeground Service 否則,它們可能無法按預期執行,因為系統會在一定時間后殺死它們。

您可以嘗試添加一個接收器來控制屏幕邏輯的開/關:

public class ScreenReceiver extends BroadcastReceiver {

    public static boolean wasScreenOn = true;

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
            // DO WHATEVER YOU NEED TO DO HERE
            Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
            long[] pattern = new long[]{0, 400, 200, 400};
            // Only perform this pattern one time (-1 means "do not repeat")
            v.vibrate(pattern, -1);
            wasScreenOn = false;
        } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
            // AND DO WHATEVER YOU NEED TO DO HERE
            wasScreenOn = true;
        }
    }

}

public class ExampleActivity extends Activity {

   @Override
    protected void onCreate() {
        // INITIALIZE RECEIVER
        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        BroadcastReceiver mReceiver = new ScreenReceiver();
        registerReceiver(mReceiver, filter);
        // YOUR CODE
    }

    @Override
    protected void onPause() {
        // WHEN THE SCREEN IS ABOUT TO TURN OFF
        if (ScreenReceiver.wasScreenOn) {
            // THIS IS THE CASE WHEN ONPAUSE() IS CALLED BY THE SYSTEM DUE TO A SCREEN STATE CHANGE
            System.out.println("SCREEN TURNED OFF");
        } else {
            // THIS IS WHEN ONPAUSE() IS CALLED WHEN THE SCREEN STATE HAS NOT CHANGED
        }
        super.onPause();
    }

    @Override
    protected void onResume() {
        // ONLY WHEN SCREEN TURNS ON
        if (!ScreenReceiver.wasScreenOn) {
            // THIS IS WHEN ONRESUME() IS CALLED DUE TO A SCREEN STATE CHANGE
            System.out.println("SCREEN TURNED ON");
        } else {
            // THIS IS WHEN ONRESUME() IS CALLED WHEN THE SCREEN STATE HAS NOT CHANGED
        }
        super.onResume();
    }

}

這是一個活動生命周期: 活動生命周期

參考:

https://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/

無論您使用服務還是生命周期方法,您都需要創建一個循環周期,以便您的振動器在完成您定義的模式后重新啟動。

我使用處理程序按如下方式進行了操作。

Handler handlerVibrate;
Vibrator vibrator;
private void vibrate(){
    // this handler will keep vibrator running even with screen off (vibrator stops when the phone has the screen off)
    vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
    handlerVibrate = new Handler();
    handlerVibrate.post(new Runnable() {
        @Override
        public void run() {
            if(vibrator != null) {
                Log.d("mainActivity", "handler");
                long[] pattern = {0, 500, 500};
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    vibrator.vibrate(VibrationEffect.createWaveform(pattern, 0)); // repeat at index 0
                } else {
                    //deprecated in API 26
                    vibrator.vibrate(pattern, 0); // repeat at index 0
                }
            }
            if(CONDITIONS TO STOP/CONTINUE){
                // keep launching so that it keeps vibrating even with the screen off
                handlerVibrate.postDelayed(this, 1000);
            } else {
                if(vibrator != null) {
                    vibrator.cancel();
                }
            }
        }
    });
}

從你的解釋

我有一項服務可以檢查我網站上的更新

您會定期檢查您網站的更新。 確保在嘗試連接到服務器之前獲得喚醒鎖,因為您的應用程序不會,否則您的應用程序將無法連接到互聯網。

您還可以嘗試通過顯示通知或按照此答案以編程方式打開屏幕,以防屏幕關閉時您無法獲得喚醒鎖定。

我相信這個問題可能是因為您可能在檢測到更新后嘗試獲取喚醒鎖。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM