Android Code Architecture - Best Practices
https://developer.android.com/jetpack/ (New, old and incoming stuff)

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 ?

To view or add a comment, sign in

More articles by Toma Velev

Others also viewed

Explore content categories