I was thinking of migrating our legacy code to Android Architectural Components.
But, it's a huge project and it will take lots of time, with impact on business, if I plan to migrate all at once.
But, as it's a Multi Module project. I have some queries:
Can I change some modules to Android Architectural Components without
affecting the main module ?
Is it possible to change some modules to Android Architectural Components using Kotlin ?
Need your suggestions.
For both the question's answer is yes. Android Architectural Components
some modules to Android Architectural Components you can use the component's in any module specifically without effecting any other module of your project example you can use Live Data only between few Fragment's of the module. similarly you can use ViewModel only in one Activity so Android Architectural Components is totally independent of the Module it can be used even only in a part of module also based on the need as i am using it in my project.
some modules to Android Architectural Components using Kotlin as
Android Architectural Components are supported both by Java and Kotlin so need to worry about that you can use it anyway Java or Kotlin
Related
I don't have a multiplatform application right now but I'd like to structure it in a way that would make it easy to turn it into one.
I have a Fragment/View which can use all Androidx/Android classes.
And I have a ViewModel and Repositories where I want to use the Paging3 library but it's from the Androidx package.
If I want them to be portable, do I have to use only my own classes and things available in Kotlin? (Like FlowState and other coroutines.)
I have built a code in Android Studio with Kotlin. I initially haven't set it up as a Kotlin Multiplatform Mobile project and I would like to bring it now also on iOS. Is there a way to "convert" it to a Kotlin Multiplatform Mobile at this stage? Thanks
This is a multi-step process:
You'll need to adapt your build configuration - change build.gradle.kts to a KMM setup. Examples you can find at PeopleInSpace and KaMPKit repos
You have to make your Android code platform agnostic in order to share pieces with iOS
The changes you need to make depends on how many Android dependencies you have, how much platform-specific code you wrote and how much you want to share with iOS.
I wouldn't underestimate how big of a refactor this might need, as there are loads of platform-specific things that as an Android devs can overlook (JUnit, File, Dates are just a few examples, where we commonly used JVM libs)
I'd recommend starting small, creating a shared module with a KMM configuration, then step-by-step moving things to shared
Reach out if you have more questions
Checkout this detailed video that explains this process https://www.youtube.com/watch?v=X6ckI1JWjqo
You would need to switch using Kotlin native libraries for common shared code, so depending on that, you might have more or less work to do.
On top of that, you would need to use strategies around dependency injection, common view model layer etc.
I'm almost finishing migrating my app to MVVM with databinding and livedata (still java though) and now I have much more than a decent architectured Android app (which I'm showing below). I'm happy with that, but would like to go one step further.
Talking about clean architecture, I'm trying to figure out how to do a proper separation of concerns in Android (database, business, services, etc).
I work in .net and in that platform, what you do to separate layers is to create a different proyect for each layer (database, bussiness, presentation) and then you reference them in the correct order, but projects are mostly independent one of the others.
In Android, and as far as I know, you have an app module and even though I have a nice package agrupation, all is "together" into the same project.
I'm not sure if this is the best approach to really follow clean architecture principles. I've heard about Dagger, heard you can create modules with it, but not sure if it is intended for what I'm trying to do.
Any help/hints about a good way to implement separation of concerns in Android?
My current app structure:
com
xxx
xxx
dto
class_1_dto.java
...
class_N_dto.java
helpers
helper_http.java
helper_json.java
helper_utils.java
helper_enum.java
helper_file.java
helper_smtp.java
helper_date.java
...
model
model_class_1
model_class_2
...
all_model_classes_linked_to_AWS_database
poco
some_poco_classes
repository
aws
IAWSDAO
AWS_Repository
...
all_stuff_related_to_AWS_database_query
local
model_class_1_repo
model_class_2_repo
...
all_stuff_related_to_SQLite_database_query
services
model_class_1_serv
model_class_2_serv
...
all_stuff_related_to_local_repos_query
ui
activities
activity_1
activity_1_viewmodel
activity_2
activity_2_viewmodel
...
activity_N
activity_N_viewmodel
component
custom_view_1
custom_view_2
...
helpers
view_helper_1
...
view_helper_N
assets
res
...
You can segregate your concerns like (app, core, network, service, repository) by making multiple modules. Just like 'app' is a module, you can create an independent module for each concern and you can use Koin for dependency injection between the modules.
For reference here is an example github repo:
https://github.com/Fahad-github/Bykea-CaseStudy-MusicApp
Square Inc. has presented it's internal modular architecture at Droidcon SF'19:
https://www.droidcon.com/media-detail?video=380843878
However, I'm a bit confused with some bullets. Could you please help me?
Why do they actually need :wiring modules? I find it adding complexity:
you get extra gradle module for each new feature
you have to make a sort of global injection into your Fragments somewhere in :app, because Fragments defined in :impl modules cannot access it's DaggerComponent, which is defined in :impl-wiring modules. :impl doesn't depend on :impl-wiring, because the dependency is reversed.
you cannot have an Android Dynamic Feature modules, because they should know about it's DaggerComponent in order to inject it's Fragment. But there is no way to do such injection from :app module, which is base-module for Dynamic Features.
so why :wiring modules at all?
One can merge :impl and :impl-wiring, or :fake and :fake-wiring together to eliminate all the issues mentioned above. And also, in :demo-apps one could just have a dependency on either :impl or :fake``, and not on :impl-wiring(or:fake-wiring```).
The creation of this type of modules is to separate even more. With this you generate an abstraction of the type of component you use (koin, dagger) and how. If the project is large, it makes sense to do it.
Currently I generate the following flow of dependencies between modules:
WARNING: Check the directionalities well.
:feature-A:open <- :feature-A:impl -> :feature-A:impl-wiring
:feature-A:impl-wiring -> :feature-A:impl, :feature-A:open
:app -> :feature-A:open, :feature-A:impl-wiring
I'm still not sure if app should depend on open and impl-wiring, or which app should only depend on open and open from impl-wiring.
Eventually, I came up with the following solution:
each feature consists of the following gradle-modules:
api
impl and fake
data:api
data:impl1 ... data:implN and data:fake
data:wiring
ui
demo
So, here api, impl and fake as usual, but I've my data layers separated. I bought myself that I need multiple different implementation of data layers sometimes, for example - if I develop Stock-Charts App, I could rely on Finnhub Open API or MBOUM API or provide fake implementation.
Thus I have data:api, data:implX. Indeed, data:api defines FeatureRepository interface (one or many) and data:implX provides actual implementation for them. In order to bind interface and implementation, I use data:wiring, which defines Dagger modules and component(s). In addition, I keep the same package names within each data:implX module in order to "write-once" the data:wiring module. And to replace one implementation with another, I just change a single line in data:wiring/build.gradle which states a sort of:
implementation project(":data:implA")
to
implementation project(":data:implB")
Also, to break the confusion mentioned in my original question, I introduce ui module, which contains some Views of a particular feature. Fragments go in demo (a standalone app to test feature) or in ui, they refer to viewModel which have some bindings ctor-injected from Dagger component of a feature. But the UI and library are separated here. Fragment instantiates a dedicated Dagger component that uses component dependencies to refer to feature's library bindings, such as interactor or repository etc.
So, to wrap up - separation between UI and business logic implementation (a "library") for each feature makes it possible to solve the issue. Feature's api declares an entry point to it's functionality as a library, and it's global access via Dagger multibindings from :app. So it can be used further in any :demo, :ui and :dynamic-feature.
I'm a little confused about the advantages and disadvantages of using Android KTX vs Anko. Because both libraries are trying to achieve the same end goal, and the line between them it's getting a little bit blurry to the point, in some cases, the same functionality is available in both libraries.
I will be very thankful if you help me to clarify the mission of each one, and their use cases.
Thanks in advance!
Anko is a project JetBrains started while developing Kotlin and making it relevant for Android. I'd qualify it as an early production-ready showcase of Kotlin possibilities.
Anko is well known for Anko layouts, but also has some extensions for Android development in Anko Commons, and also a few other modules like SQLite.
However, Anko libraries have accumulated a significant number of methods updates after updates, which today make the library relatively heavyweight when you are limited to 65K methods per dex file (I prefer staying with a single one, for apk size and performance reasons).
Anko commons provides extensions for Android, so it's similar to Android KTX in a way, but it's not as well integrated and organized (packages and artifacts wise) as Android KTX which is now part of AndroidX, which is part of Android Jetpack. Making the libraries smaller, and more loosely coupled is part of the Android Jetpack / Android X philosophy BTW.
So Android KTX, is clearly the future, and I see no reason to not jump in the ship, or rather, not letting it jump in your Android projects.
Also, as you yourself pointed out, future Anko versions will deprecate (and probably finally remove) overlap with Android KTX, to provide only features that are not in AndroidX.
Includes a shameless plug:
Since you're talking about Anko, if Anko layouts got your attention, but you experienced struggles with them (especially when interacting with custom or third-party views), I'd recommend you to check out Views DSL in Splitties, which is more flexible than Anko layouts, and very lightweight. The other modules may also interest you. I started this project to leverage Kotlin features in my Android projects at work and at home.
You've not asked about it, but here's my take on Anko coroutines:
I find the bg { … } extension confusing. I prefer to use kotlinx.coroutines with the Android artifact, using launch, withContext, etc, along with Dispatchers.IO.
However, the Anko coroutines listeners (e.g. onClick that can suspend) are not a bad idea IMO.
Anko is a Kotlin library from JetBrains. It shares the goals with Android KTX of making your life as an Android developer easier and making your code more readable and pleasant to use. Android KTX and are Anko are similar but not quite the same.
Differences Between Anko and Android KTX
They have common goals but with different scopes in mind. The mission of KTX is to bring idiomatic APIs to Kotlin users. KTX does not intend to add new functionality to the existing Android APIs.
Anko has a wider scope, and this gives it the flexibility to innovate and create new features
Deciding When to Use Anko or Android KTX
Generally speaking, Anko and Android KTX cover different parts of the Android API, and there’s no reason you can’t use both in your project. Investigate each one individually and use either as much as you want in your projects!