gpt4 book ai didi

java - 当用户将其置于后台时,我的 Android 11 应用程序将停止运行,除非手机已连接到电源

转载 作者:行者123 更新时间:2023-12-04 01:04:14 27 4
gpt4 key购买 nike

我编写了一个前台服务,以确保我的应用程序在进入后台时可以继续运行。该应用程序需要在后台运行,因为在其计时器结束后,它会发出提示音并振动以提醒用户。但是,当按下电源或主页按钮时,应用程序的计时器会在大约 15 分钟后停止运行,除非手机已插入电源。我测试时手机已充满电。
顺便说一句,在阅读各种网站后,我还将应用程序设置为不针对电池生命周期进行优化,以确保应用程序继续运行。从我阅读的所有内容来看,我做的一切都是正确的,但我仍然无法让它发挥作用。我在 Pixel 2 上运行 Android 11。我知道 Google 限制了更高版本 Android 的前台处理,但是将应用程序设置为不针对电池生命周期进行优化应该可以解决这个问题,不是吗?为了安全起见,当应用程序启动时,它会要求用户批准后台操作:

     PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE);
if (!pm.isIgnoringBatteryOptimizations(APPLICATION_ID)) {
// Ask user to allow app to not optimize battery life. This will keep
// the app running when the user puts it in the background by pressing
// the Power or Home button.
Intent intent = new Intent();
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + APPLICATION_ID));
startActivity(intent);
}
因此,当应用程序运行并针对电池进行优化时,用户会看到以下内容:
enter image description here
我按如下方式启动前台服务:
    private void startForegroundMonitoring() {
broadcastIntent = new Intent(context, BroadcastService.class);
broadcastIntent.putExtra(ALLOWEDTIME, allowed_time);
broadcastIntent.putExtra(BEEP, beep.isChecked());
broadcastIntent.putExtra(VIBRATE, vibrate.isChecked());
broadcastIntent.putExtra(NOTIFY, notify_monitor.isChecked());
broadcastIntent.putExtra(CURFEW, curfew_config.isChecked());
broadcastIntent.putExtra(CURFEWSTARTTIME, curfew_start_time);
broadcastIntent.putExtra(CURFEWENDTIME, curfew_end_time);
startService(broadcastIntent);
}
更新:这是一些演示问题的代码:
主要 Activity :
package com.testapp.showbug;

import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.PowerManager;
import android.provider.Settings;

import static com.testapp.showbug.BuildConfig.APPLICATION_ID;

public class MainActivity extends AppCompatActivity {

private Context context;

private Intent broadcastIntent;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

context = getApplicationContext();

PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE);
if (!pm.isIgnoringBatteryOptimizations(APPLICATION_ID)) {
// Ask user to allow app to not optimize battery life. This will keep
// the app running when the user puts it in the background by pressing
// the Power or Home button.
Intent intent = new Intent();

intent.setAction(
Settings.
ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" +
APPLICATION_ID));
startActivity(intent);
}

broadcastIntent = new Intent(context,
BroadcastService.class);
startService(broadcastIntent);
}
public void onDestroy() {
super.onDestroy();

stopService(broadcastIntent);
}
}
广播服务:
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.CountDownTimer;
import android.os.IBinder;
import android.widget.Toast;

import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;

import static android.content.pm.ServiceInfo.
FOREGROUND_SERVICE_TYPE_LOCATION;

public class BroadcastService extends Service {
private static final int ONE_MINUTE = 60000;

private int allowed_time = 30, tickCounter;

private CountDownTimer countDown;

private NotificationManagerCompat notificationManager;

private NotificationCompat.Builder notification;

@Override
public void onCreate() {
super.onCreate();

// Clear all notifications sent earlier.
notificationManager =
NotificationManagerCompat.from(this);
notificationManager.cancelAll();

createNotificationChannel();
}

@Override
public void onDestroy() {
super.onDestroy();
}

@Override
public int onStartCommand(Intent intent, int flags,
int startId) {
if (intent == null) return START_STICKY;

Intent notificationIntent = new Intent(this,
BroadcastService.class);
PendingIntent pendingIntent =
PendingIntent.getActivity(this, 0,
notificationIntent, 0);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notification = new
NotificationCompat.Builder(this,
getString(
R.string.default_notification_channel_id))
.setContentTitle(
getText(R.string.notification_title))
.setContentText(
getText(R.string.notification_message))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(
getText(R.string.notification_message)))
.setContentIntent(PendingIntent.getActivity(
this, 0, new Intent(), 0))
.setSmallIcon(R.mipmap.ic_launcher_round)
.setLocalOnly(true)
.setContentIntent(pendingIntent);
} else {
notification = new
NotificationCompat.Builder(this,
getString(
R.string.default_notification_channel_id))

.setContentTitle(
getText(R.string.notification_title))
.setContentText(
getText(R.string.notification_message))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(
getText(R.string.notification_message)))
.setContentIntent(PendingIntent.getActivity(
this, 0, new Intent(), 0))
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContentIntent(pendingIntent);
}

startForeground(FOREGROUND_SERVICE_TYPE_LOCATION, notification.build());

tickCounter = -1;
// Start countdown timer for allowed time.
countDown = new CountDownTimer(allowed_time * ONE_MINUTE, ONE_MINUTE) {
@Override
public void onTick(long millisUntilFinished) {
tickCounter++;
Toast.makeText(getApplicationContext(), "tickCounter = " + tickCounter, Toast.LENGTH_LONG).show();
}

@Override
public void onFinish() {
Toast.makeText(getApplicationContext(), "tickCounter = " + allowed_time, Toast.LENGTH_LONG).show();
}
}.start();
return START_STICKY;
}

private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.channel_name);
String description = getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(getString(R.string.default_notification_channel_id), name, importance);
channel.setDescription(description);

notificationManager.createNotificationChannel(channel);
}
}

@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
上面的代码启动了一个前台服务,该服务又启动了一个 CountDownTimer,它每分钟将刻度数增加 1 并打印结果。 30 分钟后,它应该显示 30 个滴答声。相反,它会提前停止,通常在 15-16 个滴答声之后。
以下是运行代码的方法:
  • 开始 Activity ,断开设备电源(这很重要,显然需要真实设备),然后点击设备上的电源按钮。
  • 等待 28 分钟。
  • 将应用程序放回前台并等待下一个滴答声。
  • 请注意,下一个刻度显示小于 28 的值。

  • 感谢您对此的任何帮助。在我看来,它就像 Android SDK 中的一个错误,看起来不太可能。我没有看到任何其他原因。顺便说一句,我在运行 Android 11(我拥有的唯一设备)的 Pixel 2 和 Samsung Tab A 上测试了此代码,所以我不知道该错误是否发生在早期版本的 Android 或其他设备上。

    最佳答案

    我终于解决了这个问题,使用唤醒锁。唤醒锁确保按下电源按钮后 CPU 继续运行。我所要做的就是在 BroadcastService.java 中添加以下代码:
    在 onCreate() 中:

        PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE);
    wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PeriSecure:MyWakeLock");
    在 onStartCommand() 中:
        wakeLock.acquire(allowed_time * ONE_MINUTE);
    在 onDestroy() 中:
    wakeLock.release();
    就这样!后台服务现在按原样运行。

    关于java - 当用户将其置于后台时,我的 Android 11 应用程序将停止运行,除非手机已连接到电源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67062114/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com