【问题标题】:Phone vibration stops working after screen is off / locked屏幕关闭/锁定后手机振动停止工作
【发布时间】:2020-09-22 02:49:45
【问题描述】:

我有一项服务可以检查我网站上的更新,我希望它能够在发现更新时引起振动,即使屏幕关闭或锁定。

目前仅当屏幕未关闭/锁定时振动才有效。 即使屏幕关闭/锁定,所有其他功能也能正常工作。

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,但这似乎不是问题?

我设置了所有权限,因为它在屏幕打开时工作。

【问题讨论】:

  • 您在哪个设备上测试?
  • 如何使用具有高优先级频道的通知?
  • 您不应该一直轮询您的网站以获取更新。这将使用设备上的大量数据,耗尽电池并在您的网站上产生大量负载。更好的解决方案是在有可用更新时从服务器向您的应用发送通知。
  • @Persson 是否有任何帖子回答了您的问题?

标签: java android android-service android-vibration


【解决方案1】:

鉴于此:

我有一项服务可以检查我网站上的更新,我希望它能够在发现更新时引起振动,即使屏幕关闭或锁定。

还有这个:

如何在手机屏幕关闭的情况下振动手机?我尝试使用 WakeLock,但这似乎不是问题?

我得出的结论是,当您的应用程序在前台时,您的服务可以正常工作,但在后台时不会出现问题。因此,您的目标 Android API 很可能是 26 或更高版本。

在这种情况下,由于操作系统施加的后台限制,您的更新服务会在一段时间后停止工作。由于更新服务不再运行,显然它无法启动任何振动。

API 的后台执行限制 >= 26

从 Android 8.0 开始,对在后台运行的应用程序有限制。因此,您的服务将工作一段时间,然后它会被系统杀死,如文档中所述(请阅读更多here):

当一个应用程序进入后台时,它有几个窗口 仍然允许它创建和使用服务的分钟数。在 该窗口结束时,应用程序被认为是空闲的。在这 时间,系统停止应用程序的后台服务,就像 应用程序调用了服务的 Service.stopSelf() 方法。

因此,如果您希望您的服务在应用程序处于后台时继续运行,您仍然可以选择。其中一些是以下

工作经理

WorkManager API 可以轻松安排可延迟的异步 即使应用程序退出或设备也应运行的任务 重新启动。

将您的服务替换为WorkManager,它会定期运行以查询您的服务器。

作业调度器

好吧,如果你使用WorkManager,你真的不需要它。如果您的设备 API 为 23 及更高版本,WorkManager 将在内部使用它。

前台服务

将您的服务转换为前台服务,以便应用在执行期间被视为前台。但在这种情况下,它必须在您执行更新检查的整个过程中都处于活动状态,所以它可能不是最好的解决方案。请阅读更多here

结论

请记住,从 API 26 开始,应将后台服务替换为 WorkManagerForeground Service。否则,它们可能无法按预期执行,因为系统会在一定时间后将它们杀死。

【讨论】:

    【解决方案2】:

    您可以尝试添加一个接收器来控制屏幕逻辑的开/关:

    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/

    【讨论】:

    • 我相信您在这里回答的是不同的问题。 OP 声明他的更新服务不会导致他的设备在屏幕关闭时振动。但是,您要回答的是,如果收到 Intent.ACTION_SCREEN_OFF,如何启动振动。
    【解决方案3】:

    无论您使用服务还是生命周期方法,您都需要创建一个循环周期,以便您的振动器在完成您定义的模式后重新启动。

    我使用处理程序按如下方式进行。

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

    【讨论】:

      【解决方案4】:

      根据你的解释

      我有一项服务可以检查我网站上的更新

      您会定期检查您网站的更新。确保在尝试连接到服务器之前获得唤醒锁,因为您的应用程序不会,否则您的应用程序将无法连接到互联网。

      您也可以尝试通过显示通知或关注this answer 以编程方式打开屏幕,以防屏幕关闭时无法获得唤醒锁定。

      我相信这个问题可能是因为您在检测到更新后尝试获取唤醒锁。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-04-04
        • 1970-01-01
        • 2011-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多