Dependency Injection w Androidzie

Aby ułatwić pisanie aplikacji postanowiłem spróbować znaleźć i użyć framework do Dependency Injection.

Po szybkich poszukiwaniach natrafiłem na framework Dagger. Framework ten jest przystosowany do użycia go w aplikacjach mobilnych. Dagger działa inaczej niż większość frameworków DI, które działają na refleksjach. Dagger tworzy klasy, które będzie wstrzykiwał, na etapie kompilacji. Podejście to tworzy pewne ograniczenia, lecz jest szybsze i mniej pamięciożerne, co jest zdecydowanie przydatne w przypadku aplikacji mobilnych.

Po tym wyborze przystąpiłem do konfiguracji frameworka, lecz naszła mnie pewna myśl… Moja aplikacja będzie dosyć prosta. Czy faktycznie potrzebuję frameworka DI? Po chwili namysłu stwierdziłem, że samodzielnie stworzę coś na wzór frameworka DI. Oczywiście prostszego i bardziej ubogiego ale mam nadzieję, że wystarczającego 🙂

Podszedłem do tego w następujący sposób:

  1. Stworzyłem w Javie klasę dziedziczącą po klasie Application, ze statycznym dostępem do contextu.
    public class ApplicationContext extends Application {
    
        private static Context context;
    
        public void onCreate() {
            super.onCreate();
            context = getApplicationContext();
        }
    
        public static Context getAppContext() {
            return context;
        }
    }

    W Scali nie są dostępne metody statyczne w klasach, a Object Scalowy nie mógłby być zainicjalizowany przez system. W związku z tym byłem zmuszony stworzyć powyższą klasę Javową, aby zyskać dostęp do kontekstu aplikacji.

  2. Dodałem odniesienie do powyższej klasy w pliku AndroidMnifest.xml w atrybucie android:name dla tagu application. Wygląda to mniej więcej tak:
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="pl.lantkowiak.sdm">
    
        ...
    
        <application
            ...
            android:name="pl.lantkowiak.sdm.di.ApplicationContext">
            ...
        </application>
    </manifest>
  3. Stworzyłem obiekt, w którym tworzone są instancje, które będą 'wstrzykniętę’ oraz metodę służącą do pobrania tych instancji.
    object ApplicationModule {
      private val instances = collection.mutable.Map[Class[_], Any]()
    
      {
        instances.put(classOf[DocumentDao], documentDAO())
      }
    
      def wire[T](clazz: Class[T]): T = {
        instances.get(clazz).asInstanceOf[Some[T]].get
      }
    
      private def documentDAO(): DocumentDao = {
        new DocumentDaoBean(ApplicationContext.getAppContext)
      }
    }

    Obiekt zawiera w sobie mapę, która zawiera mapowanie klasy na jej instancje. Mapa ta jest uzupełniania w bloku inizjalizującym – tutaj będę musiał dodać wszystkie klasy wraz z instancjami, do których będę chciał mieć dostęp w ten sposób.
    Metoda wire pobiera instancje z mapy oraz ją zwraca.

  4. Samo 'wstrzyknięcię’ robimy w poniższy sposób:
    private lazy val documentDao = wire(classOf[DocumentDao])

    Oczywiście powyższe podejscie będzię wstrzykiwać zawsze tą samą instancje, lecz na potrzeby mojej aplikacji powinno być to całkowicie wystarczające.

← Previous post

Next post →

1 Comment

  1. Mechanik Samochodowy

    Nie rozumiem za bardzo tego, ciężki temat

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *