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

Commit

Permalink
Remove viewmodel memory leak
Browse files Browse the repository at this point in the history
  • Loading branch information
NotWoods committed Oct 25, 2021
1 parent 4af47e8 commit 368808d
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class ExpandableAppListAdapter(
appDownload.apply {
setOnClickListener {
viewModel.openInstallDialog(
activity.supportFragmentManager,
buttonTag,
apps[position]
)
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)
}
}
}
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
90 changes: 42 additions & 48 deletions app/src/main/java/com/vanced/manager/ui/viewmodels/HomeViewModel.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.vanced.manager.ui.viewmodels

import android.annotation.SuppressLint
import android.app.Application
import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.widget.Toast
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.vanced.manager.R
Expand Down Expand Up @@ -38,12 +39,11 @@ import com.vanced.manager.utils.PackageHelper.uninstallRootApk
import com.vanced.manager.utils.PackageHelper.vancedInstallFilesExist
import kotlinx.coroutines.launch

//TODO fix leak
@SuppressLint("StaticFieldLeak")
class HomeViewModel(private val activity: FragmentActivity) : ViewModel() {
class HomeViewModel(application: Application) : AndroidViewModel(application) {

private val prefs = getDefaultSharedPreferences(activity)
private val prefs = getDefaultSharedPreferences(context)
private val variant get() = prefs.getString("vanced_variant", "nonroot")
private val context: Context get() = getApplication()

val vancedModel = MutableLiveData<DataModel>()
val vancedRootModel = MutableLiveData<RootDataModel>()
Expand All @@ -54,13 +54,13 @@ class HomeViewModel(private val activity: FragmentActivity) : ViewModel() {

fun fetchData() {
viewModelScope.launch {
loadJson(activity)
loadJson(context)
}
}

private val microgToast = Toast.makeText(activity, R.string.no_microg, Toast.LENGTH_LONG)
private val microgToast = Toast.makeText(context, R.string.no_microg, Toast.LENGTH_LONG)

fun openUrl(url: String) {
fun openUrl(context: Context, url: String) {
val color: Int =
when (url) {
DISCORD -> R.color.Discord
Expand All @@ -71,82 +71,82 @@ class HomeViewModel(private val activity: FragmentActivity) : ViewModel() {
else -> R.color.Vanced
}

openUrl(url, color, activity)
openUrl(url, color, context)
}

fun launchApp(app: String, isRoot: Boolean) {
val componentName = when (app) {
activity.getString(R.string.vanced) -> if (isRoot) ComponentName(
context.getString(R.string.vanced) -> if (isRoot) ComponentName(
vancedRootPkg,
"$vancedRootPkg.HomeActivity"
) else ComponentName(vancedPkg, "$vancedRootPkg.HomeActivity")
activity.getString(R.string.music) -> if (isRoot) ComponentName(
context.getString(R.string.music) -> if (isRoot) ComponentName(
musicRootPkg,
"$musicRootPkg.activities.MusicActivity"
) else ComponentName(musicPkg, "$musicRootPkg.activities.MusicActivity")
activity.getString(R.string.microg) -> ComponentName(
context.getString(R.string.microg) -> ComponentName(
microgPkg,
"org.microg.gms.ui.SettingsActivity"
)
else -> throw IllegalArgumentException("Can't open this app")
}
try {
activity.startActivity(Intent().setComponent(componentName))
context.startActivity(Intent().setComponent(componentName))
} catch (e: ActivityNotFoundException) {
log("VMHMV", e.toString())
}

}

fun openInstallDialog(buttonTag: ButtonTag?, app: String) {
if (variant == "nonroot" && app != activity.getString(R.string.microg) && !microgModel.value?.isAppInstalled?.value!!) {
fun openInstallDialog(fragmentManager: FragmentManager, buttonTag: ButtonTag?, app: String) {
if (variant == "nonroot" && app != context.getString(R.string.microg) && !microgModel.value?.isAppInstalled?.value!!) {
microgToast.show()
return
}

if (buttonTag == ButtonTag.UPDATE) {
when (app) {
activity.getString(R.string.vanced) -> VancedPreferencesDialog().show(activity)
activity.getString(R.string.music) -> MusicPreferencesDialog().show(activity)
else -> AppDownloadDialog.newInstance(app).show(activity)
context.getString(R.string.vanced) -> VancedPreferencesDialog().show(fragmentManager)
context.getString(R.string.music) -> MusicPreferencesDialog().show(fragmentManager)
else -> AppDownloadDialog.newInstance(app).show(fragmentManager)
}
return
}

when (app) {
activity.getString(R.string.vanced) -> {
context.getString(R.string.vanced) -> {
when (variant) {
"nonroot" -> {
if (vancedInstallFilesExist(activity)) {
InstallationFilesDetectedDialog.newInstance(app).show(activity)
if (vancedInstallFilesExist(context)) {
InstallationFilesDetectedDialog.newInstance(app).show(fragmentManager)
} else {
VancedPreferencesDialog().show(activity)
VancedPreferencesDialog().show(fragmentManager)
}
}
"root" -> {
VancedPreferencesDialog().show(activity)
VancedPreferencesDialog().show(fragmentManager)
}
}
}
activity.getString(R.string.music) -> {
context.getString(R.string.music) -> {
when (variant) {
"nonroot" -> {
if (musicApkExists(activity)) {
InstallationFilesDetectedDialog.newInstance(app).show(activity)
if (musicApkExists(context)) {
InstallationFilesDetectedDialog.newInstance(app).show(fragmentManager)
} else {
MusicPreferencesDialog().show(activity)
MusicPreferencesDialog().show(fragmentManager)
}
}
"root" -> {
MusicPreferencesDialog().show(activity)
MusicPreferencesDialog().show(fragmentManager)
}
}
}
activity.getString(R.string.microg) -> {
if (apkExist(activity, "microg.apk")) {
InstallationFilesDetectedDialog.newInstance(app).show(activity)
context.getString(R.string.microg) -> {
if (apkExist(context, "microg.apk")) {
InstallationFilesDetectedDialog.newInstance(app).show(fragmentManager)
} else {
AppDownloadDialog.newInstance(app).show(activity)
AppDownloadDialog.newInstance(app).show(fragmentManager)
}
}
}
Expand All @@ -155,68 +155,62 @@ class HomeViewModel(private val activity: FragmentActivity) : ViewModel() {

fun uninstallPackage(pkg: String) {
if (variant == "root" && uninstallRootApk(pkg)) {
viewModelScope.launch { loadJson(activity) }
viewModelScope.launch { loadJson(context) }
} else {
uninstallApk(pkg, activity)
uninstallApk(pkg, context)
}
}

init {
with(activity) {
with(context) {
if (variant == "root") {
vancedRootModel.value = RootDataModel(
vanced,
this,
this,
vancedRootPkg,
this.getString(R.string.vanced),
activity.getString(R.string.description_vanced),
this.getString(R.string.description_vanced),
R.drawable.ic_vanced,
"vanced"
)
musicRootModel.value = RootDataModel(
music,
this,
this,
musicRootPkg,
this.getString(R.string.music),
activity.getString(R.string.description_vanced_music),
this.getString(R.string.description_vanced_music),
R.drawable.ic_music,
"music"
)
} else {
vancedModel.value = DataModel(
vanced,
this,
this,
vancedPkg,
this.getString(R.string.vanced),
activity.getString(R.string.description_vanced),
this.getString(R.string.description_vanced),
R.drawable.ic_vanced
)
musicModel.value = DataModel(
music,
this,
this,
musicPkg,
this.getString(R.string.music),
activity.getString(R.string.description_vanced_music),
this.getString(R.string.description_vanced_music),
R.drawable.ic_music
)
microgModel.value = DataModel(
microg,
this,
this,
microgPkg,
this.getString(R.string.microg),
activity.getString(R.string.description_microg),
this.getString(R.string.description_microg),
R.drawable.ic_microg
)
}
managerModel.value = DataModel(
manager,
this,
this,
managerPkg,
this.getString(R.string.app_name),
"Just manager meh",
Expand Down

This file was deleted.

9 changes: 7 additions & 2 deletions app/src/main/java/com/vanced/manager/utils/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import android.widget.RadioGroup
import androidx.core.graphics.ColorUtils
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LifecycleOwner
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.progressindicator.LinearProgressIndicator
Expand All @@ -22,14 +23,18 @@ val RadioGroup.checkedButtonTag: String?
checkedRadioButtonId
)?.tag?.toString()

fun DialogFragment.show(activity: FragmentActivity) {
fun DialogFragment.show(fragmentManager: FragmentManager) {
try {
show(activity.supportFragmentManager, "")
show(fragmentManager, "")
} catch (e: Exception) {
log("VMUI", e.stackTraceToString())
}
}

fun DialogFragment.show(activity: FragmentActivity) {
show(activity.supportFragmentManager)
}

fun List<String>.convertToAppVersions(): List<String> = listOf("latest") + reversed()

fun String.formatVersion(context: Context): String =
Expand Down

0 comments on commit 368808d

Please sign in to comment.