Android Code Architecture - Best Practices
At the moment of writing this document the recommended architecture for Android Applications is MVVM https://www.garudax.id/pulse/core-code-architectures-toma-velev/
Dependency Injection - Dagger 2
- Necessary steps to integrate dagger in new app:
ext.dagger_version = "2.11" //update with any upcoming version
implementation "com.google.dagger:dagger:$dagger_version"
implementation "com.google.dagger:dagger-android:$dagger_version"
implementation "com.google.dagger:dagger-android-support:$dagger_version"
//for kotlin replace with kapt
annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version"
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
Attach AppInjector in the class extending android.app.Application and mark in what kind of activities and fragments will be injectable:
DaggerAppComponent.builder().application(app) .build().inject(app);
app.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() { … });
AndroidInjection.inject(activity); // activities
AndroidSupportInjection.inject(f); // fragments
The convention is to put the dependency injection stuff In a package ““app-package”.di” (example - com.example.myapp.di)
Model
Currently the recommended and provided by Google ORM Library is Room.
import android.arch.persistence.room.*; //Entity, ColumnInfo(name = "someName"),
For Remote Objects provided by Google Library is GSON with some extra annotations for fixing differences:
import com.google.gson.annotations.SerializedName;
@SerializedName("someProperty")
import android.arch.persistence.room.Ignore;
@Ignore - For properties that are not supposed to be saved
Db
In Room the developer’s code in the database layer are Interfaces:
@Dao
public interface SomeDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
//@Update
//@Query(“SELECT * from Some”)
//@Delete
void someOperation(Some some);
}
+ a Database Initialization class that exposes the interfaces and enumerates the models
@Database(entities = {Some.class}, version = 1)
@TypeConverters()//if any
public abstract class MyAppDb extends RoomDatabase {
abstract public SomeDao someDao();
}
- Where you need the database (probably called only once):
Room.databaseBuilder(app, MyAppDb.class, "myapp.db").build()
Repositories - Db And Rest
The Repository layer does most of the IO work - working with the database and the network. That is why it uses the Executor API to move away the work from the UI Thread
https://developer.android.com/training/multiple-threads/
*Advanced Json Tip - if some json request is too big and it consumes too much memory, use android.util.JsonReader. It is tricky because you must know the json scheme, but it does not lift the whole json object graph + json string in the memory.
*Advanced Tip Connectivity Tab from docummentation: https://developer.android.com/training/efficient-downloads/efficient-network-access
UI + View Model
The ViewModel is recommended to contain LiveData instead of Data.
The View is recommended to only respond to data changes and pass user interaction to the ViewModel
UI
A recommended library for Android User Interface Development is Data Binding:
https://developer.android.com/topic/libraries/data-binding/#kotlin
Start using it with
dataBinding {
enabled = true
}
In the build.gradle and a <layout> as root element in the XML
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable name="varName" type="VarType" />
</data>
<ConstraintLayout... /> <!-- UI layout's root element →
</layout>
It can
- All Ids are referenceable in the code with generated variables (this is probably obsolete with Kotlin)
- Populate UI Views Data directly from a model (passed with a variable)
- Use @BindingAdapter(“property”) for transforming and setting the values differently and custom to the properties of the views (you have practically full control over how the data is passed to the full).
- For most of the cases Glide library will be enough for image processing coming from back-end. For app for billions Google recommends several techniques that are also dependent from the back-end systems.
- https://developer.android.com/docs/quality-guidelines/building-for-billions-connectivity - load different images depending from screen size, Internet speed, target space from screen (dimensions) of the images.. etc
ConstraintLayout - is the recommended Layout so it has it as root some view and maximum second level nesting - instead of Layout in Layout in Layout ....
Cool Tool Attribute: https://developer.android.com/studio/write/tool-attributes
Notifications
Read the Notification Section, because Google updates it when new OS version are released (even not final) https://developer.android.com/guide/topics/ui/notifiers/notifications
Background Work
https://developer.android.com/training/best-background
https://developer.android.com/topic/performance/background-optimization
https://developer.android.com/topic/libraries/architecture/workmanager/ (currently not final Yet)
GPS
Read the User Location Section, because Google updates it when new OS version are released (even not final) https://developer.android.com/training/location/
If you contact me, I could send you a version of my GeneratorApp: http://tomavelev.com/GeneratorApp/ that outputs many of the above code components and modules. It is not released officially mostly because the new architecture breaks all the other (non-Room) ORMs.
TODO: Very soon I'll create some Empty from concrete models Starter Java and Kotlin Project Templates with all - Dependency Injection, Data Binding, Room, ViewModel, Retrofit, etc stuff. Stay tuned.
how to integrate LiveData with Rx.Android ? do you have any idea ?