Skip to content

How to unregister an re-registerSingleton properly? #112

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

Closed
freewebwithme opened this issue Sep 30, 2020 · 17 comments
Closed

How to unregister an re-registerSingleton properly? #112

freewebwithme opened this issue Sep 30, 2020 · 17 comments

Comments

@freewebwithme
Copy link

Hi!
I am using get_it with injectable package.
I need to update some of instance like session and client that is already registered.
In Session case,
I registered session instance manually(not using injectable for session instance) after successfully logged in.

final session = Session.fromJson(result.data["logIn"]);

// here  I am updating a session instance
if (getIt.isRegistered<Session>()) {
    getIt.unregister<Session>();
   // Register new session instance
    getIt.registerSingleton<Session>(session);
  } else {
    getIt.registerSingleton<Session>(session);
  }
  

But it seems that there is still a old session instance.
Am I doing wrong?

I googled for this and also tried in issues, but I can't find proper answer for me.
And for now I can't upgrade to v5 because getIt V5 is not supported in injectable.

@escamoteur
Copy link
Collaborator

On first glance, this looks totally fine for me. What do you mean with 'is seems there is an old instance'?
Do you get an exception?

@freewebwithme
Copy link
Author

Thanks for your reply. Yes the problem was from other thing.
I have more question relating this title.

If instance A(Singleton) is depending on instance B(Singleton), then some reason I got new instance B.
So I unregister instance B and re-register instance B.
Do I have to re-register instance A to get a new instance B?

For example

@singletone
class AuthenticationApi {
  AuthenticationApi(this.client);
  final GraphQLClient client;
}

AuthenticationApi is created at app starts up and client instance also created without auth token.
After login or sign up, I created new instance of client with auth token.
So I did

  // creating new client instance
  final client = Client().client();
  if (getIt.isRegistered<GraphQLClient>()) {
    getIt.unregister<GraphQLClient>();
    getIt.registerSingleton<GraphQLClient>(client);
  } else {
    getIt.registerSingleton<GraphQLClient>(client);
  }

So I registered new singleton of client.
Do I have to do this for AuthenticationApi instance also?
AuthenticationApi instance still has old client instance?

@escamoteur
Copy link
Collaborator

You are using injectable right? I have no idea what it does under the hood.
If you are using GetIt manually you don't have such effects.

@EngGemy95
Copy link

EngGemy95 commented May 22, 2022

I have the same problem and i did not find any solution .
But I used your code for unregister all previous instance and register it after login ( and it work ) .

@razasubtain
Copy link

razasubtain commented Jan 31, 2025

final GetIt locator = GetIt.instance;

///[register]
///
void register(BaseOptions dioBaseOptions) {
p('Base Options===========================> ${dioBaseOptions.baseUrl}');
locator.registerLazySingleton(
() => DioConfig(initialOptions: dioBaseOptions),
);
locator.registerLazySingleton(
() => ApiService(
dioConfig: locator(),
),
);
}

unRegisterAllLocator() async {

await locator.unregister< ApiService >();

await locator.unregister< DioConfig >();

}

i have two different configurations for the api's in my application. During login i have different base options and after login i use different baseOptions.After login When i unRegister locators through (unRegisterAllLocator() ) and register locator with new baseoptions it works fine and uses the new base options. but when i try to logout the user and unregister the locators and pass the locator with new baseOptions it prints the new baseoptions as i use the p('Base Options===========================> ${dioBaseOptions.baseUrl}'); but when i call the api it somehow uses the old instance with old baseoptions. I am stuck for a while and don't understand why this is happening.

@escamoteur
Copy link
Collaborator

escamoteur commented Feb 1, 2025 via email

@razasubtain
Copy link

How should get_it know which object it should unregister if you don't pass the type?

I'm general for your use case of login/logout I recommend using get_it scopes for that. Check the Readme.
Am 1. Feb. 2025, 00:44 +0100 schrieb razasubtain @.***>:

i have passed the type somehow it is not displayed in the question i share my code again
void register(BaseOptions dioBaseOptions) {
p('Base Options===========================> ${dioBaseOptions.baseUrl}');
locator.registerLazySingleton(
() => DioConfig(initialOptions: dioBaseOptions),
);
locator.registerLazySingleton(
() => ApiService(
dioConfig: locator(),
),
);
}

unRegisterAllLocator() async {

await locator.unregister< ApiService >();

await locator.unregister< DioConfig >();

}
just adding the quotes for question purpose show how the type is getting removed when i post the question but i am not using quotes in real.

please have a look if need some info let me know.
the log printing the correct baseoption but when i call the api it somehow uses the old baseoption and old instance.

@escamoteur
Copy link
Collaborator

