My talk called "Simplified Android Development using Simple-Stack" about single-activity applications at
@androidww_
is now finally available! ๐๐๐
You can watch it on YouTube using the following link:
Thank you so much
@androidww_
for having me, I hope the talk on Simple-Stack (and other navigation approaches) was informative as intended :)
The slides are available here:
I'm excited to see the END of backing properties in Kotlin with Kotlin 1.7.0 once and for all.
Never liked backing properties and the _prefix. Always went out of my way to avoid the _.
Finally, a new language feature will eliminate any/all need for them. Good news for Kotlin.
(!!!) People who use Navigation-Compose in Jetpack Compose should be aware of this:
If you use Navigation-Compose, you need to pass NavHostController to your composable, instead of creating it as default argument.
If you use it as default argument, state restoration won't work.
Make sure you get that Flow from a UseCase that talks to a Repository that talks to a Service that talks to a Datasource that talks to a Dao that talks to a Database that talks to a mental health professional
This is TDD (Therapy-Driven Development)
#tdd
#cleanarch
#mandroiddev
Concepts you need to know and understand in order to work effectively with Jetpack Compose
- launched/disposable/side effects
- composition/recomposition
- key {}, remember(key), rememberSaveable
- modifiers (Draw/Layout/ParentDataModifier)
- CompositionLocal
- stable/immutable
My experience with updating to Jetpack Compose 1.5.0 stable release
- AGP 7.4.2 is not supported, you need AGP 8.1
- AGP 8.1 is not supported by Flamingo, use AS Giraffe
- Compose 1.5.0 needs compileSdk 34
Then you use Kotlin 1.9.0 + Compose Compiler 1.5.1, now it seems to work
When you create DataSource Dao Repository UseCase Helper to "ensure consistency across all data access and implement clean architecture", just to write a string in shared pref
Not sure who still needs to hear this, but the following Github link is the latest edition of the official Android Clean Architecture repository, as described by the Android Clean Architecture article series
Check it for reference on Clean Architecture
I've published an article on some tips that can make Kotlin code easier to read/understand, and minimize the usage of some potentially cryptic and/or unnecessary and/or less trustworthy constructs (e.g avoiding `?.let {} ?: run {}` as general control flow)
The walls of the "MVI maze" represent
- unexpected race conditions
- non-cancellable obsolete in-flight requests
- state restoration bugs due to saving data and transient state along with the actual state
- modelling synchronous function calls with classes
- "reducer" complexity
If you use LiveData +Kotlin, then it's time to STOP writing `, Observer {})`. Use trailing lambdas. Add this import from lifecycle-ktx and you should be good: `import androidx.lifecycle.observe`
.observe(viewLifecycleOwner) {
adapter.submitList(it)
}
Android development is mostly frontend, so with the advent of Compose + "MVI" + Hilt + AndroidX-Navigation i feel this is true
#androiddev
#mandroiddev
I've released a new article on Medium!
"Structural and navigation anti-patterns in multi-module and modularized applications: the case against โAndroid Clean Architectureโ and the โdomainโ module".
TL;DR: "Android Clean Architecture" is an anti-pattern.
Article by
@IceRockDev
on how to avoid unnecessary recompositions and laggy UI when using Jetpack Compose
#androiddev
Examples:
1.) remember {{ }} lambdas
2.) avoiding ConstraintLayout (it's slower than Row/Column, same as XML)
3.) Argument type stability
This is a question to
#androiddev
s๐
โ๏ธ Assuming I were to write a book about Android dev, what is it that you'd feel excited to read about?
I'm thinking view-based UI development, lifecycle management, state management, fragments/child fragments, etc. but what about you? ๐ค
I must say I'm a bit rusty when it comes to writing articles, but it's finally out
"Reclaim the reactivity of your state management, say no to imperative MVI"
Will this be the final blow to `_state.value = _state.value.copy()`?
Only time will tell ๐
Today's Android development fact
- If you don't know about DisposableEffect(key) {} and key(key) {} in Jetpack Compose
(despite using Jetpack Compose)
Then you should probably learn a bit more about Jetpack Compose first, as you won't be able to write code that works correctly
My favorite error message is
Execution failed for task ':project:kaptDebugKotlin'.
> A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptExecution
> java.lang.reflect.InvocationTargetException (no error message)
I've published 'Dagger Magic Tricks: leveraging AssistedInjection to inject ViewModels with SavedStateHandle, and Map-Multibinding to inject Workers in WorkManager using WorkerFactory'. Get it while it's hot! And when it's cold. Should be nice either way.
After Android 12+ in the root, onDestroy() will never be called, as finish() will never be called. This also means that Activity-scoped ViewModels will never get onCleared() callback
The only reliable callbacks for managing state is onStart/onStop (oddly just like LiveData does)
Merab Tato Kutalia ๐ฌ๐ช - Glory to Ukraine ๐บ๐ฆ
Big news
#androiddev
! The team working on Hilt has added support for passing custom CreationExtras to a ViewModel using Assisted Injection.
I wasn't really keeping my hopes up, so I'm really happy with this addition to Hilt, now that it is supported.
I'm happy to report that I can finally stop complaining about the way SavedStateHandle is used in Now-In-Android.
Previously, SavedStateHandle was only used to pass arguments to the ViewModel.
2 weeks ago, a new "Search" feature was added, which uses
Time for the 2023 "Good things about Android development" challenge this Monday
#androiddev
๐
I really like: how easy it is to position Views in XML layouts with minimal effort using FrameLayout layout_gravity, LinearLayout weight, previews, and being able to define margins. ๐
Apparently, the release of Jetpack Compose has brought us multiple new navigation frameworks to replace Navigation-Compose.
Bumble-Tech wrote Appyx, while Slack wrote Circuit.
It seems there will be a talk here on YouTube in a few moments about Circuit.
Android 13 docs on the new Photo Picker API using startActivityForResult/onActivityResult instead of implementing custom ActivityResultContract
I guess the docs author of realized that ResultContracts are much trickier than the "deprecated" system APIs ๐
Insightful comment by
@jakewharton
: `Nullable APIs lead to people doing foo?.bar and wonder why the app silently gets into weird states. It's because they probably wanted foo!!.bar but someone shamed them for !! and requireFoo() was "too much boilerplate"`
What an interesting article on how using StateFlows from ViewModels can actually result in trickier code with more edge-cases than using LiveData (even including the liveData { coroutine builder)๐ค
I made a promise that I'll make an article on Reactive MVI (which is better than the MVI you're used to
Most likely not tomorrow, but likely the day after that ๐
I'm still hearing people claim that "just put your state into a ViewModel, and it will survive the Android lifecycle"
but in reality that doesn't handle process death unless you also use SavedStateHandle
I had a talk on this April 6th 2021 still relevant
Sometimes I wonder why we need 8+ classes to do what web developers can do with a single line of code ๐ค
$.get("URL").then((result) -> {}).catch((err) -> {})
The equivalent on Android would be as simple as
viewModelScope.launch {
api.getUrl().fold(onSuccess={}, onError={})
}
Stuck with Dagger-Android? Fret not, I've written an article on how Dagger-Android works, what it solves, and how to structure Dagger Modules for better scalability.
TL;DR: do not have an ActivityBuildersModule, FragmentBuildersModule or ViewModelModule.
@VasiliyZukanov
I don't think this is true, ViewBinding is pragmatically a safer alternative to findViewById.
Jake Wharton created ViewBinding while he worked at Google to save us from Databinding and KAPT - giving us type-safety and null-safety at IDE time (instead of compilation time). ๐
Why I don't like the typical data-domain-presentation split, having "both repositories and usecases", clean architecture (as it is generally done on Android) and mvi
TL;DR clean architecture is a code fashion trend where people copy code and hope for the best, nothing more.
\/
Google says they created Compose/Jetpack samples that are meant to show "best practices",
But then where is `savedStateHandle.saveable { mutableStateOf() }`?
According to this post on Reddit, using Jetpack Compose, it is extremely likely that if you are using the `val (value, setValue) = remember { mutableStateOf(..) }` way to declare a mutable state, then you are also introducing bugs that are hard to debug.
So I found this guide (on creating custom views using onDraw, and even how to define custom states for views that can be used from inside drawable selector). This is something that's been missing for a very long time.
I'm so happy to see the Kotlin 1.4.30 release!
Not only does it come with sealed interfaces, but it also fixes some performance problems you could run into with type inference.
I expect this to greatly increase IDE responsivity! Update your IDE plugin ๐ฅ
Google adds that passing the ViewModel to the RecyclerView is not good practice because it's tight couling between the adapter and the ViewModel
But then why do they pass a ViewModel to a Composable? ๐ค
"CommonsWare published a series of books on Android application development. All are available now under the Creative Commons BY-SA 4.0 License. All are available for free download as PDF, EPUB, or MOBI/Kindle editions, and some are available to read right from your Web browser."
Android UI development goalpost-moving in a nutshell:
- "Android UI dev is slow"
+ "Just use Compose bro"
- "I'm already using Compose, still slow"
+ "Just git gud bro"
- "That won't help 3-minute preview rendering"
+ "Just buy a MacBook Pro M1 bro"
- "Actually it doesn't help"
implementation "androidx.compose.ui:ui-util:$compose_version"
You should be using `fastForEach` on your Lists (and `fastMap`, `fastAll`, `fastAny`, `fastForEachIndexed`, `fastSumBy`, etc) inside Composable functions
I sure do scream each time I see
1.) top-level "domain" module
2.) UseCases that do nothing but delegate to a "Repository" that does nothing but call 1 suspend fun and that's it
3.) "Repository" interfaces in the "domain" module (if you have them, it's the public API of "data")
Google Maps Compose Integration development is inactive since March 30th 2023, while there are plenty critical bugs and crash issues opened.
Priorities on issues are no longer set, all issues after April are marked "triage me".
Is Google support dropped?
Must watch talk from Hadi Hariri and Kevlin Henney on:
- overengineering for the sake of adding complexity and not because it's needed ("clean arch")
- copypasting "solutions" that solve no real problems
- making software development seem more difficult
I can't believe I forgot about the "shotgun surgery" code smell, when I was talking about the "Android clean arch" that makes you put 1 responsibility in 5 classes and 3 "layers" in 3 modules,
And each time you need to make an edit, you have to edit every single one of them ๐
Interesting news, apparently now you can contribute to Room and WorkManager through Github, rather than only through the AOSP.
In fact, there seems to be a whole new Github mirror to AndroidX Jetpack. Now you can browse the Jetpack source code on Github.
Thanks to Android Studio Electric Eel, it's possible to find out that by following everyday samples, Jetpack Compose will end up in "recomposition hell" & poor performance.
To optimize for runtime performance, either pass function references, or remembering callbacks is needed.
I feel like we should appreciate `associateBy`, which allows you to easily transform an iterable (list, set, etc) into a Map, using a given property as a key to map against another prop
One of the nicest features of Kotlin really is the built-in collection extension functions ๐
Compose compiler metrics allow you to determine how many composable functions are restartable or skippable, depending on how many of its arguments are marked stable or immutable
Here's a good comment by Jake Wharton on why you should beware Mockito taking up too much responsibility, and accidentally hardcoding implementation details in unit tests. Or quoting his words, "Mockito is test cancer. Avoid."
I've been hearing complaints such as "LiveData is bound to the UI thread, so you should never use it in a Repository, because your mapping is always on the UI thread".
To counter this myth, here is today's extension function.
(Snippet with
@carbon_app
)
The 2022 Android Developer Roadmap supports 11 different world languages in README! ๐
English, Korean, Arabic, German, Spanish, Turkish, Bahasa Indonesia, French, Portuguese, Khmer, and Vietnamese.
Anyone can contribute to support your languages.
If you're planning to create a fully Compose app, consider looking at Appyx instead of Navigation-Compose.
I hear it already supports complex screen transitions, not just hard-coded Crossfade ๐
Who's excited for the new Simple-Stack 2.7.0 update? ๐
#androiddev
After a few days of coding, predictive back support (Android 14, targetSdk 34, android:enableBackInvokedCallback) is finally coming ๐
Migration path is provided from onBackPressed/HandlesBack, of course.
Using the new `bundle.getParcelable` released in Android T that takes a "Class" parameter is actually bugged, and you should NOT use it, as it crashes at runtime.
The fix will not be available in Android 13, therefore this will always remain a trap.
I updated my Fragment + Compose sample to align with recomposition best practices for optimal performance:
- screen layout composable is a top-level composable function, instead of a function of Fragment instance
- all input arguments are passed as State