-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Fix/129 fix eliminate parkings flickering #152
Fix/129 fix eliminate parkings flickering #152
Conversation
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.
I'll try to do this too when I have a moment. I have few ideas but we'll see how they'll do
@@ -13,7 +13,7 @@ extension RefIntervalRefreshX on Ref { | |||
void setRefresh(Duration interval) { | |||
final timer = Timer.periodic( | |||
interval, | |||
(t) => invalidateSelf(), | |||
(t) => invalidate(parkingsRepositoryProvider), |
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.
Unfortunetly this throws :(
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: 'package:riverpod/src/framework/element.dart': Failed assertion: line 614 pos 11: 'listenable._origin != origin': A provider cannot depend on itself
basically invalidateSelf()
and invalidate(someProvider)
works the same with the difference the second one seems to throw when use inside the same provider (I didn't knew that actually, but make sense)
@mikolaj-jalocha I've been playing around with it for some time 😭 But I have a fix. Suprisingly it wasn't so much about the riverpod but more with the UI itself and the Nagranie.z.ekranu.2024-08-10.o.16.14.49.mov |
1a93f8c
to
c0d5083
Compare
@mikolaj-jalocha when you have a moment you can make a review here, cause i cannot request review from its author |
@simon-the-shark thanks for feedback. I didn't see exception before (I should look on logs..). I will do review ASAP (tomorrow) |
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.
The flickering issue seemed simple to fix but ended up requiring quite a refactor. Good job! I wouldn’t have come up with a solution so quickly—my Flutter experience is too limited and my state management skills aren’t strong enough for that. 😂
Below are a few suggestions and some questions I have about how certain parts of the code work, so I can better understand the issue.
I really like the introduction of IList. It's an order of magnitude faster than Flutter's built-in version, and I think it could have a noticeable impact on our app’s performance.
By the way, every time I review your code, I end up reading documentation on something new—which is cool!
@@ -6,7 +6,7 @@ import "../../../config/api_base_config.dart"; | |||
part "iparking_client.g.dart"; | |||
|
|||
abstract class ParkingsConfig { | |||
static const parkingsRefreshInterval = Duration(minutes: 1); | |||
static const parkingsRefreshInterval = Duration(seconds: 30); |
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 the period here ok?
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.
Yeah I did this on purpose. It's not our server anyway and previously if we entered app in unfortunate moment we could have almost 1 minut delay from the server. Now it's tops 30 sec. In the future we can think of some mechanism that will "align" our refreshes with those on server
.watch(context.mapSourceRepository<T>()) | ||
.value | ||
.whereNonNull | ||
.toList(); |
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.
I wonder if we can use here immutable list? (IList
)
btw the way Consumer
here's introduced improved visibility a lot imo.
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.
Btw, is this a change that reduced flickering? Moving state refreshment inside AsyncValue
?
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.
Yeah we can use IList here
I moved the state listening down the tree in few places, meaning less widgets are refreshed needlesly. But it still doesn't help :P with the flickering
AsyncError(:final error) => | ||
SliverToBoxAdapter(child: MyErrorWidget(error)), | ||
AsyncValue(:final value) => | ||
_DataSliverList<T>(value.whereNonNull.toList()) | ||
_ => const DataListLoading(), |
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.
What happened to AsyncLoading
?
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.
That's the change that helped. This alone solves the problem. I got the idea from docs as well, from the pull to refresh guide. https://riverpod.dev/docs/case_studies/pull_to_refresh
What was the problem is the fact that after refresh the state changes to AsyncLoading
and we showed the loading screen for a second.
It turns out through, even though the state is loading. State.value still holds previous value for us to use.
So I changed the pattern matching switch logic a bit.
Now if the async value have any value we show it. If it has error we show error and in all other cases (_
means all unmatched previously things) we show loading screen. So the loading screen shows if we have async loading or async data with value=null
// misz-masz here fixed flickering | ||
// we probably should consider similar refactoring to all switches, but won't be visible in our other use-cases | ||
AsyncValue(:final IList<T?> value) => | ||
_DataSliverList<T>(value.whereNonNull.toIList()), |
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.
Does the introduction of immutable list reduced flickering?
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.
It was one of many things I've tried cause IList
implements list comparability, meaning ILists
are equal if have equal elements in same order. Hovewer I forgot the riverpod doesn't check equality ==
operator anyway, but uses identical
comparator. More you can read here in one of the questions https://riverpod.dev/docs/essentials/faq
It allowed me to reduce flickering frequency with manual check, but didn't eliminate it fully:
if (state != newstate) {
state = newstate; // or ref.invalidate or smth, basically reduces flickering to only situation when the number of places changed
}
So its not the solution but I left the IList
anyway cause it's recommended to have immutable and combarable state objects
final itemSelected = ref.watch(mapControllers.activeMarker); | ||
if (itemSelected != null) { | ||
return [itemSelected]; // shows only selected building | ||
return [itemSelected].lock; // shows only selected building |
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.
Tell me if i properly understand that; if the item is selected, the list cannot be modified?
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.
I believe .lock
is just a shortcut for .toIList()
but I didn't dive deeply
Thanks for the review! Hopefully i answered your questions here. If not, then hit me up or we can hop on a call too. Basically for state management i reccomend the official riverpod.dev docs. They are crazy good. I like to read all the pages there from time to time when I have a problem. And also if youre not that familiar with pattern matching concept you can check it out too. Its very powerfull tool, pretty new to dart and we're using it in a very limited range here |
I've tested it on Android device (the bug was there before as well). Everything looks fine. Hopefully new state is being updated.