escamoteur commented Feb 1, 2025 via email

@razasubtain
Copy link

This is actually my company project so can't share unfortunately but i used the pushNewScope and it did not worked.
locator(BaseOptions dioBaseOptions){
if (!locator.hasScope('sessionScope')) {
locator.pushNewScope(
scopeName: 'sessionScope',
dispose: () {
p('Session Scope Disposed');
},
);
}

locator.registerLazySingleton(
() => DioConfig(options: dioBaseOptions),
);

locator.registerLazySingleton(
() => ApiService(
dioConfig: locator( ),
),
);}
////
unRegisterAllLocator() async {
if (locator.hasScope('sessionScope')) {
await locator.popScope(); // Clears all scoped dependencies
}

// Below theses are my dio configurations which i pass inside the DioConfig class based on if user is logged in or not.
after logout it uses the old instance even after calling the unregisterAllLocator Method. I don't understand why this is happening.
///
class AllDioOptions {
static final FirstDioOptions = BaseOptions(
validateStatus: (status) {
return status != null &&
status >= 200 &&
status < 400; // Allow redirects
},
followRedirects: true,
baseUrl: AllBaseUrl.cAuthEndPoint,
connectTimeout: const Duration(seconds: 100),
receiveTimeout: const Duration(seconds: 100),
headers: DifferentHeaders.getCHeader());

static final SecondDioOptions = BaseOptions(
validateStatus: (status) {
return status != null &&
status >= 200 &&
status < 400; // Allow redirects
},
followRedirects: true,
baseUrl: AllBaseUrl.tBaseUrl,
connectTimeout: const Duration(seconds: 100),
receiveTimeout: const Duration(seconds: 100),
headers: DifferentHeaders.getTHeader());
}

@escamoteur
Copy link
Collaborator

escamoteur commented Feb 3, 2025 via email

@razasubtain
Copy link

Can you please tell me one thing, if there are multiple threads running can it lead to this issue where even
after unregistering the instances i am still getting the old instance ?

@escamoteur
Copy link
Collaborator

escamoteur commented Feb 4, 2025 via email

@razasubtain
Copy link

razasubtain commented Feb 5, 2025

First of all thanks for you response. I resolved the issue finally. Actually i was calling the multiple api's at a time and after using that approached which you mentioned to check directly if the object is registered or not after unregistering it
if (locator.isRegistered<"ApiService">()) { p('Api Service Still registered=========='); }

i realized the print statement was being called even after unregistering the locator i am not sure why this was happening any idea??? so i did this
await unregisterService<" ApiService ">();
Future unregisterService<"T extends Object">() async {
if (locator.isRegistered<"T">()) {
p('Unregistering ${T.toString()}...');
await locator.unregister<"T">();
} else {
p('${T.toString()} is not registered.');
}
}

and explicitly removed the locator from getit . After that i never got the log of "Api service is still registered".

The second change which i had to make was specifically not related to getit but it might be helpful for someone in future.

dio = Dio(
BaseOptions(
validateStatus: (status) => status != null && status >= 200 && status < 400,
followRedirects: true,
baseUrl: AllBaseUrl.cAuthEndPoint,
connectTimeout: const Duration(seconds: 100),
receiveTimeout: const Duration(seconds: 100),
headers: {
'accept': 'application/json',
'authorization': 'Bearer $_token',
'content-type': 'application/json',
},
),
);
i was passing the token as a string variable so in all cases after logging out it was keeping the old token until i restart the app so i changed the variable with getToken() method to return the latest token every time . Small mistake but it was over looked and took so much time to notice but thankfully the issue got resolved. Thanks Again!!!!

@escamoteur
Copy link
Collaborator

escamoteur commented Feb 5, 2025 via email

@razasubtain
Copy link

razasubtain commented Feb 5, 2025

i am also confused why my type is getting removed when i save the comment. I just added the qoutes around the type for avoiding this behaviour only, not a part of my actual flutter code .

@escamoteur
Copy link
Collaborator

escamoteur commented Feb 5, 2025 via email

@razasubtain
Copy link

No actually i was awaiting the unregisterAll method. The problem which i couldn't completely understand the reason was i called the unregistered method only once on logout but i was getting the multiple print statements of the below print statement maybe because i was calling the multiple api's at same time so there was some kind of race problem.
if (locator.isRegistered<"ApiService">())
{
p('Api Service Still registered==========');

}

so instead of unregistering them directly i put a condition to first check if it is register then unregister it so if unregisterAll method is called multiple times in a response of multiple api executions it verifies every time if the instance is register then unregister it. Also i was using some static values which were might be causing the Race problem so i converted them into singleton. For now my code is working fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants