'Android memory usage keeps increasing while using app
I have developed a compose app which retrieves crypto data (a list of 1063 objects) from Socket each 3 seconds. While using app I recognized that after some time working with app it crashes with Out of memory. I profiled my app (release version) and recognized that while using app java code increase until it crashes with OOM error.
Let me show you some code for better understanding. For socket, I created a SocketManager class which instantiates on app startup via Dagger Hilt in singleton component.
class SocketManager @Inject constructor(
socket: Socket,
private val json: Json
) {
var cryptoFlow = MutableStateFlow<List<CryptoDataSetItemDto>>(emptyList())
init {
socket.connect()
socket.on("crypto_data") {
it.forEach { data ->
try {
val coinList =
json.decodeFromString<List<CryptoDataSetItemDto>>(data.toString())
cryptoFlow.tryEmit(coinList)
} catch (e: Exception) {
Sentry.captureException(e)
}
}
}
}
}
@Module
@InstallIn(SingletonComponent::class)
object SocketModule {
@Provides
@Singleton
fun provideJson(): Json {
return Json {
encodeDefaults = true
ignoreUnknownKeys = true
}
}
@Provides
@Singleton
fun provideSocket(client: OkHttpClient): Socket {
val socket: Socket
val opts = IO.Options()
opts.path = Constants.SOCKET_PATH
opts.secure = true
socket = IO.socket(Constants.SOCKET_BASE_URL, opts)
return socket
}
@Provides
@Singleton
fun provideSocketManager(socket: Socket, json: Json): SocketManager {
return SocketManager(socket, json)
}
}
Then I inject SocketManager to viewModel to get data on the screens I need those data. I create a function which gets a coroutine context from composable and collects data in that scope.
@HiltViewModel
class WithdrawDepositViewModel @Inject constructor(
private val useCase: WalletUseCases,
private val socketManager: SocketManager,
savedStateHandle: SavedStateHandle
) : ViewModel() {
fun getCoinData(context: CoroutineContext) {
CoroutineScope(context).launch(Dispatchers.Default) {
socketManager.cryptoFlow.asStateFlow()
.shareIn(CoroutineScope(context), SharingStarted.WhileSubscribed())
.collectLatest { cryptoListDto ->
val cryptoList = cryptoListDto.map { it.toCryptoList() }.toMutableList()
val irt = CryptoDataItem(
enName = "Toman",
faName = "تومان",
symbol = "IRT"
)
cryptoList.add(0, irt)
_state.value = state.value.copy(
cryptoList = cryptoList,
isLoading = false
)
}
}
}
and in screen I call the function like this:
@Composable
fun HomeScreen(
onNavigate: (String) -> Unit,
scaffoldState: ScaffoldState,
viewModel: HomeScreenViewModel = hiltViewModel()
) {
val scope = rememberCoroutineScope()
val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(key1 = lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_CREATE) {
viewModel.getCryptoData(scope.coroutineContext)
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
}
This is my architecture to get data. when looked at heap dump result, I recognized that CryptoDataSetItemDto object which I get it on socket, has allocated lots of memory. I can not find the problem also I know that there is better architecture which I hope to learn from you.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|

