在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):Lajesh/clean-architecture-kotlin开源软件地址(OpenSource Url):https://github.com/Lajesh/clean-architecture-kotlin开源编程语言(OpenSource Language):Kotlin 100.0%开源软件介绍(OpenSource Introduction):Clean Architecture for Enterprise Mobile ApplicationIt has been over an year i am using Clean architecture for enterprise mobile applications. However i feel now the time has arrived to update the architectural template as my existing boilerplate is extensively using Rxjava (I am a big fan of Rxjava though :)). Even i can't believe my self as i am moving from RxJava to Kotlin Coroutines. I was exploring coroutine and flow since last couple of months, and i am convinced enough to make a shift from Rxjava to Coroutine and flow. This boilerplate project is created to serve as an architectural template which can be used for highly scalable enterprise mobile applications. Below are the design considerations that i have taken while creating the boilerplate project.
Keeping all these principles in mind, Clean architecture will be a great fit for any software application. Having that said Clean architecture will not be appropriarte for every project. So its down to you to decide whether or not it fits ur needs. ArchitectureThe architecture of the application strictly complies the following points.
ModulesThe following diagram represents the various module and their relationship.
Architecture componentsThis boilerplate is extensively using architecture components such as databinding, ViewModel, Livedata ,etc. The template is made in such a way that the ViewModel shouldn't know anything about Android. This improves testability, leak safety and modularity. ViewModels have different scopes than activities or fragments. While a ViewModel is alive and running, an activity can be any of its lifecycle states. Activities and Fragments can be recreated again while the ViewModel is unaware. So that merely means ViewModel has a longer lifecycle, so passing a reference of view to a ViewModel is a serious risk. Lets assume the ViewModel requests data from the network and the data comes back some times later. May be at that time the view reference might be destroyed or might be an old activity thats no longer visible, in that case it might generate a memory leak and possibly a crash. Livedata and DatabindingI have been using databinding extensively throughout all my projects and i am a great fan of it. Databinding brings a balance between View and ViewModel (Someone might not agree with me on this :D) When i was starting this boilerplate, there was a confusion whether to go with databinding or viewbinding, both are for the similar purpose. The additional advantage of databinding is that you can bind data directly in your view xml, so that means you don't need to access a view in the Fragment / Activity to set the data which eliminates lots of boilerplate code. This is one of the main reason why i chose databinding over viewbinding. If you are using databinding in ur project, you can make sure that your view class will not grow beyond a size as you are distributing your logic with view xml, View class and ViewModel. Since Google has introduced architectural components, LiveData is the solution for reactive stream and its lifecycle aware too. But in this template i am using a combination of two reactive streams which is Kotlin Flow and LiveData. Kotlin flow is being used a reactive stream in my business layer and the same has been converted to LiveData in the ViewModel to support databinding. Kotlin flow support for databinding is in alpha now, once that becomes stable we can remove LiveData completely. Kotlin CoroutinesAs said earlier i was using Rxjava quite a lot in most of my projects , but i liked the structured concurrency in coroutines very much. Kotlin coroutine with flow can be great solution for multithreading and reactive streams. Below diagram represents the pattern that we follow in this architectural template. Points to note:
LiveData is an observable data holder that is lifecycle aware. It helps with problems or issues which circles around lifecycle of a component. Additionally, it can be updated from any thread. This brings the next question — Why do we need Flow? Can’t we use either Flow or LiveData or Do we need both?Why Flow over LiveDataLiveData was never designed to be fully-fledged reactive control. It’s good for one shot operation where we get all the data in one shot. But if you are getting a data stream or you are getting data in multiple packets, flow would be the right choice. In case of LiveData, if you want to perform certain transformation, by default they would run on main thread. so if you have to dispatch the transformation on different thread, you probably would want to use suspend functions. Additionally, LiveData has a very small set of built-in operators while flow comes up with lots of them. Why LiveData over FlowLiveData caches the result. Let’s say, you fetch a result and it is stored in a LiveData object. Now user rotates the device to landscape mode, the activity will be recreated. Since the result was already fetched while device was in portrait mode, LiveData would emit the same result again so we would not need to refetch the results. In case of flow, it does not cache the result so in the same scenario we have to refetch the results, which is why it’s suggested to use LiveData between the view and view model layer. LiveData takes care of data binding which means every-time there is data change, it can be observed in the view XML itself directly and the object does not need to observed in UI class of component. This is a kind of add-on in LiveData. Golden rules of ViewModel and LiveData
How navigation works in a multi-modular project ?As you might have noticed, the boilerplate is based on multi modular architecture. There is an app module(which is the main module), and this app module depends on various feature modules. There were lots of unknowns when i started thinking about how to use navigation jetpack in a multimodular project. Thanks to the awesome android community, i have referred lots of articles and finally i am able to find answer to all my questions. Let me detail about the questions that i had in my mind when i was thinking about the same ?
Design ConsiderationI have decided to use nested navigation graph approach. So here i have a main navigation graph, which is located in the app module and then i have individual navigation graph for each feature modules. The main navigation graph includes all other child navigation graphs. We have 2 feature modules here, an onboarding module and a profile module. The onboarding module contains two fragments such as Splash and Login. Similarly the profile module contains Profile and Edit profile frgments. How to navigate to other modules navigation graph ?The answer to the questions is through IDs. You can define a unique resource id in an xml. Using the name you provide in element, the android developer tools create a unique integer in your projects R.java class, which you can use as an identifier for application resources or a unique integer for use in application. So here in our context we need to navigate from our LoginFragment(which belongs to onboarding feature module) to ProfileFragment (start destination of profile feature module), since both of these fragment belongs to different feature module, we can't directly reference the one in profile feature module from onboarding. But using the ID, we can refer to another navigation graph from our onboarding module. As you can see above, i am linking that particular id as the destination in the action tage. The specific id is mentioned in the ids.xml like below. The same id has been used as an identifier for the nav_graph_profile, like below. So when you are referring this ID as a denstination, it will link the corresponding navigation graph and will be navigated to the start destination of that particluar graph. In this case it will be profileFragment. How to go back to a fragment which belongs to a different feature module ?Lets suppose if we want to go back to Login screen from Edit profile screen which belongs to the profile feature module. In this situation also we an use id. onboarding feature moduleHow to navigate to a fragment which belongs to another feature module, but that's not the start destination ?Lets take an example, think of a case where we have to navigate to edit profile fragment from Login screen. When you have nested navigation graphs, deeplinking is the way for such use cases. Since we have to navigate to edit profile screen, we need to define a deeplink to that particular destination like below. onboarding feature moduleHow to share data between fragments in a Single activity architecture ?Before architectural components, we have used bundles for data sharing between fragments and after the introduction of AAC, we have created viewModel in the activity scope and used to keep all the data there which we want to share between fragments. This pattern is Okay, if you are designing your applicatio in such a way that you will be creating seperate activities based on each flow and at the end you will be having multiple shared viewmodels instead of a single one which holds all the data. But here the Navigation Jetpack enforces single activity pattern, so we should not create multiple activities anymore. In that case, can we have a single shared viewmodel and hold everything there. Of course, No. If you are thinking in that way you don't even need a shared viewmodel, you can simply create singleton class and keep everything there. So the best practice here is to create a ViewModel that's scoped to a navigation graph, enabling you to share UI-related data between the graph's destinations. Any ViewModel objects created in this way live until the associated NavHost and its ViewModelStore are cleared or until the navigation graph is popped from the back stack. Ktx provides a new sweet extension called navGraphViewModels for the same. So lets say for example if you want to share data between fragments in the onboarding module, you can create a viewModel scoped to its navigation graph like below.
Tech stack
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论