- Android Design Patterns: The Singleton Pattern
- What Is the Singleton Pattern?
- Benefits of the Singleton Pattern
- Implementation
- Example: Creating a Single Instance of Retrofit
- Dealing With Multithreading
- Synchronize the getInstance() Method
- Eagerly Create an Instance
- Bonus: Using Dagger 2
- Conclusion
- Шаблоны дизайна Android: шаблон Singleton
- Что такое шаблон синглтона?
- Преимущества шаблона Singleton
- Реализация
- Singletons in Android
- Avoid them or at least think twice before use them
- So, what if I have simple Singleton
- Problem
- Solution
- What have we learned
- My Singleton stores Context
- Problem
- Solution
- What have we learned
- I want to use my singleton in Activity and Remote Service
- Solution
- I have immutable singleton
- Problem
- Solution
- How we can create proper Singletons
- Afterwords
- P.S.: Links
Android Design Patterns: The Singleton Pattern
What Is the Singleton Pattern?
The Singleton Pattern is a software design pattern that guarantees a class has one instance only and a global point of access to it is provided by that class. Anytime multiple classes or clients request for that class, they get the same instance of the class. This Singleton class may be responsible for instantiating itself, or you can delegate the object creation to a factory class.
Let’s use the example of a cellphone and its owner. A phone is typically owned by a single person, while a person can own many phones. Anytime one of these phones rings, the same owner picks it up.
Benefits of the Singleton Pattern
In a typical Android app, there are many objects for which we only need one global instance, whether you are using it directly or simply passing it to another class. Examples include caches, OkHttpClient , HttpLoggingInterceptor , Retrofit , Gson , SharedPreferences , the repository class, etc. If we were to instantiate more than one of these types of objects, we’d run into problems like incorrect app behaviour, resource overuse, and other confusing results.
Implementation
It’s quite easy to implement this pattern. The following code snippet shows how a Singleton is created.
In the code above, we have a static variable INSTANCE to hold an instance of the class. We also made the constructor private because we want to enforce noninstantiability—the class can only instantiate itself. The method getInstance() guarantees that the class is instantiated, if it has not been, and that it’s returned to the caller.
Example: Creating a Single Instance of Retrofit
Retrofit is a popular library to connect a REST web service by translating the API into Java interfaces. To learn more about it, check out my tutorial here on Envato Tuts+.
In an Android app, you’ll need a single global instance of a Retrofit object so that other parts of an app such as a UserProfileActivity or SettingsActivity can use it to execute a network request without the need to create an instance every single time we need it. Creating multiple instances would pollute our app with unused retrofit objects, thereby occupying unnecessary memory on an already memory-constrained mobile device.
So anytime client A calls RetrofitClient.getClient() , it creates the instance if it has not been created already, and then when client B calls this method, it checks if the Retrofit instance already exists. If so, it returns the instance to client B instead of creating a new one.
Dealing With Multithreading
In the Android system, you can spin off multiple threads to perform different tasks. These threads can end up executing the same code block simultaneously. In the case of the Singleton class above, this could lead to the creation of multiple object instances, which violates the contract of a Singleton. So our Singleton code snippet method getInstance() is not thread safe. We’ll now look at ways to make it thread safe.
Synchronize the getInstance() Method
One of the ways to make the singleton code thread safe is by making the method getInstance() a synchronized one. Doing this only allows one thread to run the method at a time, forcing every other thread to be in a wait or blocked state.
This approach makes our code thread safe, but it is an expensive operation. In other words, this can slow down performance. So you have to investigate and see if the performance cost is worthwhile in your application.
Eagerly Create an Instance
Another approach to deal with multiple threads accessing the singleton is to create the Singleton instance immediately when the class is loaded or initialized (by the Android ClassLoader in the Dalvik VM). This makes the code thread safe. Then the object instance will already be available before any thread accesses the INSTANCE variable.
A drawback to this approach is that you can end up creating an object that might never be used, thereby occupying unnecessary memory. So this approach should typically only be used if you are sure that the singleton will be accessed.
Bonus: Using Dagger 2
A dependency injection library such as Dagger can help you wire up your object dependencies and create singletons by using the @Singleton annotation. This will ensure that the object is only initialized once throughout the application lifecycle.
In the code above, we create a single instance of Gson , Cache , File , OkHttpClient and finally Retrofit types to be provided from the dependency graph generated by Dagger.
To learn more about Dagger 2, check out our tutorial here on Envato Tuts+.
Conclusion
In this short tutorial, you learned about the Singleton pattern in Android: what it is, the benefits of using it, how to implement it by writing your own, and some ways of dealing with multiple threads. I also showed you how to use a third-party library such as Dagger 2.
In the meantime, check out some of our other courses and tutorials on the Java language and Android app development!
Источник
Шаблоны дизайна Android: шаблон Singleton
Что такое шаблон синглтона?
Шаблон Singleton — это шаблон разработки программного обеспечения, который гарантирует, что у класса есть только один экземпляр, и этот класс обеспечивает глобальную точку доступа к нему. Каждый раз, когда несколько классов или клиентов запрашивают этот класс, они получают один и тот же экземпляр класса. Этот класс Singleton может отвечать за создание его экземпляра, или вы можете делегировать создание объекта классу фабрики.
Давайте использовать пример мобильного телефона и его владельца. Телефон обычно принадлежит одному человеку, в то время как человек может иметь много телефонов. Каждый раз, когда один из этих телефонов звонит, тот же владелец поднимает его.
Преимущества шаблона Singleton
В типичном приложении для Android есть много объектов, для которых нам нужен только один глобальный экземпляр, независимо от того, используете ли вы его напрямую или просто передаете его другому классу. Примеры включают в себя кэши, OkHttpClient , HttpLoggingInterceptor , Retrofit , Gson , SharedPreferences , класс репозитория и т. Д. Если бы нам пришлось создавать экземпляры более чем одного из этих типов объектов, мы столкнулись бы с такими проблемами, как некорректное поведение приложения, чрезмерное использование ресурсов и другие сбивающие с толку результаты.
Реализация
Это довольно легко реализовать этот шаблон. Следующий фрагмент кода показывает, как создается Singleton.
Источник
Singletons in Android
Avoid them or at least think twice before use them
Jul 22, 2016 · 11 min read
There are a lot of articles and posts about Singleton Pattern. In fact there are many articles about how bad Singleton Pattern can be and how especially it can be harmful in Android. Here a bunch of them, here, here, here, here and here.
But every post concerns only about some small specific p r oblem. Some of them about memory leaking, some of them about loosing a state, some of them about multiprocessing. But I didn’t find an article, that covered all topics. And I will try to touch all of topics, or at least most of them, most of needed to understand, that Singletons are evil, and especial in Android (at least you need to choose them wisely and provide some mechanism to keep their states and e.t.c.).
Also I do my best to improve my knowledges and skills in programming, in Java, in Android. So I think this article will be useful not only for you, but for me, too.
So, what if I have simple Singleton
Let’s look at this code:
Except ‘lazy initialisation’ and ‘multithreading’ this code has two main problems:
- We have published state of singleton that can be changed everywhere. It’s not an Android problem, it’s an architectural problem. Of course we can say: “We know, where to set value”, “There are only couple places and e.t.c”. But still the fact is that such Singleton provides a global variable. And moreover you can not create second or third instance. There is only one instance.
- For android there is more dangerous problem with stateful mutable Singleton. Losing state. If your singleton provides some state that can be changed in your application, then you can easily losing state.
Let’s provide some simple application that uses our Singleton. Here layout for activity:
Yeap, that’s all. Now we can run our application. And we will see 0 in center of screen. Then we click on the button and see 5 in center. We can rotate an application, for example, or press Home button and then on application icon. And everything will be normal. We will still have 5 on center of the screen. But if we run bunch of other apps: play some games, write couple of emails and e.t.c, and then go back to our application we will se 0 instead of 5. What? What happened?
Problem
During our usage of phone, system was needed more memory and it saw that our application was not used for a while. So it killed it. And then when we went back to our app, system recreated it, restoring some state. Of course our singleton was not saved and restored, because it’s naive and didn’t know that can be killed.
Solution
There is no so obvious solution as it seems, because such simple singleton can be changed everywhere. In every Activity, in every Fragment, in services — everywhere within its process. Of course, all that we know exactly is that we need to provide some saving mechanism. There are two fast solutions that can come to mind, but both of them are not perfect. In defense, I would say, that using such singleton is not perfect solution of some architect problem.
First variant. We can create saveState(Bundle outState)/restoreState(Bundle state) similarly to onSaveInstanceState(Bundle outState)/onRestoreInstanceState(Bundle outState) for our Singleton and then call them wherever we want.
But this approach has huge flaw. You need to decide where to save state. In fact, you can choose only between activities, views and fragments. For example, if you changed state of Singleton in activity, then close it, but you have background service that changed state one more time, then app was killed and restarted by the system, you will lose last updating, that was made by service. And of course most likely you will have to call these functions (saveState, restoreState) from all Activities, Views and Fragments which somehow (directly or not) affects to state of Singleton, which produces a lot of boilerplate code.
Small improvement of this solution: provide not bundle but anything that might store state of your Singleton. For example, it might be SharedPreferences, Stream or maybe your own Class/Interface. Moreover, you can make those methods parameterless, so your Singleton will be implement it’s own saving mechanism. Thus, you will able to call save/restore methods from everywhere, but as I said it can turn out a huge boilerplate, if your singleton managed from many places.
Second variant. Singleton can provide its own saving mechanism and call ‘save’ methods inside setState, giving to us a possibility of “auto” saving. Also in Singleton’s initialization ‘restore’ method will be called, giving to us “auto” restoring mechanism.
Unlike previous variant, this one frees us from writing a lot of extra code. But it have shortcoming of permanent saving any setting state. For example, if you will have loop that iteratively sets new state, then every time save mechanism will be invoked. And it can be harmful for performance.
You can combine these two variant, giving to client opportunity to disable auto save when it will frequently sets new states and enable it later.
What have we learned
Above example shows that naive stateful mutable singleton can be a mess, if you not handle it properly. You need to always think, when you actually need to change it state to avoid many “entry points”. If you care about state of singleton, you need always think, where you need to save it and how.
My Singleton stores Context
Let’s look at the code:
“So what’s the problem in this code?” you will say, “this singleton has immutable instance, there is no problems with state and e.t.c, what is wrong with you man?”
Let’s omit problems with multithreading. We initializing our singleton in launch activity, for example through ContextSingleton.init(this), then work with our activity, then go to second activity, third, fourth and get’s OutOfMemoryException. What’s wrong?
Problem
In Android there are class called Context. It’s required, when you need to get access to services, resources or internal files in your application. It is used for creating views and launching another Activities. So it might seem that Context would be very helpful in your singleton object, because you can do a lot of stuff with it and thus encapsulate many things in your singleton.
But it is an illusion. Of course there are a lot of libraries that provides singletons or single instances that keeps Context reference, but it is application context, not some ‘local’ context.
Yes, there are Application context and, for example, Activity context. They both are instances of Context class, but first attached to application lifecycle and second to activity lifecycle. First will be destroyed, when app will be killed, second, when activity will be killed.
Now, as we remember our singleton lives all across application. So it will be destroyed when application will be destroyed. Thus when we pass, for example, activity context in singleton and then run another activity and then kill application, then everything will be all right, but if second activity will require a lot of memory, for example, then system will decide to kill first activity, but it will fail, since there are reference to it in our singleton, and we receive OutOfMemoryExeption. It is unpleasant to be honest.
Solution
In short. Do not pass any context except app context in your singleton. Please. For more sequrity change initialization code little bit:
In details. You can pass activity context if you want, but you need to be aware all the time, you need to clear reference when you stop working with your activity, replace it with another reference, when you start new activity. So it can be huge headache. I highly recommend to not pass any context in your singleton, but, if you still want to do it, please, pass only application context. And if you are 100% sure that you need to pass some ‘local’ context in your singleton (for example, you need to create an mechanism of processing bitmaps in background and displaying them in attached views), think about ‘release context reference’ mechanism. For example, you can use WeakPreference of your context objects, so system will be able to destroy them, during garbage collecting.
What have we learned
Think twice if you want to store context in your singleton. You need to be sure that using the context will be justified. And if you will use some ‘local’ context, provide mechanism for releasing its reference to allow garbage collector mark this object as unused and collect it, otherwise you might face with memory leaks in your app.
I want to use my singleton in Activity and Remote Service
Then I have bad news for you. You can not do it. The reason is simple: your activities, fragments and other ui components are placed in application process and your Remote Service placed in remote process. And those processes are different. And there is only one way you can interact with them. It’s AIDL.
If, for example, for activities and local services you can make global static state and share it between them (which is bad, but also what singleton often actually does), then for activity and remote service you can not do such thing, because each process has own class loader.
Actually in our case we will have two instances of singleton. One in process of application and one in remote process.
Solution
If you want to use singleton that share some state through processes then, please, remove this singleton. Consider to use AIDL, broadcasts, intents. Remember, there are no singletons in multiprocessing app, only in single process. So if you have, for example, remote process and singleton in your app, make sure that this singleton be used only in one of the processes.
I have immutable singleton
As for me Immutable Singletons (with some restrictions) are one of the options to build proper single instances in android, because you know that your instance sets up only once, during creation phase and then not changing. So it’s more easily to keep it around, even through app restarting.
Although, it could be good solution of some problem, it can be a mess, if you for example create Immutable Singleton passing local context to it and not provide any mechanism to release it, as I said earlier.
One of good usings of Immutable Singletons is to use so-called ‘extension’ of Singleton named Enumeration. Enums have some restrict, predefined number of instances, as for Singleton. But unlike Singleton there can be 2, 3, 10 instances of some class. One of good examples of enums, is to use them as typed constants. For example:
Instead of defining string constants like that, we can define them like this:
This approach will give you typed constants and, thus, prevent you from checking their validity in places where you will use them.
Problem
Actually there is no such big performance or memory problem. But there is an architectural problem. If you have in application immutable singleton then you need to think do you actually need it.
Solution
There are three types of immutable singletons that could came to mind right now:
- Singletons without state but with pack of functions. So you have singleton that have only functionality, but not state. So in code you have something like ‘ Something.INSTANCE.computeSomething(SomethingOther other)’. In this case, first, you need to think about replacing singleton with ‘Utility’ class. It’s a class with private empty constructor and only static methods. So invocation will be look like ‘ SomeUtil.computeSomething(SomethingOther other)’, which reduce redundant INSTANCE word. Second, if SomethingOther class is not library class, but your class, consider to move ‘computeSomething’ method to it, so invocation will be look like: ‘ other.computeSomething()’.
- Singletons with initial state (not context) and pack of functions. As for previous point you need to provide Utility class with initial state in private constructor and static methods.
- Singletons with application context state and pack of functions. These singletons often appears from libraries, which are want to interact with app somehow. If you want to use something similar in your application. Consider to create not singleton, but class with constructor that has application context as parameter and invoke it in application’s onCreate callback, then store it in static field of Application class and provide static getter for accessing to it.
Third point leads us to the next section.
How we can create proper Singletons
The answer permeates the entire article. Don’t use singletons.
- They provide global state, which is not OOP solution
- They can lose their state
- They can leak your context
- They hard to test (you alway need to clear or restore init state for stateful singletons)
- They are not actually singletons in multiprocessing apps
- They can be executed everywhere and it can lead to reducing maintainability
- In multithreading apps they can change state from any thread and this can lead to unexpected results
- They can not be extended
For now I don’t use singletons. If I need to provide a global state I create a single instance of some class, and single instance concept differs from singleton. Single instance is created to provide some global state (which is bad in OOP generally, but is normal in android), but you can still create multiple instances of your class. This gives us possibility to properly test our class, or create local instances for doing some small specific work, or to extend them with new logic.
So to create global instance of our class we need to extend application class and add initialisation of our class in onCreate method. Then we need to provide static getter for our global instance.
Then we can invoke anywhere in code ‘ getSomething()’ and work with our global instance.
Afterwords
Singletons are bad and you should avoid them. Especially in Android. But if you really need global state, write your class properly and create global instances through application creation phase.
P.S.: Links
If you liked article there are other by me about improve working with permissions, saving states and refactoring base fragment.
Источник