Reputation: 196
I am retrying an api call if I get 401 response but I am not Abel to call and I am facing exception following is my retry code
final client = RetryClient(
http.Client(),
retries: 1,
when: (response) {
return response.statusCode == 401 ? true : false;
},
onRetry: (req, res, retryCount) {
print('retry started');
if (retryCount == 0 && res?.statusCode == 401) {
Provider.of<Auth>(context, listen: false).restoreAccessToken();
}
},
);
in the above code I am Abel to restore new access token but I am not Abel to retry api call following is my proxy provider I Am guessing error is coming from here
ChangeNotifierProxyProvider<Auth, ApiCalls>(
create: (_) => ApiCalls(null),
update: (context, auth, previous) => ApiCalls(auth.token)),
Upvotes: 1
Views: 536
Reputation: 479
I've tried several and will share what I came up with.
I ran into the same issue mentioned in the question, I'll explain it again now.
This is my ChangeNotifierProxyProvider code:
ChangeNotifierProxyProvider<ProfileProvider, SplashProvider>(
create: (context) => SplashProvider(splashRepo: SplashRepo(), profileProvider: ProfileProvider()),
update: (context, profileProvider, _) => SplashProvider(splashRepo: SplashRepo(), profileProvider: profileProvider),
),
And when I execute the notifyListeners();
function from SplashProvider
, the same error mentioned in the question pops up
Unhandled Exception: A SplashProvider was used after being disposed.
So the logical solution is to move the Provider above MaterialApp/Navigator as mentioned in this issue.
However my code is actually written this way! So how does this error appear? I don't understand why SplashProvider is being disposed? I did not even disposed my current screen yet!
So I've tried the following:
SplashProvider({
required this.splashRepo,
required this.profileProvider,
})
to:
SplashProvider({
required this.splashRepo,
required this.profileProvider,
}) {
debugPrint('SplashProvider constructor');
}
To keep track of the number of objects being created from the same provider It turned out that more than one instance was created, and this is the output:
I/flutter ( 5370): SplashProvider constructor
I/flutter ( 5370): SplashProvider constructor
I/flutter ( 5370): SplashProvider constructor
So I modified the constructor by adding message
:
final SplashRepo splashRepo;
ProfileProvider? profileProvider;
+ final String? message;
SplashProvider({
required this.splashRepo,
this.profileProvider,
+ this.message,
}) {
debugPrint('SplashProvider constructor: $message');
}
Then changed ChangeNotifierProxyProvider
by adding message
to distinguish each of them:
ChangeNotifierProxyProvider<ProfileProvider, SplashProvider>(
create: (context) => SplashProvider(message: 'create', splashRepo: SplashRepo(), profileProvider: ProfileProvider()),
update: (context, profileProvider, _) => SplashProvider(message: 'update', splashRepo: SplashRepo(), profileProvider: profileProvider),
),
Then I wrote these two commands into SplashProvider
to track if the provider was disposed
or not, and also when notifyListeners
was called, and for which object in them.
@override
void dispose() {
debugPrint('SplashProvider disposed...[$message]');
super.dispose();
}
@override
void notifyListeners() {
debugPrint('notifyListeners in splash: [$message]');
super.notifyListeners();
}
And this is the output:
...
I/flutter ( 5370): SplashProvider constructor: create
I/flutter ( 5370): SplashProvider constructor: update
I/flutter ( 5370): notifyListeners in splash: [update]
...
I/flutter ( 5370): SplashProvider constructor: update
I/flutter ( 5370): SplashProvider disposed...[update]
I/flutter ( 5370): [🌎 Easy Localization] [DEBUG] Build
...
I/flutter ( 5370): notifyListeners in splash: [update]
E/flutter ( 5370): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: A SplashProvider was used after being disposed.
E/flutter ( 5370): Once you have called dispose() on a SplashProvider, it can no longer be used.
...
notifyListeners
in the updated instance which had disposed already!then it throws that error 😃
To solve this problem I tried changing the main ChangeNotifierProxyProvider command to:
ChangeNotifierProxyProvider<ProfileProvider, SplashProvider>(
create: // same code...,
update: (context, profileProvider, prev) => prev!..setProfileProvider(profileProvider),
),
And surely added this function in SplashProvider
:
void setProfileProvider(ProfileProvider profile){
this.profileProvider = profile;
}
to set profileProvider.
Upon trying more than once, the problem was actually solved. 1. The error never appears again. 2. SplashProvider is not disposed. 3. Only one Provider instance is created.
But I don't know yet if this will affect the other Provider that I passed to SplashProvider and will it pass the same instance or will it create a new instance? I will experiment and if there is something unexpected I will amend my comment.
Upvotes: 2
Reputation: 196
here after a long try I got the solution following code solved the issue I had changed code in change notifier provider
ChangeNotifierProxyProvider<Auth, ApiCalls>(
create: (_) => ApiCalls(),
update: (context, auth, previous) =>
previous!..updates(auth.token!)),
Upvotes: 0