我正在制作一个可在一天的特定时间通知用户的应用程序。就像闹钟一样。该代码可在Android Oreo之前的版本中正常运行。
I am making an application that notifies the user at certain times of the day. Like an alarm clock. The code works normally in versions prior to Android Oreo.
据我了解,Android Oreo及更高版本会在后台终止动作,这就是为什么我在下面出现错误。
From what I read, Android Oreo and later versions kill actions in the background and that's why I'm having the error below.
2020-07-13 20:31:06.766 1609-1737/? W/BroadcastQueue: Background execution not allowed: receiving Intent { act=android.intent.action.PACKAGE_REPLACED dat=package:studio.archeagemanager flg=0x4000010 (has extras) } to air.br.alelo.mobile.android/co.acoustic.mobile.push.sdk.wi.AlarmReceiver就好像在以下情况下不会触发BroadcastService它应该是。但是,当我打开该应用程序时,它会立即启动。
It is as if the BroadcastService is simply not triggered when it should be. But when I open the app, it starts up instantly.
AndroidManifest.xml
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="owner.custom.permission" /> <permission android:name="owner.custom.permission" android:protectionLevel="signatureOrSystem"> </permission> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> <application android:allowBackup="true" android:icon="@mipmap/app_icon_new" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".SplashScreenActivity" android:theme="@style/AppCompat.TelaCheia"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".MainActivity" android:label="@string/app_name" android:screenOrientation="portrait" android:theme="@style/AppTheme.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> <receiver android:name=".AlarmReceiver" android:enabled="true" android:exported="false"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> </application>
TabFragEventA.java (这里,我只放置了启动警报的函数)
TabFragEventA.java (Here I put only the function that initiates the alarm)
public void startAlarm(int eventID) { String[] NOTIFICATION_TITLES = {"Ocleera Rift", "Ocleera Rift", "Mistmerrow Conflict", "Mistmerrow Conflict", "Mistmerrow Conflict", "Nation Construction Quests", "Diamond Shores", "Diamond Shores", "Battle of the Golden Plains", "Battle of the Golden Plains", "Karkasse Ridgelands", "Kraken", "The Mirage Isle Fish Fest", "Red Dragon", "Abyssal Attack", "Lusca Awakening", "Delphinad Ghostship", "Cattler Wrangler", "Legendary Chef", "+1"}; String notificationTitle = getString(R.string.contentTitle); String notificationText = NOTIFICATION_TITLES[eventID] + getString(R.string.contentNotificationText); int alarmHour = localHour.get(eventID); int alarmMinute = localMinute.get(eventID); // Decrease 5 minutes if(alarmMinute == 0) { alarmHour = alarmHour - 1; alarmMinute = 55; } else { alarmMinute = alarmMinute - 5; } // Setting the alarm moment Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, alarmHour); calendar.set(Calendar.MINUTE, alarmMinute); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); // Analyze if the alarm moment has passed Calendar actualTime = Calendar.getInstance(); if(actualTime.getTimeInMillis() >= calendar.getTimeInMillis()) { calendar.add(Calendar.DAY_OF_MONTH, 1); } Intent intent = new Intent(getActivity().getApplicationContext(), AlarmReceiver.class); intent.putExtra("contentTitle", notificationTitle); intent.putExtra("contentText", notificationText); /*if(eventID == 11 || eventID == 13) { intent.putExtra("specificDayWeek", true); } else { intent.putExtra("specificDayWeek", false); }*/ if(eventID == 12) { intent.putExtra("castleSupply", true); intent.putIntegerArrayListExtra("castleSupplyDayWeek", (ArrayList<Integer>) CastleSupply); } else if(eventID == 13) { intent.putExtra("castleClaim", true); intent.putIntegerArrayListExtra("castleClaimDayWeek", (ArrayList<Integer>) CastleClaim); } else if(eventID == 14) { intent.putExtra("abyssalAttack", true); intent.putIntegerArrayListExtra("abyssalDaysWeek", (ArrayList<Integer>) AbyssalDayWeek); } else if(eventID == 15) { intent.putExtra("luscaAwakening", true); intent.putIntegerArrayListExtra("luscaAwakeningDayWeek", (ArrayList<Integer>) LuscaAwakening); } else { intent.putExtra("abyssalAttack", false); } intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); // PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity().getApplicationContext(), eventID, intent, PendingIntent.FLAG_UPDATE_CURRENT); PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity().getApplicationContext(), eventID, intent, 0); AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent); }AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String contentTitle = intent.getStringExtra("contentTitle"); String contentText = intent.getStringExtra("contentText"); String CHANNEL_ID = "my_channel_01"; NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { CharSequence name = "Channel Name"; int importance = NotificationManager.IMPORTANCE_HIGH; NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance); notificationManager.createNotificationChannel(mChannel); } PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.icon_notification) .setContentTitle(contentTitle) .setContentText(contentText) .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.icon_notification)) .setContentIntent(pendingIntent) .setAutoCancel(true) .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)) .setVibrate(new long[]{800, 500, 600, 300}); notificationManager.notify(0, notificationBuilder.build()); Log.d("ALARMRECEIVER", "INSIDE"); } }我想知道如何使广播接收器在后台工作。或者,也可以在Android Oreo +上设置此闹钟,以便即使应用程序关闭或在后台也可以通知用户。
I would like to know what to do to make the Broadcast Receiver work in the background. Or an alternative to set this alarm clock on Android Oreo + so that it notifies the user even with the application closed or in the background.
推荐答案Android具有打a模式,在这种模式下,一些不活动后会进入睡眠状态,即使您设法在某些手机上做到这一点,中文ROM也肯定会给您带来麻烦(在这种情况下,从最新应用中删除会强制停止应用程序运行)
Android has a doze mode in which it goes to sleep after some inactivity, Even if you manage to do this on some phones chinese ROMs will trouble you for sure ( in which removing from recent apps works as force stopping application)
对于您的问题,有一些解决方案,例如工作管理器,Foregroundservices,jobscheduler,它应该可以工作,但不能对所有ROM都说。我认为目前没有适当的解决方案来处理这种后台处理。
For your problem there are solutions Like Work manager , Foregroundservices ,jobscheduler it should work but again can't say for all the ROMs. I think right now there isn't a proper solution to this background processing.
但是您可以做的一件事就是从服务器发送具有高优先级的FCM通知。
But One thing you can do is sending a FCM notification from server with high priority.
您可以看到Facebook和whatsapp可以在后台运行,因为它们已被公司列入白名单。您可以通过从设置中启用自动启动功能来将应用程序列入白名单。但是您需要手动执行此操作,这在我们谈论fb和whatsapp时不会出现
You can see that Facebook and whatsapp can work in background because they are whitelisted by the companies. You can whitelist your application by enabling auto start from settings.But you need to do it manually which isnt a case when we talk about fb and whatsapp
查看此网站以获取更多详细信息: dontkillmyapp/
Check this website for more details : dontkillmyapp/
受此问题影响最大的是闹钟,健康跟踪器,自动化应用程序,日历或只是在不使用手机的特定时刻需要为您完成某些工作的任何事物。
With this issue Most affected are alarm clocks, health trackers, automation apps, calendars or simply anything which needs to do some job for you at a particular moment when you don’t use your phone.
使用Android 6(棉花糖),谷歌已经在基本的Android系统中引入了Doze模式,以期在各种Android手机上统一节省电池。
With Android 6 (Marshmallow), Google has introduced Doze mode to the base Android, in an attempt to unify battery saving across the various Android phones.
不幸的是,一些制造商(例如小米,华为,OnePlus甚至三星)。 )似乎没有接住球,而且他们都有自己的电池保护程序,通常写得很差,仅在表面上节省了电池的副作用。
Unfortunately, some manufacturers (e.g. Xiaomi, Huawei, OnePlus or even Samsung..) did not seem to catch that ball and they all have their own battery savers, usually very poorly written, saving battery only superficially with side effects.
更多推荐
Android Oreo +中的AlarmManager和BroadcastReceiver
发布评论