1

This is mostly an app architecture question. I have a repository class that centralizes operations on collections of media:

interface MediaRepository {
    suspend fun getTracks(): List<Track>
    suspend fun getAlbums(): List<Album>
    fun observeMediaChanges(): Flow<ChangeNotification>
}

This repository pulls from multiple DAOs sources that expose their data as Flow to observe for changes like the following:

interface MediaDao {
    fun getTracks(): Flow<List<Track>>
    fun getAlbums(): Flow<List<Album>>
}

Therefore, the implementation of MediaRepository is stateful: it lazily observes changes to the Flows from the first time the equivalent getX function is called, caches the latest received value whenever received then compute and broadcasts a ChangeNotification to observers of observeMediaChanges().

This structure worked well when the Repository was only injected into a Service, because the repository resources could be cleaned-up when the service terminated. I now need to inject the same MediaRepository into an instance of Worker. Since workers have their own lifecycle, I need to make the MediaRepository a singleton.

The problem

by keeping active subscriptions for the whole lifetime of the application, am I leaking valuable resources (for example, one DAO internally uses ContentObservers) ? How can I change my app architecture to avoid leaks ?

What I thought of

  1. Make MediaRepository stateless and expose media lists as Flows. It is then the consumer's reponsibility to cache the latest value.
  2. Keep the cache in MediaRepository, but do not share instances between the service and the worker.
  3. Do not use a cache at all, since most data are read from the device's storage.
Thibault Seisel
  • 1,197
  • 11
  • 23

1 Answers1

0

I suppose you have already a dagger component declared.

You only mark the provided MediaRepository implementation with @Singleton.

@Singleton
class MediaRepositoryImpl @Inject constructor(...)

And in a module bind this instance to its interface

@Binds fun bindsMediaRepository(impl: MediaRepositoryImpl): MediaRepository

To give additional parameters to a Worker you have to instantiate a custom WorkManagerFactory in your application.

This medium post explains the full process step by step very detailed.

Take also a look to the official documentation

crgarridos
  • 8,758
  • 3
  • 49
  • 61
  • Thanks for your answer. I've had a rather a rather precise idea of how to setup those factories. The problem I have is that exposing my repository as a singleton has a high risk of leaking memory because it is stateful. I'm looking for a way to structure my application to avoid that – Thibault Seisel Jan 06 '20 at 08:03
  • Then as EpicPandaForce point out, this should not be `@Singleton`. Anyway if you are forced to, you can reuse a current created instance marking it as `@Reusable` instead, This way dagger will free the instance if any consumer is not longer pointing to it. – crgarridos Jan 06 '20 at 09:46