Fixed
Status Update
Comments
ru...@gmail.com <ru...@gmail.com> #2
Project: platform/frameworks/support
Branch: androidx-master-dev
commit b55fe68edc02b253b908a1c7c2e98350ba67afe4
Author: Ian Lake <ilake@google.com>
Date: Wed Aug 12 14:21:57 2020
Ignore Animations/Animator when Transitions run
For a given Fragment, a single owner for its
transition from visible to non-visible is needed
to avoid conflicts as different systems try to
influence the same set of properties.
This has two consequences:
- Animations (which work at the parent container level)
will interfere if there are *any* Transitions run.
- Animators will interfere if there are any Transitions
run on that specific Fragment.
By tracking which Transitions were started and using
that information to selectively ignore conflicting
Animations/Animators, we can avoid visual artifacts.
Test: updated tests pass
BUG: 149569323
Change-Id: I9e5169ffd36853c3dfbd7f217837a74674a9508d
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionAnimTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java
https://android-review.googlesource.com/1398530
Branch: androidx-master-dev
commit b55fe68edc02b253b908a1c7c2e98350ba67afe4
Author: Ian Lake <ilake@google.com>
Date: Wed Aug 12 14:21:57 2020
Ignore Animations/Animator when Transitions run
For a given Fragment, a single owner for its
transition from visible to non-visible is needed
to avoid conflicts as different systems try to
influence the same set of properties.
This has two consequences:
- Animations (which work at the parent container level)
will interfere if there are *any* Transitions run.
- Animators will interfere if there are any Transitions
run on that specific Fragment.
By tracking which Transitions were started and using
that information to selectively ignore conflicting
Animations/Animators, we can avoid visual artifacts.
Test: updated tests pass
BUG: 149569323
Change-Id: I9e5169ffd36853c3dfbd7f217837a74674a9508d
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionAnimTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java
ra...@google.com <ra...@google.com> #3
There are two parallel systems in Android - the Animation
system and the Animator
system (which the Transition
system is built on top of). With this change and Fragment 1.3.0-alpha08, no Animation
will run if there are any Transitions kicked off at the same time and no Animator
will run on Fragments that have Transitions directly associated with them (either via an enter/exit transition or as part of a shared element transition).
ru...@gmail.com <ru...@gmail.com> #4
Project: platform/frameworks/support
Branch: androidx-master-dev
commit fa55358f7f2870bf05ef5cce12d2b4e2d86732aa
Author: Ian Lake <ilake@google.com>
Date: Mon Sep 14 11:30:52 2020
Ignore Animations when Animators run
As a continuation of the work in b/149569323 ,
we now prioritize running Animators over running
Animations. This avoids cases where both are
running simultaneously.
As Animations and Animators are now properly
decoupled, we can use animator.cancel() when
our CancelationSignal is triggered instead of
using clearAnimation().
Test: all tests pass, updated FragmentAnimatorTest passes
BUG: 167579557
Change-Id: I7b3f5c1cc1355e02ff770838cb485d659dfb1619
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimatorTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java
https://android-review.googlesource.com/1427449
Branch: androidx-master-dev
commit fa55358f7f2870bf05ef5cce12d2b4e2d86732aa
Author: Ian Lake <ilake@google.com>
Date: Mon Sep 14 11:30:52 2020
Ignore Animations when Animators run
As a continuation of the work in
we now prioritize running Animators over running
Animations. This avoids cases where both are
running simultaneously.
As Animations and Animators are now properly
decoupled, we can use animator.cancel() when
our CancelationSignal is triggered instead of
using clearAnimation().
Test: all tests pass, updated FragmentAnimatorTest passes
BUG: 167579557
Change-Id: I7b3f5c1cc1355e02ff770838cb485d659dfb1619
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimatorTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java
ru...@gmail.com <ru...@gmail.com> #5
And shouldn't the behaviour be consistent across all Android versions?
su...@google.com <su...@google.com> #6
We don't see any issues with KEEP. If you have a way for us to reproduce any problems, please send us the appropriate instructions.
ru...@gmail.com <ru...@gmail.com> #7
Ok, I found something odd. Seems like setRequiredNetworkType(NetworkType.UNMETERED) causes this for some reason. I'm going to update the sample so you can review this again. Please, reopen this since it's not intended behavior.
ru...@gmail.com <ru...@gmail.com> #8
This happens on a fresh install with KEEP instead of REPLACE if the constraints have setRequiredNetworkType(NetworkType.UNMETERED). I've updated the sample
ra...@google.com <ra...@google.com> #9
"And shouldn't the behaviour be consistent across all Android versions?"
The behavior is actually consistent. Once your worker starts running, if we get a call to enqueueUniquePeriodicWork a new work request and with ExistingPeriodicWorkPolicy.REPLACE we will stop existing work.
If your Worker was not running, then there is nothing to cancel. This is just a matter of timing.
The behavior is actually consistent. Once your worker starts running, if we get a call to enqueueUniquePeriodicWork a new work request and with ExistingPeriodicWorkPolicy.REPLACE we will stop existing work.
If your Worker was not running, then there is nothing to cancel. This is just a matter of timing.
ru...@gmail.com <ru...@gmail.com> #10
I'm not arguing against the expected behavior of ExistingPeriodicWorkPolicy.REPLACE, since that's working as intended. But this is happening only when setRequiredNetworkType(NetworkType.UNMETERED) is used while having ExistingPeriodicWorkPolicy.KEEP.
ra...@google.com <ra...@google.com> #11
Can you send us an updated sample ?
ra...@google.com <ra...@google.com> #12
Looks like you have updated the sample, let me take another look.
ru...@gmail.com <ru...@gmail.com> #13
Yes, I've updated the sample on github. Thanks for taking another look.
ra...@google.com <ra...@google.com> #14
I looked at your code. Looks like the constraints are being unmet after the work starts in some cases.
So essentially, your worker starts, and mid-way the constraints are unmet. At this point because your Worker may not recover gracefully, we cancel and reschedule work. This happens for all your workers actually (if you turn on verbose logging you can see that).
This too is expected.
So essentially, your worker starts, and mid-way the constraints are unmet. At this point because your Worker may not recover gracefully, we cancel and reschedule work. This happens for all your workers actually (if you turn on verbose logging you can see that).
This too is expected.
to...@gmail.com <to...@gmail.com> #15
We have exactly the same issue in a major app - so that even SDK versions < 23 make up a six figure number of installs. We use WorkManager to synchronize data from an api - this should only happen every couple of minutes and due to this issue, it leads to multiple api calls per seconds on those older Android versions, generating an "expensive" load on our cloud-based infrastructure.
su...@google.com <su...@google.com> #16
Re: #13/14: We're looking at it some more.
#15: File a separate bug, with sample code or a sample app. The issue is vague enough that there could be something completely different happening.
#15: File a separate bug, with sample code or a sample app. The issue is vague enough that there could be something completely different happening.
ru...@gmail.com <ru...@gmail.com> #17
#14: Even with verbose logging selected, I only see TestWorkerA being cancelled. The other workers are still successful.
ra...@google.com <ra...@google.com>
to...@gmail.com <to...@gmail.com> #18
I can confirm the root cause is exactly the same here as in our app:
java.util.concurrent.CancellationException: Task was cancelled.
at androidx.work.impl.utils.futures.AbstractFuture.cancellationExceptionWithCause(AbstractFuture.java:1184)
at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:514)
at androidx.work.impl.utils.futures.AbstractFuture.get(AbstractFuture.java:475)
at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
In our case:
fun scheduleHighlightsSync() {
val request = PeriodicWorkRequest.Builder(SyncHighlightsWorker::class.java, 1, TimeUnit.HOURS)
.setConstraints(Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build())
.build()
WorkManager.getInstance().enqueueUniquePeriodicWork(SYNC_HIGHLIGHTS,
ExistingPeriodicWorkPolicy.KEEP, request)
}
according to the logs TimeUnit.HOURS is ignored and we get them several times per second on SDK < 23
java.util.concurrent.CancellationException: Task was cancelled.
at androidx.work.impl.utils.futures.AbstractFuture.cancellationExceptionWithCause(AbstractFuture.java:1184)
at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:514)
at androidx.work.impl.utils.futures.AbstractFuture.get(AbstractFuture.java:475)
at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
In our case:
fun scheduleHighlightsSync() {
val request = PeriodicWorkRequest.Builder(SyncHighlightsWorker::class.java, 1, TimeUnit.HOURS)
.setConstraints(Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build())
.build()
WorkManager.getInstance().enqueueUniquePeriodicWork(SYNC_HIGHLIGHTS,
ExistingPeriodicWorkPolicy.KEEP, request)
}
according to the logs TimeUnit.HOURS is ignored and we get them several times per second on SDK < 23
ru...@gmail.com <ru...@gmail.com> #19
01-09 18:36:22.440 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerA: I did some work
01-09 18:36:22.450 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerB: I did some work
01-09 18:36:22.740 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerC: I did some work
01-09 18:36:22.750 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerD: I did some work
01-09 18:36:23.050 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerE: I did some work
01-09 18:36:52.350 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerA: I did some work
01-09 18:36:52.360 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerB: I did some work
01-09 18:36:52.650 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerC: I did some work
01-09 18:36:52.650 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerD: I did some work
01-09 18:36:52.950 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerE: I did some work
01-09 18:37:22.350 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerA: I did some work
01-09 18:37:22.380 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerB: I did some work
01-09 18:37:22.660 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerC: I did some work
01-09 18:37:22.680 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerD: I did some work
01-09 18:37:22.960 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerE: I did some work
01-09 18:38:22.350 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerA: I did some work
01-09 18:38:22.390 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerB: I did some work
01-09 18:38:22.660 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerC: I did some work
01-09 18:38:22.690 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerD: I did some work
01-09 18:38:22.950 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerE: I did some work
Logs when all workers are affected. Even though Result.sucess() was returned, due to this issue, WorkManager keeps retrying them. You can see the exponential backoff starting at 30 sec and going to 1 min, 2 min, 4 min etc
01-09 18:36:22.450 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerB: I did some work
01-09 18:36:22.740 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerC: I did some work
01-09 18:36:22.750 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerD: I did some work
01-09 18:36:23.050 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerE: I did some work
01-09 18:36:52.350 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerA: I did some work
01-09 18:36:52.360 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerB: I did some work
01-09 18:36:52.650 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerC: I did some work
01-09 18:36:52.650 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerD: I did some work
01-09 18:36:52.950 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerE: I did some work
01-09 18:37:22.350 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerA: I did some work
01-09 18:37:22.380 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerB: I did some work
01-09 18:37:22.660 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerC: I did some work
01-09 18:37:22.680 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerD: I did some work
01-09 18:37:22.960 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerE: I did some work
01-09 18:38:22.350 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerA: I did some work
01-09 18:38:22.390 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerB: I did some work
01-09 18:38:22.660 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerC: I did some work
01-09 18:38:22.690 12508-12528/com.github.rubensousa.workkitkatbug D/TestWorkerD: I did some work
01-09 18:38:22.950 12508-12529/com.github.rubensousa.workkitkatbug D/TestWorkerE: I did some work
Logs when all workers are affected. Even though Result.sucess() was returned, due to this issue, WorkManager keeps retrying them. You can see the exponential backoff starting at 30 sec and going to 1 min, 2 min, 4 min etc
to...@gmail.com <to...@gmail.com> #20
Yes, definitely not 15 minutes as in your github example project.
to...@gmail.com <to...@gmail.com> #21
I think if this issue can not be solved quickly, https://developer.android.com/topic/libraries/architecture/workmanager/ needs a big warning message for SDK < 23 - at least for periodic jobs
to...@gmail.com <to...@gmail.com> #24
Thanks!!! Is there a time estimate for the next beta ?
ru...@gmail.com <ru...@gmail.com> #25
#23: Thank you so much for taking another look and solving the issue :)
su...@google.com <su...@google.com> #26
#24: Most likely next week.
Description
Version used: 1.0.0-beta1
Devices/Android versions reproduced on: API 19
This seems to be happening on API 19 only.
To reproduce, just add a Thread.sleep(1000) in any worker before returning Result.SUCCESS. Worker is stopped due to cancellation instead of being treated as being successful. This causes the worker to being retried.
In our case, the behavior is the same. We're using RxJava and blocking observable operators to perform network requests. This issue causes API 19 devices to keep running the same worker using the backoff strategy instead of marking it as success.
Sample project: