Start start delayed (startActivity).

Recently, I get information from users that the application for the alarm does not ring when it is needed. Finally, one of the users sent me information from the assembly in the log, it was really strange:

74. 4:25:0 - StartAlarm received 75. 5:22:15 - AlarmOnScreen create 76. 5:22:15 - Time: 04:25 

The problem is that the log information is stored as follows:

 //BroadcastReceiver @Override public void onReceive(Context context, Intent intent) { Logger.initialize(context); Logger.log("StartAlarm received"); Intent i = new Intent(context, AlarmOnScreen.class); i.putExtras(intent.getExtras()); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(i); } //AlarmOnScreen (activity) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.alarm_on_screen); Logger.log("AlarmOnScreen create"); //Time value of alarm is logged below (...) 

As you can see, the onset of activity was significantly delayed. How is this possible? The user reported that the alarm was delayed until he began to "use" the phone. I assume that this means that the screen lock will not be unlocked or the screen is turned on. I am still waiting for an answer with more information. At other times, delays were only 5 minutes - each time until the user started using the β€œphone”

Any ideas?

EDIT: Let me add, something that has begun recently, after the application has been for several months. I am still looking to see if I can change anything in the manifest and in the latest update, but is it possible that this something happens only in new versions of Android?

+4
source share
2 answers

I think your problem is using AlarmManager without using WakeLocks properly, when the device is sleeping with the screen off, your receiver will not work properly.

I think your receiver got onReceive () from AlarmManager, which most likely was launched with the _WAKEUP flag as follows:

 mAlarmManager.set(AlarmManager.RTC_WAKEUP, .......); 

This _WAKEUP flag means that the device will be "turned on" even if it is in sleep mode. However, as described in the documentation here ( http://developer.android.com/reference/android/app/AlarmManager.html ):

The alarm manager contains a processor monitoring lock while the onReceive () alarm receiver is running. This ensures that the phone will not sleep until you finish working with the broadcast. When the onReceive () function returns, the alarm manager releases this lock. This means that the phone will sleep in some cases as soon as your onReceive () method is complete. If your alarm receiver is called Context.startService (), it is possible that the phone will sleep before the requested service starts. To prevent this from happening, your BroadcastReceiver and service will need to implement a separate tracking blocking policy to make sure that the phone continues to work until the service becomes available.

In your code, this means that the system goes back to sleep as soon as onReceive() finishes, and as startActivity(i) does not work synchronously - this leads directly to the problem mentioned above - it will start, but a lot, much later when the user turns on the screen.

To solve this problem, I would recommend doing something like this:

 //BroadcastReceiver @Override public void onReceive(Context context, Intent intent) { Logger.initialize(context); Logger.log("StartAlarm received"); Intent i = new Intent(context, AlarmOnScreen.class); i.putExtras(intent.getExtras()); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(i); AlarmOnScreen.acquireLock(context); //Before, system could sleep right after this line(not exactly, however) and activity actually would be started much later } //AlarmOnScreen (activity) private static WakeLock sWakeLock; public static void acquireLock(Context context) { PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); sWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "providersLock"); //Limit 10 sec, if something wrong will happen - we'll not drain the battery to much. sWakeLock.acquire(10000); //As we are acquiring and releasing only once - we don't need a counter. sWakeLock.setReferenceCounted(false); } private static void releaseLock(Context context) { try { sWakeLock.release(); } catch (Exception e) { //In case it already auto-released e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.alarm_on_screen); Logger.log("AlarmOnScreen create"); //Time value of alarm is logged below (...) @Override protected void onResume() { releaseLock(this); } 

This solution will work for the first time and will allow you to better understand the problem. To check - just start using your alarms when the screen is off and maybe the cable is connected, but I'm not sure that the latter is really necessary to put the device into sleep mode.

However, I would strongly recommend implementing a more elegant solution suitable for your project, because the current static reference design is pretty bad, as it does not work perfectly in racing conditions, for example.

Hope this helps, and please let me know if you have any questions. Good luck.

UPD: I think I also suggest using not only PARTIAL_WAKE_LOCK, but also FULL. How:

 pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "providersLock"); 

This will cause the screen to be turned on in any case, not depending on the previous state and platform reaction when creating a new activity.

+5
source

In the activity window, you need to set several flags:

 getWindow().addFlags( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON ); 
0
source

Source: https://habr.com/ru/post/1432893/


All Articles