Skip to content

Commit 444c0c5

Browse files
committed
Refactor the way Coroutines "health" is checked because if a CancellationException is thrown out of the catch block or the ViewModel is told to cancel its scope as soon as it is detected/thrown, code won't be able to return any kind of error to upper layers and that will lead to gray area where the app goes to a zombie state and UI will "forever" wait for a result that never comes
The information that lead to this second change is contained in this article: https://betterprogramming.pub/the-silent-killer-thats-crashing-your-coroutines-9171d1e8f79b The point is that the examples shown in the article go for a more generic approach and do not reflect how Coroutine scope generation works on Android where the Scope owner is not in most cases in the same file where a CancellationException will likely be thrown so devs have to find a way around in order to tell the Scope owner which usually is ViewModel to check if its scope is still active or not The way I found to be the better one in my specific case is to instead of letting CancellationExceptions out of catch blocks or warn ViewModels to check on their Coroutine scopes and possibly cancel them if it is found they are not active anymore leading the app to a "Zombie" state, is to check the scope status at the end of every operation. This way, the UI is warned beforehand and if indeed the scope in question is not active anymore, it is cancelled before another operation is performed under it. According to Roman Elizarov's comments in the open issue for this matter, it will probably never be fixed due to its high complexity where a new implementation of Coroutines from scratch would almost certainly be required to fix it, which will most likey never happen. So, there's that. Let's enjoy Coroutines as it is :) More info on it can be found here and I highly recommend you take a look at it: Kotlin/kotlinx.coroutines#1374 Move away from the "By feature + By layer" modularization approach in favor of the "By feature" only approach Create domain module Create di module Create resources module Create utils module Delete unused XML layouts Delete unused ViewHolders Create specific modules for JVM and Instrumented testing so one cannot access the other's dependencies Rename midfield module to domain Convert all module-level build.gradle files to KTS Remove targetSdk field from build.gradle files as it is now deprecated Add Koin lazy modules feature Add Koin startup feature Migrate to Kotlin 2.1.0 Migrate from packagingOption to packaging as it is now deprecated Migrate default build.gradle JVM Versioning approach to jvmToolchain Upgrade to Coil3 Upgrade to Ktor 3.0 Upgrade Gradle to 8.12 Refactor layout ids Disable "allowBackup" manifest option as database changes will always require migrations even if all app data is removed through the app details screen Remove empty/unused manifest files Split ProfileAggregator into individual UseCases Refactor gradlew script Add "orderingId" field to Profile table so now when data is retrieved from Database it accurately reflects how data is ordered in Github API since it does not return individual profile scores anymore Refactor libs.versions.toml Re-add INSERT to available SQL commands Refactor the way remote repositories propagate their results so now there is a callback for each type of result and there is no need to check for success or failure more than once Move ResultHandler to Data layer Change HTTP codes inside RemoteFetcher as search quota reached error code is not 451 anymore but 403 (Forbidden) Add checks to UIState so state checking in the UI is more concise Update dependency versions
1 parent 6d43c76 commit 444c0c5

File tree

199 files changed

+1685
-2212
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

199 files changed

