Статьи

Шаблоны дизайна Android: шаблон 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 SDK
    Отправка данных с помощью HTTP-клиента Retrofit 2 для Android

В приложении 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() 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, может помочь вам @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 +.

  • Android SDK
    Внедрение зависимостей с помощью Dagger 2 на Android
    Керри Перес Уанка

В этом коротком руководстве вы узнали о шаблоне 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 на естественном языке
    Ашраф Хатхибелагал