https://github.com/strvcom/dundee
Android App Architecture Showcase
https://github.com/strvcom/dundee
android architecture data-binding mvvm repository-pattern
Last synced: 12 months ago
JSON representation
Android App Architecture Showcase
- Host: GitHub
- URL: https://github.com/strvcom/dundee
- Owner: strvcom
- License: apache-2.0
- Created: 2017-12-14T13:33:42.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2018-03-20T07:27:27.000Z (about 8 years ago)
- Last Synced: 2025-03-23T20:22:19.531Z (about 1 year ago)
- Topics: android, architecture, data-binding, mvvm, repository-pattern
- Language: Kotlin
- Homepage:
- Size: 972 KB
- Stars: 13
- Watchers: 13
- Forks: 10
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
dundee
==============
[](https://circleci.com/gh/strvcom/dundee)
(R.layout.activity_main)
//...
// then in onCreate():
vmb.viewModel.doSomething()
vmb.binding.myView.doSomethingElse()
```
_see MainView.kt class for more_
View Class (Activity/Fragment) does not have to implement or extend anything special. In case of a Fragment, you still need to override the `onCreateView()` method though. But you can just return `vmb.rootView`.
ViewModel needs to extend Architecture Components `ViewModel` or `AndroidViewModel`.
If you want to instantiate ViewModel yourself, you can provide a lambda functions that provides the instance.
This function will be called just in time when you have access to Intent and other data within the Activity/Fragment so you can pass any parameters to your ViewModel constructor:
```kotlin
private val vmb by vmb(R.layout.activity_sign_up) { SignUpViewModel(intent.getStringExtra(EXTRA_DEFAULT_EMAIL), intent.getStringExtra(EXTRA_DEFAULT_PASSWORD)) }
```
ViewModels hold data exclusively within LiveData. ObservableFields were replaced by MutableLiveData which can be directly consumed by the View. Once you use LiveData instance within a layout file DataBinding mechanism will observe
the data with a proper LifecycleOwner - Activity or Fragment.
View communicates with ViewModel directly via public API. ViewModels communicate with View via LiveData or EventLiveData - see `SignUpViewModel` for an example
Dependency Injection
--------------------
We use basic DI mechanism consisting of two kotlin functions. First you need to call `provide { Gson() }` or `provideSingleton { Gson() }` somewhere (see `DIModule.kt`) and then to inject the dependency into a property
just use `val gson by inject()`. You can also use different scopes for the DI by providing String scope name to both functions.
In your test suite you can use different module which will provide different or mock variants of your classes.
Repository Pattern
------------------
Repository pattern used in this project is based on [this article](https://developer.android.com/topic/libraries/architecture/guide.html) but heavily modified. The idea is that both network calls and database operations
return data in form of LiveData. NetworkBoundResource takes care of merging those two data sources into single LiveData using `MediatorLiveData`. It can manage both simple (not cached) network calls as well as automatically cached calls.
Data is always wrapped within a `Resource` class adding status, message and potentially a Throwable instance. See `repository.kt` for more and `DashboardViewModel` with `TickerLiveData` for an example.
To be able to receive data from REST API within a LiveData there is a custom Retrofit `CallAdapterFactory` which transforms `Call` to `LiveData>`
Shared Preferences Delegate
---------------------------
Shared Preferences Delegates massively simplifies work with Android SharedPreferences. Just declare a property using the delegate and read/set its value. It will be automatically stored within SharedPreferences of your choice.
Example:
```kotlin
var accessToken by sharedPrefs().string() // property name will be used as the key
var userEmail by sharedPrefs().string(key = "email")
var hasReadConditions by sharedPrefs().boolean(false)
//...
// then
accessToken = "asd328y0823hdkajshd238"
if (!hasReadConditions){
//...
hasReadConditions = true
}
```
If you rather work with LiveData, there are delegates for that as well. When active, the LiveData listens to SharedPreferences changes for the given key and gets updated automatically. It supports setting value as well so
you can connect it to the layout directly:
```kotlin
// in ViewModel
var userName by sharedPrefs().stringLiveData()
```
```xml
```
Other Tools
-----------
**Logs** - multiple logging functions - see `log.kt`
**LiveData** - `LiveData.map()`, `LiveData.switchMap()` extension shorthands, `EventLiveData` for delivering one-time events to View, `mutableLiveDataOf()` shorthand, etc. - see `livedata.kt`
**Async** - `doAsync {}` and `uiThread {}` functions to simplify background operations
Author
------
Jakub Kinst (jakub.kinst@strv.com)
Leos Dostal (leos.dostal@strv.com)