Android MVVM (Architecture)

Help us to keep this website almost Ad Free! It takes only 10 seconds of your time:
> Step 1: Go view our video on YouTube: EF Core Bulk Extensions
> Step 2: And Like the video. BONUS: You can also share it!

Remarks

Syntax quirks with DataBinding

When binding a viewModel function to a property in xml certain function prefixes like get or is are dropped. Eg. ViewModel::getFormattedText on the ViewModel will become @{viewModel.formattedText} when binding it to a property in xml. Similarly with ViewModel::isContentVisible -> @{viewModel.contentVisible} (Java Bean notation)

The generated binding classes like ActivityMainBinding are named after the xml they're creating bindings for, not the java class.

Custom Bindings

In the activity_main.xml I set the textColor attribute on the app and not the android namespace. Why is that? Because there is a custom setter defined for the attribute textColor that resolves a ColorRes resource id send out by the ViewModel to an actual color.

public class CustomBindings {

    @TargetApi(23)
    @BindingAdapter({"bind:textColor"})
    public static void setTextColor(TextView textView, int colorResId) {
        final Context context = textView.getContext();
        final Resources resources = context.getResources();
        final int apiVersion = Build.VERSION.SDK_INT;
        int color;

        if (apiVersion >= Build.VERSION_CODES.M) {
           color = resources.getColor(colorResId, context.getTheme());
        } else {
            color = resources.getColor(colorResId);
        }

        textView.setTextColor(color);
    }

}

For details on how this works check DataBinding Library: Custom Setters

Wait...there is logic in your xml!!!?

You could argue that the things I do in xml for android:visibility and app:textColor are wrong/anti-patterns in the MVVM context because there is view logic in my view. However I would argue it is more important for me to keep android dependencies out of my ViewModel for testing reasons.

Besides, what really does app:textColor do? It only resolves a ressource pointer to the actual color associated with it. So the ViewModel still decides which color is shown based on some condition.

As for the android:visibility I feel because of how the method is named it is actually okay to use the ternary operator here. Because of the name isLoadingVisible and isContentVisible there is really no doubt about what each outcome should resolve to in the view. So I feel it is rather executing a command given by the ViewModel than really doing view logic.

On the other hand I would agree that using viewModel.isLoading ? View.VISIBLE : View.GONE would be a bad thing to do because you are making assumptions in the view what that state means for the view.

Useful Material

The following resources have helped me a lot in trying to understand this concept:



Got any Android Question?