+1685
-2212
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/355f2c30bb5746cc8083b0bc684c7650)](https://www.codacy.com/gh/caiodev/GithubProfileSearcher/dashboard?utm_source=github.com&utm_medium=referral&utm_content=caiodev/GithubProfileSearcher&utm_campaign=Badge_Grade) [![codebeat badge](https://codebeat.co/badges/59a0827f-9c7e-44a3-999b-86ab4662e128)](https://codebeat.co/projects/github-com-caiodev-githubprofilesearcher-edge___often_broken___)
1+
[![codebeat badge](https://codebeat.co/badges/59a0827f-9c7e-44a3-999b-86ab4662e128)](https://codebeat.co/projects/github-com-caiodev-githubprofilesearcher-edge___often_broken___) [![CodeFactor](https://www.codefactor.io/repository/github/caiodev/githubprofilesearcher/badge/edge___often_broken___)](https://www.codefactor.io/repository/github/caiodev/githubprofilesearcher/overview/edge___often_broken___)
22

33
# GithubProfileSearcher
44

app/build.gradle

-77
This file was deleted.

app/build.gradle.kts

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
2+
3+
plugins {
4+
alias(dep.plugins.androidApplication)
5+
alias(dep.plugins.kotlinPlugin)
6+
}
7+
8+
apply {
9+
from("$rootDir/flavors/flavors.gradle")
10+
}
11+
12+
android {
13+
compileSdk =
14+
dep.versions.compileSdk
15+
.get()
16+
.toInt()
17+
defaultConfig {
18+
applicationId = "githubprofilesearcher.caiodev.com.br.githubprofilesearcher.app"
19+
minSdk =
20+
dep.versions.minSdk
21+
.get()
22+
.toInt()
23+
versionCode =
24+
dep.versions.versionCode
25+
.get()
26+
.toInt()
27+
versionName = dep.versions.versionName.get()
28+
vectorDrawables.useSupportLibrary = true
29+
}
30+
31+
buildTypes {
32+
debug {
33+
applicationIdSuffix = ".debug"
34+
isMinifyEnabled = false
35+
isShrinkResources = false
36+
signingConfig = signingConfigs.getByName("debug")
37+
}
38+
39+
release {
40+
applicationIdSuffix = ".release"
41+
isMinifyEnabled = true
42+
isShrinkResources = true
43+
proguardFiles(
44+
getDefaultProguardFile("proguard-android.txt"),
45+
"proguard-rules.pro",
46+
)
47+
}
48+
}
49+
50+
kotlin {
51+
jvmToolchain(JvmTarget.JVM_23.target.toInt())
52+
}
53+
54+
packaging {
55+
resources {
56+
excludes +=
57+
setOf(
58+
"/META-INF/{AL2.0,LGPL2.1,LICENSE.md,LICENSE-notice.md,licenses/ASM}",
59+
"win32-x86{/attach_hotspot_windows.dll,-64/attach_hotspot_windows.dll}",
60+
"kotlin{/annotation/annotation,/collections/collections,/coroutines/coroutines," +
61+
"/internal/internal,/kotlin,/ranges/ranges,/reflect/reflect}.kotlin_builtins",
62+
)
63+
}
64+
}
65+
66+
namespace = "githubprofilesearcher.caiodev.com.br.githubprofilesearcher.app"
67+
}
68+
69+
dependencies {
70+
debugImplementation(dep.leakCanary)
71+
implementation(projects.modules.common.di) { because("DI Module") }
72+
implementation(projects.modules.common.resources) { because("Resources Module") }
73+
implementation(projects.modules.features.profile) { because("Profile Module") }
74+
implementation(dep.bundles.coil)
75+
}
76+
77+
tasks.withType<Test> {
78+
systemProperty("includeAndroidResources", "true")
79+
useJUnitPlatform()
80+
}
81+
82+
group = "githubprofilesearcher.caiodev.com.br.githubprofilesearcher.app"

app/proguard-rules.pro

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# By default, the flags in this file are appended to flags specified
33
# in /home/unknown/Android/Sdk/tools/proguard/proguard-android.txt
44
# You can edit the include path and order by changing the proguardFiles
5-
# directive in build.gradle.
5+
# directive in build.gradle.kts.
66
#
77
# For more details, see
88
# http://developer.android.com/guide/developing/tools/proguard.html

app/src/main/AndroidManifest.xml

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,22 @@
44

55
<application
66
android:name=".App"
7-
android:allowBackup="true"
7+
android:allowBackup="false"
88
android:icon="@mipmap/ic_launcher"
99
android:label="@string/app_name"
1010
android:localeConfig="@xml/locales_config"
1111
android:networkSecurityConfig="@xml/network_security_config"
1212
android:roundIcon="@mipmap/ic_launcher_round"
1313
android:supportsRtl="true"
1414
android:theme="@style/AppTheme"
15-
tools:ignore="AllowBackup"
1615
tools:targetApi="tiramisu">
1716

1817
<profileable
1918
android:shell="true"
2019
tools:targetApi="q" />
2120

2221
<activity
23-
android:name=".ui.profile.activity.ProfileListingActivity"
22+
android:name="githubprofilesearcher.caiodev.com.br.githubprofilesearcher.profile.ui.activity.ProfileListingActivity"
2423
android:configChanges="uiMode"
2524
android:exported="true">
2625
<intent-filter>

app/src/main/kotlin/githubprofilesearcher/caiodev/com/br/githubprofilesearcher/App.kt

-49
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package githubprofilesearcher.caiodev.com.br.githubprofilesearcher.app
2+
3+
import android.app.Application
4+
import androidx.appcompat.content.res.AppCompatResources
5+
import coil3.ImageLoader
6+
import coil3.PlatformContext
7+
import coil3.SingletonImageLoader
8+
import coil3.asImage
9+
import coil3.disk.DiskCache
10+
import coil3.memory.MemoryCache
11+
import coil3.network.ktor3.KtorNetworkFetcherFactory
12+
import coil3.request.crossfade
13+
import coil3.util.DebugLogger
14+
import githubprofilesearcher.caiodev.com.br.githubprofilesearcher.profile.di.profileModule
15+
import okio.Path.Companion.toOkioPath
16+
import org.koin.android.ext.koin.androidContext
17+
import org.koin.android.ext.koin.androidLogger
18+
import org.koin.androix.startup.KoinStartup
19+
import org.koin.core.annotation.KoinExperimentalAPI
20+
import org.koin.core.lazyModules
21+
import org.koin.core.logger.Level
22+
import org.koin.dsl.KoinAppDeclaration
23+
import githubprofilesearcher.caiodev.com.br.githubprofilesearcher.resources.R as Resources
24+
25+
@OptIn(KoinExperimentalAPI::class)
26+
class App :
27+
Application(),
28+
KoinStartup,
29+
SingletonImageLoader.Factory {
30+
override fun onKoinStartup(): KoinAppDeclaration =
31+
{
32+
androidContext(this@App)
33+
androidLogger(Level.DEBUG)
34+
lazyModules(profileModule)
35+
}
36+
37+
override fun newImageLoader(context: PlatformContext): ImageLoader {
38+
val defaultImage =
39+
AppCompatResources
40+
.getDrawable(
41+
applicationContext,
42+
Resources.mipmap.ic_launcher,
43+
)
44+
?.asImage()
45+
return ImageLoader
46+
.Builder(context)
47+
.components { add(KtorNetworkFetcherFactory()) }
48+
.crossfade(true)
49+
.diskCache {
50+
DiskCache
51+
.Builder()
52+
.directory(cacheDir.resolve(COIL_CACHE_DIR).toOkioPath())
53+
.maxSizePercent(DISK_CACHE_CAP)
54+
.build()
55+
}
56+
.memoryCache {
57+
MemoryCache
58+
.Builder()
59+
.maxSizePercent(context, MEMORY_CACHE_CAP)
60+
.build()
61+
}
62+
.placeholder(defaultImage)
63+
.error(defaultImage)
64+
.logger(DebugLogger())
65+
.build()
66+
}
67+
68+
companion object {
69+
private const val COIL_CACHE_DIR = "coil_image"
70+
private const val DISK_CACHE_CAP = .02
71+
private const val MEMORY_CACHE_CAP = .05
72+
}
73+
}

app/src/main/res/values/styles.xml

-9
This file was deleted.

build.gradle

-28
This file was deleted.

0 commit comments

Comments
 (0)