Что такое шаблон синглтона?
Шаблон Singleton — это шаблон разработки программного обеспечения, который гарантирует, что у класса есть только один экземпляр, и этот класс обеспечивает глобальную точку доступа к нему. Каждый раз, когда несколько классов или клиентов запрашивают этот класс, они получают один и тот же экземпляр класса. Этот класс Singleton может отвечать за создание его экземпляра, или вы можете делегировать создание объекта классу фабрики.
Давайте использовать пример мобильного телефона и его владельца. Телефон обычно принадлежит одному человеку, в то время как человек может иметь много телефонов. Каждый раз, когда один из этих телефонов звонит, тот же владелец поднимает его.
Преимущества шаблона Singleton
В типичном приложении для Android есть много объектов, для которых нам нужен только один глобальный экземпляр, независимо от того, используете ли вы его напрямую или просто передаете его другому классу. Примеры включают в себя кэши, OkHttpClient
, HttpLoggingInterceptor
, Retrofit
, Gson
, SharedPreferences
, класс репозитория и т. Д. Если бы нам пришлось создавать экземпляры более чем одного из этих типов объектов, мы столкнулись бы с такими проблемами, как некорректное поведение приложения, чрезмерное использование ресурсов и другие сбивающие с толку результаты.
Реализация
Это довольно легко реализовать этот шаблон. Следующий фрагмент кода показывает, как создается Singleton.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
public class Singleton {
private static Singleton INSTANCE = null;
// other instance variables can be here
private Singleton() {};
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return(INSTANCE);
}
// other instance methods can follow
}
|
В приведенном выше коде у нас есть статическая переменная INSTANCE
для хранения экземпляра класса. Мы также сделали конструктор закрытым, потому что мы хотим реализовать неинстансируемость — класс может создавать только сам экземпляр. Метод getInstance()
гарантирует, что экземпляр класса будет создан, если он не был, и что он будет возвращен вызывающей стороне.
Пример: создание отдельного экземпляра дооснащения
Retrofit — это популярная библиотека для подключения веб-службы REST путем перевода API в интерфейсы Java. Чтобы узнать больше об этом, ознакомьтесь с моим руководством на Envato Tuts +.
В приложении Android вам понадобится один глобальный экземпляр объекта Retrofit, чтобы другие части приложения, такие как UserProfileActivity
или SettingsActivity
могли использовать его для выполнения сетевого запроса без необходимости создавать экземпляр каждый раз, когда нам нужно Это. Создание нескольких экземпляров приведет к загрязнению нашего приложения неиспользуемыми объектами дооснащения, что займет ненужную память на мобильном устройстве, уже имеющем ограниченную память.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl) {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
|
Поэтому каждый раз, когда клиент A вызывает RetrofitClient.getClient()
, он создает экземпляр, если он еще не был создан, а затем, когда клиент B вызывает этот метод, он проверяет, существует ли экземпляр Retrofit. Если это так, он возвращает экземпляр клиенту B вместо создания нового.
Работа с многопоточностью
В системе Android вы можете раскрутить несколько потоков для выполнения разных задач. Эти потоки могут выполнять один и тот же кодовый блок одновременно. В случае с классом Singleton
выше это может привести к созданию нескольких экземпляров объекта, что нарушает контракт Singleton. Поэтому наш метод сниппета getInstance()
Singleton getInstance()
не является поточно-ориентированным. Теперь мы рассмотрим способы сделать его потокобезопасным.
Синхронизировать метод getInstance()
Один из способов сделать поток одноэлементного кода безопасным — сделать метод getInstance()
a синхронизированный Выполнение этого позволяет только одному потоку запускать метод за раз, заставляя каждый другой поток находиться в состоянии ожидания или заблокирован.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
public class Singleton {
private static Singleton INSTANCE = null;
// other instance variables can be here
private Singleton() {};
public static synchronized Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return(INSTANCE);
}
// other instance methods can follow
}
|
Такой подход делает наш поток кода безопасным, но это дорогостоящая операция. Другими словами, это может снизить производительность. Таким образом, вы должны исследовать и посмотреть, стоит ли затраты производительности в вашем приложении.
С готовностью создайте экземпляр
Другой подход к работе с несколькими потоками, обращающимися к синглтону, заключается в создании экземпляра Singleton сразу после загрузки или инициализации класса (с помощью загрузчика классов Android в ВМ Dalvik). Это делает поток кода безопасным. Тогда экземпляр объекта будет доступен до того, как какой-либо поток INSTANCE
доступ к переменной INSTANCE
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
public class Singleton {
private static Singleton INSTANCE = new Singleton();
// other instance variables can be here
private Singleton() {};
public static Singleton getInstance() {
return(INSTANCE);
}
// other instance methods can follow
}
|
Недостатком этого подхода является то, что вы можете в конечном итоге создать объект, который никогда не будет использоваться, занимая тем самым ненужную память. Поэтому этот подход обычно следует использовать только в том случае, если вы уверены, что к синглтону будет доступ.
Бонус: использование Dagger 2
Библиотека внедрения зависимостей, такая как Dagger, может помочь вам @Singleton
ваши объектные зависимости и создать синглтоны с помощью аннотации @Singleton
. Это обеспечит инициализацию объекта только один раз в течение жизненного цикла приложения.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
@Module
public class NetworkModule {
@Provides
@Singleton
public Gson gson() {
GsonBuilder gsonBuilder = new GsonBuilder();
return gsonBuilder.create();
}
@Provides
@Singleton
public HttpLoggingInterceptor loggingInterceptor() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(
message -> Timber.i(message));
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return interceptor;
}
@Provides
@Singleton
public Cache cache(File cacheFile) {
return new Cache(cacheFile, 10 * 1000 * 1000);
}
@Provides
@Singleton
public File cacheFile(@ApplicationContext Context context) {
return new File(context.getCacheDir(), «okhttp_cache»);
}
@Provides
@Singleton
public OkHttpClient okHttpClient(HttpLoggingInterceptor loggingInterceptor, Cache cache) {
return new OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.cache(cache)
.build();
}
@Provides
@Singleton
public Retrofit retrofit(OkHttpClient okHttpClient, Gson gson) {
return new Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.client(okHttpClient)
.baseUrl(«you/base/url»)
.build();
}
}
|
В приведенном выше коде мы создаем один экземпляр типов Gson
, Cache
, File
, OkHttpClient
и, наконец, Retrofit
, предоставляемый из графика зависимостей, сгенерированного Dagger.
Чтобы узнать больше о Dagger 2, ознакомьтесь с нашим руководством по Envato Tuts +.
Вывод
В этом коротком руководстве вы узнали о шаблоне Singleton в Android: что это такое, о преимуществах его использования, о том, как реализовать его, написав свой собственный, и о некоторых способах работы с несколькими потоками. Я также показал вам, как использовать стороннюю библиотеку, такую как Dagger 2.
А пока ознакомьтесь с другими нашими курсами и руководствами по языку Java и разработке приложений для Android!
-
Android SDKПриложения RxJava 2 для Android: RxBinding и RxLifecycle
-
Android SDKПрактический параллелизм на Android с HaMeR
-
AndroidОбеспечение высокого качества кода Android с помощью инструментов статического анализа
-
Android SDKСоздайте интеллектуальное приложение с Google Cloud Speech и API на естественном языке