当应用处于后台或关闭状态时,Android应用中的本地通知不会显示

时间:2019-11-06 07:35:04

标签: android android-notifications android-doze

我已经使用Service生成了本地通知。当应用程序打开时,通知窗口将正常运行并显示出来。但是,当应用程序进入后台或收到关闭的通知时,它们不会显示。当我重新打开我的应用程序时,所有通知都会显示。

关于这个问题,我经历了很多讨论。因此,我尝试了startForegroundAlarmManagerBroadcastReceiver,但没有任何帮助。仅当应用程序打开时,仍会显示本地通知。我发现,当我将电池设置设置为在手机设置中在后台运行我的应用程序时,它就可以正常工作,并且会显示通知。但是用户不会知道他应该这样做。

MyService:

public class MyService2 extends Service {

private boolean running = true;
private MyAsyncTask myAsyncTask;

@Override
public IBinder onBind(Intent arg0) {
    // TODO Auto-generated method stub
    return null;
}

public void onCreate() {
    super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    startForeground(1, showAndGetNotification(getApplicationContext(), "Twoja aplikacja działa w tle", "", new Intent(getApplicationContext(), MainActivity.class)));
    myAsyncTask = new MyAsyncTask();
    myAsyncTask.execute();
    return START_STICKY;
}

public void onDestroy() {
    super.onDestroy();
    stopForeground(true);
    stopSelf();
    if (myAsyncTask != null) {
        myAsyncTask.cancel(true);
    }
    running = false;
    SharedPreferences sharedPref = getSharedPreferences("service", Activity.MODE_PRIVATE);
    boolean fromAppStop = sharedPref.getBoolean("fromAppStop", false);
    if (!fromAppStop) {
        Intent broadcastIntent = new Intent(this, SensorRestarterBroadcastReceiver.class);
        sendBroadcast(broadcastIntent);
    }
    SharedPreferences.Editor editor = sharedPref.edit();
    editor.putBoolean("fromAppStop", false);
    editor.commit();
}

private class MyAsyncTask extends AsyncTask<Void, Void, Void> {

    @Override
    protected Void doInBackground(Void... voids) {
        try {
            while (running) {
                List<Map<String, String>> medicinesToTake = getMedicinesToTake();
                for (Map<String, String> medicineToTake : medicinesToTake) {
                    String medicineName = medicineToTake.keySet().toArray()[0].toString();
                    Thread.sleep(countSleepToNextTake(medicineToTake.get(medicineName)));
                    doAlarm("Czas na lek", medicineName, medicineName);
                }
                Thread.sleep(countLeftTimeForNextDay());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        super.onPostExecute(result);
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
}

private void doAlarm(String title, String medicineName, String body) {
    Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
    intent.putExtra("title", title);
    intent.putExtra("medicineName", medicineName);
    intent.putExtra("body", body);
    AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    int id = generateUniqueId();
    PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), id, intent, PendingIntent.FLAG_CANCEL_CURRENT);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pendingIntent);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pendingIntent);
    } else {
        alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pendingIntent);
    }
}

public Notification showAndGetNotification(Context context, String title, String body, Intent intent) {
    NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

    Date now = new Date();
    int notificationId = Integer.parseInt(new SimpleDateFormat("ddHHmmss", Locale.UK).format(now)) + new Random().nextInt();
    //String channelId = "channel-01";
    String channelId = UUID.randomUUID().toString();
    String channelName = "Channel Name";
    int importance = NotificationManager.IMPORTANCE_HIGH;

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        NotificationChannel mChannel = new NotificationChannel(
                channelId, channelName, importance);
        notificationManager.createNotificationChannel(mChannel);
    }

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, channelId)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(title)
            .setAutoCancel(true)
            .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
            .setContentText(body);

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
    stackBuilder.addNextIntent(intent);
    PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
            generateUniqueId(),
            PendingIntent.FLAG_UPDATE_CURRENT
    );
    mBuilder.setContentIntent(resultPendingIntent);

    notificationManager.notify(notificationId, mBuilder.build());

    return mBuilder.build();
}

private int generateUniqueId() {
    UUID idOne = UUID.randomUUID();
    String str = "" + idOne;
    int uid = str.hashCode();
    String filterStr = "" + uid;
    str = filterStr.replaceAll("-", "");
    return Integer.parseInt(str);
}
}

MyAlarmReceiver:

public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
    String medicineName = intent.getStringExtra("medicineName");
    String body = intent.getStringExtra("body");

    Intent notificationIntent = null;
    String title = intent.getStringExtra("title");
    if (title.equals("Czas na lek")) {
        notificationIntent = new Intent(context, TimeForMedicineActivity.class);
        notificationIntent.putExtra("medicineName", medicineName);
    } else if (title.equals("Twój lek się skończył")) {
        notificationIntent = new Intent(context, AddOrDeleteMyMedicineActivity.class);
    } else if (title.equals("Twój lek się kończy")) {
        notificationIntent = new Intent(context, MainActivity.class);
    }

    NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

    Date now = new Date();
    int notificationId = Integer.parseInt(new SimpleDateFormat("ddHHmmss", Locale.UK).format(now)) + new Random().nextInt();
    String channelId = UUID.randomUUID().toString();
    String channelName = "Channel Name";
    int importance = NotificationManager.IMPORTANCE_HIGH;

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        NotificationChannel mChannel = new NotificationChannel(
                channelId, channelName, importance);
        notificationManager.createNotificationChannel(mChannel);
    }

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, channelId)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(title)
            .setAutoCancel(true)
            .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
            .setContentText(body);

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
    stackBuilder.addNextIntent(notificationIntent);
    PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
            generateUniqueId(),
            PendingIntent.FLAG_UPDATE_CURRENT
    );
    mBuilder.setContentIntent(resultPendingIntent);

    notificationManager.notify(notificationId, mBuilder.build());
}


private int generateUniqueId() {
    UUID idOne = UUID.randomUUID();
    String str = "" + idOne;
    int uid = str.hashCode();
    String filterStr = "" + uid;
    str = filterStr.replaceAll("-", "");
    return Integer.parseInt(str);
}
}

1 个答案:

答案 0 :(得分:0)

问题出在华为使用的MIUI操作系统上。它违反了android规范,该规范要求将使用startForeground的服务视为前台。

我的应用程序中存在相同的问题。我没有找到更好的解决方案,除了检测应用程序是否在MIUI上运行,然后打开警报告诉用户如果他们想要前台,他们应该手动打开电池设置并将该应用程序添加到异常中。

您可以尝试

        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        if (!pm.isIgnoringBatteryOptimizations(packageName)) {
            intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
            intent.setData(Uri.parse("package:" + packageName));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        }

使用

<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>

但是在MIUI上可能不起作用。