- kotlin_lambda.md - Lambda in Kotlin
- HiltExampleActivity.kt - Basic usage of Hilt dependency injection
Last active
November 26, 2020 16:06
-
-
Save roxxydev/4ac2f2e4cddfbd1583703d5b392df603 to your computer and use it in GitHub Desktop.
Android with Kotlin
- CoroutineExceptionHandler is invoked only on uncaught exceptions — exceptions that were not handled in any other way. In particular, all children coroutines (coroutines created in the context of another Job) delegate handling of their exceptions to their parent coroutine, which also delegates to the parent, and so on until the root, so the CoroutineExceptionHandler installed in their context is never used. In addition to that, async builder always catches all exceptions and represents them in the resulting Deferred object, so its CoroutineExceptionHandler has no effect either.
- Coroutines internally use CancellationException for cancellation, these exceptions are ignored by all handlers, so they should be used only as the source of additional debug information, which can be obtained by catch block. When a coroutine is cancelled using Job.cancel, it terminates, but it does not cancel its parent.
- Throwing exception child coroutines will cause an error and app to crash.
- If a coroutine encounters an exception other than CancellationException, it cancels its parent with that exception.
- The original exception is handled by the parent (in CoroutineExceptionHandler) only when all its children terminate, which is demonstrated by the following example.
- When multiple children of a coroutine fail with an exception, the general rule is "the first exception wins", so the first exception gets handled. All additional exceptions that happen after the first one are attached to the first exception as suppressed ones.
- crucial difference between regular and supervisor jobs is exception handling. Every child should handle its exceptions by itself via the exception handling mechanism. This difference comes from the fact that child's failure does not propagate to the parent. It means that coroutines launched directly inside the supervisorScope do use the CoroutineExceptionHandler that is installed in their scope in the same way as root coroutines do.
Example:
fun main() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
println("CoroutineExceptionHandler got $exception")
}
supervisorScope {
val child = launch(handler) {
println("The child throws an exception")
throw AssertionError()
}
println("The scope is completing")
}
println("The scope is completed")
}
Output:
The scope is completing
The child throws an exception
CoroutineExceptionHandler got java.lang.AssertionError
The scope is completed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import androidx.appcompat.app.AppCompatActivity | |
| import android.os.Bundle | |
| import androidx.fragment.app.Fragment | |
| import dagger.hilt.android.AndroidEntryPoint | |
| import javax.inject.Inject | |
| @AndroidEntryPoint | |
| class HiltExampleActivity : AppCompatActivity() { | |
| // Using Field injection | |
| @Inject | |
| lateinit var someClass: SomeClass | |
| @Inject | |
| lateinit var anotherClass: AnotherClass | |
| override fun onCreate(savedInstanceState: Bundle?) { | |
| super.onCreate(savedInstanceState) | |
| setContentView(R.layout.activity_main) | |
| println(someClass.doAThing()) | |
| println(anotherClass.doAThing()) | |
| println(anotherClass.doAThing2()) | |
| } | |
| } | |
| // Using Constructor injection | |
| class SomeClass | |
| @Inject | |
| constructor( | |
| private val someDependency: SomeDependency | |
| ) { | |
| fun doAThing(): String{ | |
| return "Look I got: ${someDependency.getAThing()}" | |
| } | |
| } | |
| class SomeDependency | |
| @Inject | |
| constructor() { | |
| fun getAThing() : String{ | |
| return "A Thing" | |
| } | |
| } | |
| // With Interface | |
| class AnotherClass | |
| @Inject | |
| constructor( | |
| private val someInterfaceImpl1: SomeInterface, | |
| @Impl2 private val someInterfaceImpl2: SomeInterface | |
| ) { | |
| fun doAThing(): String { | |
| return "Look I got: ${someInterfaceImpl1.getAThing()}" | |
| } | |
| fun doAThing2(): String { | |
| return "Look I got: ${someInterfaceImpl2.getAThing()}" | |
| } | |
| } | |
| interface SomeInterface { | |
| fun getAThing(): String | |
| } | |
| class SomeInterfaceImpl1 | |
| @Inject | |
| constructor(): SomeInterface { | |
| override fun getAThing() : String { | |
| return "A Thing1" | |
| } | |
| } | |
| class SomeInterfaceImpl2 | |
| @Inject | |
| constructor(): SomeInterface { | |
| override fun getAThing() : String { | |
| return "A Thing2" | |
| } | |
| } | |
| @InstallIn(ApplicationComponent::class) | |
| @Module | |
| class MyModule { | |
| @Singleton | |
| @Provides | |
| fun provideSomeInterface1(): SomeInterface { | |
| return SomeInterfaceImpl1() | |
| } | |
| @Impl2 | |
| @Singleton | |
| @Provides | |
| fun provideSomeInterface2(): SomeInterface { | |
| return SomeInterfaceImpl2() | |
| } | |
| /* | |
| // Use Provides instead of Binds to solve issue for injecting libraries interfaces you don't own | |
| @Singleton | |
| @Provides | |
| fun provideGson(): Gson { | |
| return Gson() | |
| } | |
| */ | |
| } | |
| // Providing instances of the same type (SomeInterface) | |
| @Qualifier | |
| @Retention(AnnotationRetention.BINARY) | |
| annotation class Impl2 |
- You can put the whole lambda inside the parentheses.
list.any({ i: Int -> i > 0 })
- You can move lambda out of parentheses if the lambda is the last argument.
list.any() { i : Int -> i > 0}
- If the parentheses are empty you can even omit them.
list.any { i: Int -> i > 0 }
- If lambda has the only argument, you can replace its name with ‘it’.
list.any{ it > 0 }
- A variable whose type is a function that takes two integer parameters and returns integer as a result
val sum = { x: Int, y: Int -> x=y }
- A variable whose type is a function that takes Int as a parameter,and returns Boolean as result
val isEven = { i: Int -> i % 2 ==0 }
val p : String.(Int) -> String = { this + it }
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment