Skip to content
This repository has been archived by the owner on Mar 15, 2022. It is now read-only.

Commit

Permalink
Merge pull request #724 from NotWoods/viewmodel-no-leak
Browse files Browse the repository at this point in the history
Remove HomeViewModel memory leak
  • Loading branch information
X1nto committed Oct 25, 2021
2 parents 25f8f80 + 368808d commit eb28c61
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,12 @@ class ExpandableAppListAdapter(
appDownload.apply {
setOnClickListener {
viewModel.openInstallDialog(
activity.supportFragmentManager,
buttonTag,
apps[position]
)
}
appDownload.setIconResource(buttonTag.image)
contentDescription = activity.getString(
when (buttonTag) {
ButtonTag.UPDATE -> R.string.accessibility_update
Expand All @@ -108,11 +110,6 @@ class ExpandableAppListAdapter(
dataModel?.installedVersionName?.observe(activity) {
appVersionInstalled.text = it
}
dataModel?.buttonImage?.observe(activity) {
if (it != null) {
appDownload.icon = it
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class LinkAdapter(

fun bind(position: Int) {
binding.linkBg.setOnClickListener {
viewModel.openUrl(links[position].linkUrl)
viewModel.openUrl(context, links[position].linkUrl)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class SponsorAdapter(
with(binding) {
sponsorName.text = sponsors[position].name
cardSponsor.setOnClickListener {
viewModel.openUrl(sponsors[position].url)
viewModel.openUrl(context, sponsors[position].url)
}
}
}
Expand Down
37 changes: 37 additions & 0 deletions app/src/main/java/com/vanced/manager/core/CombinedLiveData.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.vanced.manager.core

import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData

/**
* CombinedLiveData is a helper class to combine results from two LiveData sources.
* @param combine Function reference that will be used to combine all LiveData data.
* @param R The type of data returned after combining all LiveData data.
* Usage:
* CombinedLiveData(
* getLiveData1(),
* getLiveData2()
* ) { data1, data2 ->
* // Use datas[0], datas[1], ..., datas[N] to return a value
* }
*/
class CombinedLiveData<R, A, B>(
liveDataA: LiveData<A>,
liveDataB: LiveData<B>,
private val combine: (a: A?, b: B?) -> R
) : MediatorLiveData<R>() {

private var a: A? = null
private var b: B? = null

init {
addSource(liveDataA) {
a = it
value = combine(a, b)
}
addSource(liveDataB) {
b = it
value = combine(a, b)
}
}
}
9 changes: 7 additions & 2 deletions app/src/main/java/com/vanced/manager/model/ButtonTag.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package com.vanced.manager.model

enum class ButtonTag {
INSTALL, UPDATE, REINSTALL
import androidx.annotation.DrawableRes
import com.vanced.manager.R

enum class ButtonTag(@DrawableRes val image: Int) {
INSTALL(R.drawable.ic_app_download),
UPDATE(R.drawable.ic_app_update),
REINSTALL(R.drawable.ic_app_reinstall)
}
75 changes: 23 additions & 52 deletions app/src/main/java/com/vanced/manager/model/DataModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,46 @@ import android.graphics.drawable.Drawable
import android.os.Build
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.*
import com.beust.klaxon.JsonObject
import com.vanced.manager.R
import com.vanced.manager.core.CombinedLiveData
import com.vanced.manager.utils.PackageHelper.isPackageInstalled

open class DataModel(
private val jsonObject: LiveData<JsonObject?>,
private val context: Context,
lifecycleOwner: LifecycleOwner,
jsonObject: LiveData<JsonObject?>,
context: Context,
val appPkg: String,
val appName: String,
val appDescription: String,
@DrawableRes val appIcon: Int
) {

private val versionCode = MutableLiveData<Int>()
private val installedVersionCode = MutableLiveData<Int>()
val isAppInstalled = Transformations.map(jsonObject) { isAppInstalled(appPkg) }

private val versionCode = Transformations.map(jsonObject) { jobj ->
jobj?.int("versionCode") ?: 0
}
private val installedVersionCode = Transformations.map(isAppInstalled) {
getPkgVersionCode(appPkg, it)
}
private val unavailable = context.getString(R.string.unavailable)
private val pm = context.packageManager

val isAppInstalled = MutableLiveData<Boolean>()
val versionName = MutableLiveData<String>()
val installedVersionName = MutableLiveData<String>()
val buttonTag = MutableLiveData<ButtonTag>()
val buttonImage = MutableLiveData<Drawable>()
val changelog = MutableLiveData<String>()

private fun fetch() {
val jobj = jsonObject.value
isAppInstalled.value = isAppInstalled(appPkg)
versionCode.value = jobj?.int("versionCode") ?: 0
versionName.value = jobj?.string("version") ?: unavailable
changelog.value = jobj?.string("changelog") ?: unavailable
val versionName = Transformations.map(jsonObject) { jobj ->
jobj?.string("version") ?: unavailable
}

init {
fetch()
with(lifecycleOwner) {
jsonObject.observe(this) {
fetch()
}
isAppInstalled.observe(this) {
installedVersionCode.value = getPkgVersionCode(appPkg, it)
installedVersionName.value = getPkgVersionName(appPkg, it)
}
versionCode.observe(this) { versionCode ->
installedVersionCode.observe(this) { installedVersionCode ->
buttonTag.value = compareInt(installedVersionCode, versionCode)
buttonImage.value = compareIntDrawable(installedVersionCode, versionCode)
}
}
}
val changelog = Transformations.map(jsonObject) { jobj ->
jobj?.string("changelog") ?: unavailable
}
val installedVersionName = Transformations.map(isAppInstalled) {
getPkgVersionName(appPkg, it)
}
val buttonTag = CombinedLiveData(versionCode, installedVersionCode) { versionCode, installedVersionCode ->
compareInt(installedVersionCode, versionCode)
}

open fun isAppInstalled(pkg: String): Boolean = isPackageInstalled(pkg, context.packageManager)
open fun isAppInstalled(pkg: String): Boolean = isPackageInstalled(pkg, pm)

private fun getPkgVersionName(pkg: String, isAppInstalled: Boolean): String {
return if (isAppInstalled) {
Expand Down Expand Up @@ -95,16 +78,4 @@ open class DataModel(
}
return ButtonTag.INSTALL
}

private fun compareIntDrawable(int1: Int?, int2: Int?): Drawable {
if (int2 != null && int1 != null) {
return when {
int1 == 0 -> ContextCompat.getDrawable(context, R.drawable.ic_app_download)!!
int2 > int1 -> ContextCompat.getDrawable(context, R.drawable.ic_app_update)!!
int1 >= int2 -> ContextCompat.getDrawable(context, R.drawable.ic_app_reinstall)!!
else -> ContextCompat.getDrawable(context, R.drawable.ic_app_download)!!
}
}
return ContextCompat.getDrawable(context, R.drawable.ic_app_download)!!
}
}
3 changes: 1 addition & 2 deletions app/src/main/java/com/vanced/manager/model/RootDataModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import com.vanced.manager.utils.PackageHelper
class RootDataModel(
jsonObject: LiveData<JsonObject?>,
context: Context,
lifecycleOwner: LifecycleOwner,
appPkg: String,
appName: String,
appDescription: String,
Expand All @@ -22,7 +21,7 @@ class RootDataModel(
//Ironic, isn't it?
private val scriptName: String?
) : DataModel(
jsonObject, context, lifecycleOwner, appPkg, appName, appDescription, appIcon
jsonObject, context, appPkg, appName, appDescription, appIcon
) {

override fun isAppInstalled(pkg: String): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import com.vanced.manager.databinding.FragmentHomeBinding
import com.vanced.manager.ui.dialogs.AppInfoDialog
import com.vanced.manager.ui.dialogs.DialogContainer.installAlertBuilder
import com.vanced.manager.ui.viewmodels.HomeViewModel
import com.vanced.manager.ui.viewmodels.HomeViewModelFactory
import com.vanced.manager.utils.isFetching
import com.vanced.manager.utils.manager

Expand All @@ -37,9 +36,7 @@ class HomeFragment : BindingFragment<FragmentHomeBinding>() {
const val REFRESH_HOME = "REFRESH_HOME"
}

private val viewModel: HomeViewModel by viewModels {
HomeViewModelFactory(requireActivity())
}
private val viewModel: HomeViewModel by viewModels()

private val localBroadcastManager by lazy { LocalBroadcastManager.getInstance(requireActivity()) }

Expand Down
Loading

0 comments on commit eb28c61

Please sign in to comment.