Skip to content

This repository contains documentation of various errors and bugs commonly encountered during Android app development, along with tried and successful solutions. The goal is to be a resource that can help solve common problems encountered by both novice and experienced Android developers.

Notifications You must be signed in to change notification settings

galihif/Android-Dev-Troubleshooting

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 

Repository files navigation

Daftar Isi

Android Studio

Change Android Studio Project and Package name

  • Change App/Project Name :
    • Go to settings.gradle and rename rootProject.name
    • Go to strings.xml and rename @string/app_name
    • Change Theme Name in themes.xml
    • Gradle Sync, Clean and rebuild project
  • Change Package Name :
    • Go to build.gradle module level, rename namespace and applicationId
    • Run gradle sync
    • In the project tab, Tree Appearance > uncheck Compact Middle Packages
    • Right click on package name folder > Refactor > Rename > Do Refactor
    • Clean and rebuild project
  • Reference : Stackoverflow Thread

Gradle

Error: Execution failed for task ':app:kaptGenerateStubsDebugKotlin'

  • Issue: After adding hilt dependencies, it's successfully synced but failed to run and throw error
Execution failed for task ':app:kaptGenerateStubsDebugKotlin'.
> 'compileDebugJavaWithJavac' task (current target is 1.8) and 'kaptGenerateStubsDebugKotlin' task (current target is 17) jvm target compatibility should be set to the same Java version.
  Consider using JVM toolchain: https://kotl.in/gradle/jvm/toolchain
  • Solution: Ganti jvmTarget dan sourceCompatibility targetCompatibility ke Java 17

  • Reference: Stackoverflow Thread

Jetpack Compose

Layout: A child in row not fill max height to its parent

  • Issue: The card already set to fillMaxHeight but not showing on row.
image
  • Solution: In the parent add the .height(IntrinsicSize.Min) to its modifier
image
Row(
    modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min)
) {
    Child1(
        modifier = Modifier
            .fillMaxHeight()
            .width(100.dp),
    ) {}
    Child2(
        modifier = Modifier
            .fillMaxWidth()
            .weight(1f)
    ) {...}
}

Navigation : Popbackstack multiple screens

  • Issue:

In a navigation flow where there are multiple screens (e.g., Screen A > Screen B > Screen C), there may be situations where you want to pop multiple screens off the back stack at once. For example, you might want to navigate directly from Screen C back to Screen A, skipping Screen B. Using the default NavController.popBackStack() method will only pop one screen at a time, which may not be sufficient for your use case.

  • Solution:

A solution to this problem is using the overloaded NavController.popBackStack(route: String, inclusive: Boolean) method, which pops all destinations up to a specified one.

Here's how you can use this function in your code:

val navController = rememberNavController()
Button(onClick = {
    navController.popBackStack(route = "A", inclusive = false)
}) {
    Text(text = "Back to Screen A")
}

This code will pop the back stack until it reaches Screen A, but Screen A will remain in the stack, i.e., it will be the current destination after the operation. If inclusive is set to false (which is the default), then all destinations up to but not including the one associated with the given route (in this case A) will be popped. If inclusive is set to true, then all destinations up to and including the one associated with the given route will be popped.

Remember, popBackStack() returns a boolean indicating whether it successfully popped the back stack. You should handle the case where it returns false, which indicates that it could not find a destination associated with the given route in the back stack.


Recomposition : Updating Value Not Reflected in Composable

  • Issue :

In a Jetpack Compose project, a value updated in the ViewModel might not be reflected in a specific composable. Despite the value being changed and observed within the ViewModel, the composable may still show the initial or default value. This can lead to inconsistencies in the UI where the displayed information does not match the actual data state.

  • Solution :

A solution to this problem is using the key function in Jetpack Compose, which can be used to force recomposition of a specific composable based on a particular value. Whenever the value passed to the key function changes, the composable within the key block will recompose, ensuring that the UI correctly reflects the updated value.

Here's how you can use this approach in your code:

@Composable
fun MyComposable(user: User) {
    val score = calculateScore(user)

    // This will force recomposition of the inner content whenever the score changes
    key(score) {
        Text("User score: $score")
        // other composables that depend on the score
    }
}

By leveraging the key function, developers can ensure that the UI updates in response to specific data changes, resolving the issue where certain composables were not reflecting the updated value when expected. This leads to a more predictable and responsive user experience.

  • References : ChatGPT4

Dialog : Change Dialog Background Overlay Color

  • Issue :

In compose dialog the overlay is just black with some opacity, I want to change the color with other color not just black

  • Solution :

In DialogProperties set the usePlatformDefaultWidth to false, it will make the dialog size is full screen and not limited to platform default width. Wrap your content with Box and set its modifier to fillMaxSize() and the background() with the color you wanted.

    Dialog(
        onDismissRequest = { /*TODO*/ },
        properties = DialogProperties(usePlatformDefaultWidth = false)
    ) {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(CloveUITheme.colors.primary30.copy(alpha = 0.4f))
        ) {
            YourDialogContent()
        }
    }
  • References : ChatGPT

Column : Scroll to bottom on a vertically scrollable column and detect if it scrolled to the end

  • Issue :

In compose column there's a content that too large and it needs a vertical scroll. I want to make an animate to bottom of the column and check if it already scrolled to the bottom.

  • Solution :

Using scrollState.maxValue to get the max position of the column and scrollState.value to get the current position of the column.

Check if already scrolled to the end:

val endReached by remember {
    derivedStateOf {
        scrollState.value == scrollState.maxValue
    }
}

Scroll to the bottom of the column:

coroutineScope.launch {
    scrollState.animateScrollTo(scrollState.maxValue)
}

Jetpack compose: prevent screenshot on screen

  • Issue :

In compose app i want to set the specific screen to unable to screen captured by user

  • Solution :

Get the activity in your composable function and set the flags to WindowManager.LayoutParams.FLAG_SECURE

    val activity = LocalContext.current as Activity
    activity.window.setFlags(
        WindowManager.LayoutParams.FLAG_SECURE,
        WindowManager.LayoutParams.FLAG_SECURE
    )

Because compose is a single activity app, you have to clear the flags after the screen changed with DisposableEffect

    DisposableEffect(key1 = Unit) {
        onDispose {
            activity.window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
        }
    }

About

This repository contains documentation of various errors and bugs commonly encountered during Android app development, along with tried and successful solutions. The goal is to be a resource that can help solve common problems encountered by both novice and experienced Android developers.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published