-
Notifications
You must be signed in to change notification settings - Fork 24.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix RefreshControl race condition #7317
Conversation
By analyzing the blame information on this pull request, we identified @bestander and @andreicoman11 to be potential reviewers. |
Seems reasonable to me, what do you think @bestander? |
Lgtm |
@facebook-github-bot shipit |
Thanks for importing. If you are an FB employee go to Phabricator to review. |
8fbce30
@janicduplessis looks like this change breaks ReactSwipeRefreshLayoutTestCase instrumentation test that got open sourced just a couple of days ago. |
I'll have to revert for now but please rebase and try again |
This reverts commit 8fbce30. Reverts facebook#7317 because it breaks instrumentation tests https://circleci.com/gh/facebook/react-native/6521
Summary: This reverts commit 8fbce30. Reverts #7317 because it breaks instrumentation tests https://circleci.com/gh/facebook/react-native/6521 Closes #7529 Differential Revision: D3292461 fbshipit-source-id: 7dcde05adefe41e6b3c28697fccfa232a45f0742
2228752
to
0d61933
Compare
@janicduplessis updated the pull request. |
Found out what the problem is, there is a dead lock with |
thanks, Janic! On Fri, May 13, 2016 at 6:55 PM, Janic Duplessis [email protected]
|
I think I got to the bottom of this, the test block when calling What was weird is that it worked before so I checked what my PR changed and found out that I added a check to only call Doesn't work @Override
public void setRefreshing(boolean refreshing) {
if (mRefreshing != refreshing) {
mRefreshing = refreshing;
// Use `post` otherwise the control won't start refreshing if refreshing is true when
// the component gets mounted.
post(new Runnable() {
@Override
public void run() {
ReactSwipeRefreshLayout.super.setRefreshing(mRefreshing);
}
});
}
} Works @Override
public void setRefreshing(boolean refreshing) {
mRefreshing = refreshing;
// Use `post` otherwise the control won't start refreshing if refreshing is true when
// the component gets mounted.
post(new Runnable() {
@Override
public void run() {
ReactSwipeRefreshLayout.super.setRefreshing(mRefreshing);
}
});
} To be honest I'm not really sure why it makes it work but eh :) |
@janicduplessis updated the pull request. |
Thanks for giving it a try, @janicduplessis. The code change in this PR does not fix a race condition though. |
Yeah there is definetly something wrong, One way of fixing it that I can see is using a simple sleep ~1sec before the assertion instead, it's a bit hacky but should work 100% since we can't rely on the normal wait technique that can block forever if a repeating animation is going on. Do we want to merge this PR for now in address the test separatly? Right now it doesn't make it better or worse :) |
To be fair, I would leave it as is until we get an improvement. |
public ReactSwipeRefreshLayout(ReactContext reactContext) { | ||
super(reactContext); | ||
} | ||
|
||
@Override | ||
public void setRefreshing(boolean refreshing) { | ||
mRefreshing = refreshing; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this field useful?
It is read only once in the new Runnable below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the problem is when setRefreshing gets called twice in the same bridge transaction the order the runnables get executed is bad, see the example in the PR desc, adding the field makes sure is uses the latest value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see thanks, that makes sense.
@janicduplessis, when you give it another look, could you create a new PR? |
Sure, let's close this one. |
Summary: Improved version of #7317. `setRefreshing` and `setProgressViewOffset` needs to be called after the view has been layed out. Instead of using `post` to do that we update the `refreshing` and `progressViewOffset` values in the first call to `onLayout`. I also noticed that `progressViewOffset` default value wasn't exactly the same as when not calling `setProgressViewOffset` at all. Tweaked the values to match android defaults. **Test plan (required)** Make sure the integration test passes, In UIExplorer: test RefreshControl with `refreshing = true` initially, test `progressViewOffset`. Closes #7683 Differential Revision: D3334426 fbshipit-source-id: ddd63a5e9a6afe2b8b7fe6a25e875a40f4e888c6
Summary: There was a race condition with `SwipeRefreshLayout` that cause the `RefreshControl` to keep refreshing when it shouldn't. It was caused because we have to use `post` to set the refreshing state otherwise it doesn't work when setting `refreshing=true` on initial mount. What happened is that `post` doesn't guarantee the order the runnables will be called so calling post with `refreshing=true` followed by `refreshing=false` caused the `resfreshing=false` runnable to be called before the `resfreshing=true` one. This made it stay in refreshing state when it should not. ``` D/test ( 6171): setRefreshing true W/ReactNativeJS( 6171): false D/test ( 6171): setRefreshing false D/test ( 6171): setRefreshing post false D/test ( 6171): setRefreshing post true ``` This change adds an instance variable and uses it in the `post` runnable to make sure the last set value is always used. **Test plan (required)** Tested that it fixed the issue in the [original issue app](https://github.com/digisqu Closes facebook#7317 Differential Revision: D3290464 Pulled By: andreicoman11 fbshipit-source-id: 15cabcfc6d2f191443be96e8845b924ce66c369f
Summary: This reverts commit 8fbce30. Reverts facebook#7317 because it breaks instrumentation tests https://circleci.com/gh/facebook/react-native/6521 Closes facebook#7529 Differential Revision: D3292461 fbshipit-source-id: 7dcde05adefe41e6b3c28697fccfa232a45f0742
Summary: There was a race condition with `SwipeRefreshLayout` that cause the `RefreshControl` to keep refreshing when it shouldn't. It was caused because we have to use `post` to set the refreshing state otherwise it doesn't work when setting `refreshing=true` on initial mount. What happened is that `post` doesn't guarantee the order the runnables will be called so calling post with `refreshing=true` followed by `refreshing=false` caused the `resfreshing=false` runnable to be called before the `resfreshing=true` one. This made it stay in refreshing state when it should not. ``` D/test ( 6171): setRefreshing true W/ReactNativeJS( 6171): false D/test ( 6171): setRefreshing false D/test ( 6171): setRefreshing post false D/test ( 6171): setRefreshing post true ``` This change adds an instance variable and uses it in the `post` runnable to make sure the last set value is always used. **Test plan (required)** Tested that it fixed the issue in the [original issue app](https://github.com/digisqu Closes facebook#7317 Differential Revision: D3290464 Pulled By: andreicoman11 fbshipit-source-id: 15cabcfc6d2f191443be96e8845b924ce66c369f
Summary: This reverts commit 8fbce30. Reverts facebook#7317 because it breaks instrumentation tests https://circleci.com/gh/facebook/react-native/6521 Closes facebook#7529 Differential Revision: D3292461 fbshipit-source-id: 7dcde05adefe41e6b3c28697fccfa232a45f0742
Summary: Improved version of facebook#7317. `setRefreshing` and `setProgressViewOffset` needs to be called after the view has been layed out. Instead of using `post` to do that we update the `refreshing` and `progressViewOffset` values in the first call to `onLayout`. I also noticed that `progressViewOffset` default value wasn't exactly the same as when not calling `setProgressViewOffset` at all. Tweaked the values to match android defaults. **Test plan (required)** Make sure the integration test passes, In UIExplorer: test RefreshControl with `refreshing = true` initially, test `progressViewOffset`. Closes facebook#7683 Differential Revision: D3334426 fbshipit-source-id: ddd63a5e9a6afe2b8b7fe6a25e875a40f4e888c6
Summary: There was a race condition with `SwipeRefreshLayout` that cause the `RefreshControl` to keep refreshing when it shouldn't. It was caused because we have to use `post` to set the refreshing state otherwise it doesn't work when setting `refreshing=true` on initial mount. What happened is that `post` doesn't guarantee the order the runnables will be called so calling post with `refreshing=true` followed by `refreshing=false` caused the `resfreshing=false` runnable to be called before the `resfreshing=true` one. This made it stay in refreshing state when it should not. ``` D/test ( 6171): setRefreshing true W/ReactNativeJS( 6171): false D/test ( 6171): setRefreshing false D/test ( 6171): setRefreshing post false D/test ( 6171): setRefreshing post true ``` This change adds an instance variable and uses it in the `post` runnable to make sure the last set value is always used. **Test plan (required)** Tested that it fixed the issue in the [original issue app](https://github.com/digisqu Closes facebook#7317 Differential Revision: D3290464 Pulled By: andreicoman11 fbshipit-source-id: 15cabcfc6d2f191443be96e8845b924ce66c369f
Summary: This reverts commit 8fbce30. Reverts facebook#7317 because it breaks instrumentation tests https://circleci.com/gh/facebook/react-native/6521 Closes facebook#7529 Differential Revision: D3292461 fbshipit-source-id: 7dcde05adefe41e6b3c28697fccfa232a45f0742
Summary: Improved version of facebook#7317. `setRefreshing` and `setProgressViewOffset` needs to be called after the view has been layed out. Instead of using `post` to do that we update the `refreshing` and `progressViewOffset` values in the first call to `onLayout`. I also noticed that `progressViewOffset` default value wasn't exactly the same as when not calling `setProgressViewOffset` at all. Tweaked the values to match android defaults. **Test plan (required)** Make sure the integration test passes, In UIExplorer: test RefreshControl with `refreshing = true` initially, test `progressViewOffset`. Closes facebook#7683 Differential Revision: D3334426 fbshipit-source-id: ddd63a5e9a6afe2b8b7fe6a25e875a40f4e888c6
There was a race condition with
SwipeRefreshLayout
that cause theRefreshControl
to keep refreshing when it shouldn't.It was caused because we have to use
post
to set the refreshing state otherwise it doesn't work when settingrefreshing=true
on initial mount. What happened is thatpost
doesn't guarantee the order the runnables will be called so calling post withrefreshing=true
followed byrefreshing=false
caused theresfreshing=false
runnable to be called before theresfreshing=true
one. This made it stay in refreshing state when it should not.This change adds an instance variable and uses it in the
post
runnable to make sure the last set value is always used.Test plan (required)
Tested that it fixed the issue in the original issue app and did some additional tests in UIExplorer example to make sure everything still worked properly.
Fixes #7313