3 Documentation
Aditya Borikar edited this page 2 months ago

Documentation

This page is intended to give a quick introduction into the Mercury-IM codebase and to help you get started contributing.

As described in the architecture overview, the app consists of multiple modules. This should help keep the code more modular and reusable.

Depending on what you want to change/add in the app you have to go to the right module.

If your change is only visual (for example you want to change a layout file, add or correct a translation or add a new screen) you should look at the app module, which contains Android related code. You can think of this module as merely an embedding of the core xmpp client module into the Android world.

Speaking of the core module, if your change adds support for an XMPP Extension Protocol or fixes a protocol related bug, your change probably belongs into this module. Think of the core module as the XMPP client without a UI. It contains everything else (message listeners, handler logic…), expect for persistence related stuff. Note: The core module MUST NOT depend on any Android-related code.

What a transition! The persistence module contains everything needed to persist information into storage. This includes definitions of data types (models) as well as definitions for data repositories which are used to access the data. If your change introduces new data that needs to be saved, these changes will need to go to the persistence module.

You may have noticed, that the persistence module merely contains interfaces and no real hands-on implementations. The reason for this is that the code should be platform independent. An Android specific implementation of the persistence module can be found in persistence-room which uses Androids Room database framework to implement Mercury-IMs database. If you touch persistence, you certainly also have to touch persistence-room.

Note: The persistence and persistence-room situation may change in the future. See #8 for more information.

Used libraries

Dagger2

As you can see, Mercury-IM consists of quite a number of modules and components. Haha! Modules, Components! Get it? If you don’t you are probably new to dagger. Dagger is used as the glue that glues repositories, activities, services etc. together.

It is a so called Dependency Injection framework. Let me try to explain dependency injection (di) as briefly as possible:

public class MyService {
    Algorithm algorithm; // <- algorithm is a dependency of the service

    public MyService() {
        this.algorithm = new ConcreteAlgorithm(); // bad, as now the service took responsibility for resolving his dependencies.
    }
}

// Now with "manual" dependency injection

public class MyService {
    Algorithm algorithm;

    public MyService(Algorithm _algorithm) {
        this.algorithm = _algorithm; // better. Now the dependency is "injected" by the whoever creates the Service.
    }
}

// Now with Dagger

public class MyService {
    @Inject
    Algorithm algorithm; // <- algorithm is now injected magically by dagger \o/

    ...
}

Thats basically it. I’d recommend reading some more on the topic though, as I left out most of the specifics. All you have to know is that most classes can have access to repositories and other singletons via @Inject annotations. This removes the neeed for tons of boilerplate code, as now you no longer have to create your classes by nesting dependecies en masse.

RxJava

RxJava is a framework for reactive programming on Java. Reactive programming can roughly be compared to asynchronous programming with callbacks and futures. And streams. Just on steroids.

RxJava provides multiple types of data sources which can emit items/events. Such sources can be subscribed to by consumers, which react to the events, hence the name.

In Mercury-IM rxjava is primarily used in the database layer to abstract and asynchron-ify database calls. That way access to the database does not block the UI thread and keeps the user interface responsive.

A prime example of rxjava usage in Mercury-IM is to keep the database and UI in sync. For that we can let the UI subscribe to the database and update the UI on changes. If we change the name of a contact (for example using another XMPP client), the roster change comes in via Smack. Mercury-IMs RosterStore will write the change into the database. Now comes the magic part: The database emits the change in form of a new ContactModel which is now picked up by the UI, which updates the UI elements accordingly. That way the changed contact name is instantly displayed!

RxJava can be used for even more though, so I expect it to be used in more places throughout the app.

LiveData

Very similar to rxjava, LiveData can be used to update UI elements automatically. Actually the main difference between LiveData and RxJava is, that RxJava is more powerful and comes with more tools, while LiveData is specialized for usage on Android. That goes as far as that it can only be used on Android.

Then why deal with it at all? LiveData comes with the HUGE advantage that it is lifecycle aware. That means, it automatically detects when the activity is paused or destroyed and unsubscribes its subscribers automatically in such case. That is important, as otherwise we would leak memory and risk NPEs when trying to update destroyed views.

Thats why in our ViewModel we take the Observables etc. from rxjava and convert them to LiveData objects, which are then used by Androids UI.

As you may have guessed by now, the usage of LiveData objects is limited to the app module only. In the core module we have to use rxjava instead.

Resources

That was a lot of information! More indepth blog posts and tutorials for all this can be found on this wiki site, where I collected all the useful stuff I came across while researching into theses topics. Feel free to extend with more information!