Repository that showcases 3 Android app architectures: "Standard Android", MVP and MVVM. The exact same app is built 3 times following the different patterns.

Related tags

MVVM/MVP archi
Overview

Archi

This repository showcases and compares different architectural patterns that can be used to build Android apps. The exact same sample app is built three times using the following approaches:

  • Standard Android: traditional approach with layouts, Activities/Fragments and Model.
  • MVP: Model View Presenter.
  • MVVM: Model View ViewModel with data binding.

The App

The sample app displays a list of GitHub public repositories for a given username. Tapping on one of them will open a repository details screen, where more information about the repo can be found. This screen also shows information about the owner of the repository.

Screenshots

Libraries used

  • AppCompat, CardView and RecyclerView
  • Data Binding (only MVVM)
  • RxJava & RxAndroid
  • Retrofit 2
  • Picasso
  • Mockito
  • Robolectric

Standard Android

The /app directoy contains the implementation that follows the traditional standard Android approach. This is a couple of layout files, two Activities and the model. The model is exactly the same for the three implementations and it contains: Repository, User and a retrofit service (GithubService).

With this approach, Activities are in charge of calling the GithubService, processing the data and updating the views. They act kind of like a controller in MVC but with some extra responsibilities that should be part of the view. The problem with this standard architecture is that Activities and Fragments can become quite large and very difficult to tests. Hence why I didn't write any unit test for this case.

MVP - Model View Presenter

In /app-mvp you will find the sample app implemented following this pattern. When using mvp, Activities and Fragments become part of the view layer and they delegate most of the work to presenters. Each Activity has a matching presenter that handles accessing the model via the GithubService. They also notify the Activities when the data is ready to display. Unit testing presenters becomes very easy by mocking the view layer (Activities).

MVVM - Model View ViewModel

This pattern has recently started to gain popularity due to the release of the data binding library. You will find the implementation in /app-mvvm. In this case, ViewModels retrieve data from the model when requested from the view via data binding. With this pattern, Activities and Fragments become very lightweight. Moreover, writting unit tests becomes easier because the ViewModels are decoupled from the view.

License

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Comments
  • Repository is not loaded, keyboard is not shown

    Repository is not loaded, keyboard is not shown

    I installed all three applications (app, app-mvp, app-mvvm) on an Android emulator. When I click into the input field to enter the GitHub user name no keyboard is shown. After entering the user name via the keyboard of my computer I press Enter but nothing happens.

    archi-mvvm

    opened by johnjohndoe 7
  • [Question] What is the best way to mock presenters?

    [Question] What is the best way to mock presenters?

    Hey! First of all, thank you for a great sample! I have a question according to presenters mocking. Some time I go I adopted architecture proposed by @hitherejoe in his Android-Boilerplate project. He is mocking his dependencies for Espresso tests by providing different dagger components and looks like this approach doesn't suit well for your MVP example, because the simplest way - just to mock presenter instead of your app dependencies. So, what is the best way to do it in your opinion? I will much appreciate your answer. Thank you!

    question 
    opened by geralt-encore 4
  • notifyDataSetChanged() and RepositoryAdapter.setRepositories()

    notifyDataSetChanged() and RepositoryAdapter.setRepositories()

    I just noticed that the call of notifyDataSetChanged() is not inside the setRepositories() method of RepositoryAdapter.

    Is there a specific reason for this choice?

    opened by leinardi 2
  • Update build for version 1.5 of Android Gradle plugin.

    Update build for version 1.5 of Android Gradle plugin.

    The MVVM example would not build for me in most recent Android studio. I am not sure whether I did something wrong, but it looks like version 1.5 of the gradle plugin has more natural support for databinding, and this patch makes use of that.

    opened by vprus 1
  • Activity/Fragment in Android MVVM with data binding

    Activity/Fragment in Android MVVM with data binding

    What is the role of Activity/Fragment in MVVM? In the app-mvvm, activity is located in the activity package. So the author treat them as part of View of MVVM.
    If activity/fragment treated as View, all the business code should be located in the VM? If so, the new VM just treat as original activity/fragment without any lifecycle calls because the VM consists of view operation and busyness operation.

    question 
    opened by peacepassion 1
  • Discussion: Android Native Frameworks & Tools Review

    Discussion: Android Native Frameworks & Tools Review

    This is not an issue. I apologize for using this medium but GitHub doesn't leave much choice for communication. Please feel free to close the issue at any time

    I did a small research on the current Android RAD tools and frameworks. I included your project and I felt it's only fair to inform you and all the other projects generous developers of it: http://andyonwheels.github.io/Android-Native-Frameworks-Review/

    I hope that you see benefit from looking at what others are doing and such. If you have any feedback please do let me know.

    I'm also trying to gauge the interest of the community in having/building something on a bigger scale. Not sure what that should be so I built ~~an app~~ a survey for it. I hope experienced Android devs such as yourself would take a look at. Thank you.

    opened by SandNerd 0
  • MVVM Replace namespace android:visibility with app:visibility

    MVVM Replace namespace android:visibility with app:visibility

    Apparently when using visibility with data binding the app namespace should be used instead of android so that Android Studio stops showing it as an error.

    https://code.google.com/p/android/issues/detail?id=186266

    opened by ivacf 0
  • MVVM - store Picasso custom target in a field

    MVVM - store Picasso custom target in a field

    Picasso keeps a weak reference to the target so it needs to be stored in a field so we prevent it from being collected by the GC.

    Possibly it's worth changing the way the image is loaded with data binding and use BindingAdapter instead of a custom picasso target.

    opened by ivacf 0
  • Error loading from repository

    Error loading from repository

    Stack on Android 4.4 (API 19)

    03-08 00:38:55.273 14623-14623/uk.ivanc.archimvvm E/MainViewModel: Error loading GitHub repos 
                                                                       javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x53757e30: Failure in SSL library, usually a protocol error
                                                                       error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version (external/openssl/ssl/s23_clnt.c:744 0x5363ad74:0x00000000)
                                                                           at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:449)
                                                                           at okhttp3.internal.io.RealConnection.connectTls(RealConnection.java:239)
                                                                           at okhttp3.internal.io.RealConnection.establishProtocol(RealConnection.java:196)
                                                                           at okhttp3.internal.io.RealConnection.buildConnection(RealConnection.java:171)
                                                                           at okhttp3.internal.io.RealConnection.connect(RealConnection.java:111)
                                                                           at okhttp3.internal.http.StreamAllocation.findConnection(StreamAllocation.java:187)
                                                                           at okhttp3.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:123)
                                                                           at okhttp3.internal.http.StreamAllocation.newStream(StreamAllocation.java:93)
                                                                           at okhttp3.internal.http.HttpEngine.connect(HttpEngine.java:296)
                                                                           at okhttp3.internal.http.HttpEngine.sendRequest(HttpEngine.java:248)
                                                                           at okhttp3.RealCall.getResponse(RealCall.java:243)
                                                                           at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:201)
                                                                           at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:163)
                                                                           at okhttp3.RealCall.execute(RealCall.java:57)
                                                                           at retrofit2.OkHttpCall.execute(OkHttpCall.java:174)
                                                                           at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$RequestArbiter.request(RxJavaCallAdapterFactory.java:171)
                                                                           at rx.Subscriber.setProducer(Subscriber.java:211)
                                                                           at rx.Subscriber.setProducer(Subscriber.java:205)
                                                                           at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:152)
                                                                           at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:138)
                                                                           at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:50)
                                                                           at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
                                                                           at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:50)
                                                                           at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
                                                                           at rx.Observable.unsafeSubscribe(Observable.java:8666)
                                                                           at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94)
                                                                           at rx.internal.schedulers.CachedThreadScheduler$EventLoopWorker$1.call(CachedThreadScheduler.java:220)
                                                                           at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
                                                                           at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
                                                                           at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                                                                           at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
                                                                           at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
                                                                           at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
                                                                           at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
                                                                           at java.lang.Thread.run(Thread.java:841)
                                                                       	Suppressed: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x53757e30: Failure in SSL library, usually a protocol error
                                                                       error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version (external/openssl/ssl/s23_clnt.c:744 0x5363ad74:0x00000000)
                                                                       		... 35 more
                                                                       	Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x53757e30: Failure in SSL library, usually a protocol error
                                                                       error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version (external/openssl/ssl/s23_clnt.c:744 0x5363ad74:0x00000000)
                                                                           at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
                                                                           at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:406)
                                                                           		... 34 more
                                                                        Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x53757e30: Failure in SSL library, usually a protocol error
                                                                       error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version (external/openssl
    03-08 00:39:24.683 9240-9240/com.touchtype.swiftkey E/FullInputEventModel: onStartInput event aborted: com.touchtype.keyboard.h.q: could not obtain extracted text (class com.touchtype.keyboard.h.q)
    03-08 00:39:24.693 9240-9240/com.touchtype.swiftkey E/FullInputEventModel: onStartInputView event aborted: com.touchtype.keyboard.h.q: Could not create reset composing text event (class com.touchtype.keyboard.h.q)
    03-08 00:39:24.713 215-10813/? E/audio_a2dp_hw: adev_set_parameters: ERROR: set param called even when stream out is null
    03-08 00:39:24.963 935-1014/system_process E/MediaFocusControl: Error updating focussed RCC to RCD 
                                                                    java.util.EmptyStackException
                                                                        at java.util.Stack.peek(Stack.java:57)
                                                                        at android.media.MediaFocusControl.registerRemoteControlDisplay_int(MediaFocusControl.java:2203)
                                                                        at android.media.MediaFocusControl.registerRemoteController(MediaFocusControl.java:217)
                                                                        at android.media.AudioService.registerRemoteController(AudioService.java:4365)
                                                                        at android.media.IAudioService$Stub.onTransact(IAudioService.java:614)
                                                                        at android.os.Binder.execTransact(Binder.java:404)
                                                                        at dalvik.system.NativeStart.run(Native Method)
    
    opened by Sans84 0
  • View and Model are not completely separated.

    View and Model are not completely separated.

    你好,我认真看了你的代码,写的很棒 但是存在一个问题 MainActivity中的 adapter.setRepositories(repositories); MVP和MVVM中,View和Model都没有完全分离,我认为这样是有问题的,我们无法随意替换View或Model

    Hello, I've really read your code, and it's great But there is a problem MainActivity中的 adapter.setRepositories(repositories); In MVP and MVVM, View and Model are not completely separated. I think that's a problem, and we can't replace View or Model at will

    opened by KaiXuan666 0
  • [Question] Strange way to get reference the Application

    [Question] Strange way to get reference the Application

    Thanks for sharing this repo archi.

    This is unlikely related to the MVVM design pattern but just want to make sure I'm not missing anything important.

    Why do you do: MainViewModel.java

    private void loadGithubRepos(String username) {
       // ...
       ArchiApplication application = ArchiApplication.get(context);
       // ...
    }
    

    why not simply:
    MainViewModel.java

    private void loadGithubRepos(String username) {
       // ...
       ArchiApplication application = (ArchiApplication) context.getApplicationContext();
       // ...
    }
    

    (I tried it and the app runs just fine) Is it to prevent memory leak or sth? I can't seem to get my head around it Sorry for the noob question

    opened by ericntd 0
  • Move common model code into library project

    Move common model code into library project

    There's a bunch of duplicated code in each of the projects, by moving it into its own library project we can share the common code amongst all three apps.

    opened by jonathan-caryl 0
  • MVVM: List of repositories is lost when the screen is rotated

    MVVM: List of repositories is lost when the screen is rotated

    I'm focused on the app that implements MVVM, using it as an example to help in building my own app, and I see that the list of repositories is not persisted when the activity is killed and recreated when the device is rotated.

    How would you accomplish persisting the list of repositories when the device is rotated?

    opened by RothAndrew 1
Owner
Iván Carballo
Iván Carballo
An android app built using Kotlin following Multi-Module Clean Architecture MVVM

RickyandMorty An android app built using Kotlin that consumes RickyadMorty API to display characters.It has been built following Clean Architecture Pr

Kibet 14 Sep 2, 2022
A simple app that consumes The GitHub APIs to display github users. The aim was to learn about different jetpack libraries, built with MVVM pattern.

A simple app that consumes The GitHub APIs to display github users. The aim was to learn about different jetpack libraries, built with MVVM pattern.

Odhiambo Brandy 4 Apr 15, 2022
Group Messaging Chat (Discord Clone :eyes:) App Using Firebase Cloud-Firestore following MVVM Architecture

Nit Talk Nit Talk is a Group Chat Messaging (Discord Clone) App based on Modern Android Application tech-stacks and MVVM architecture. Techs Used ?? K

Rohit Sharma 27 Jul 22, 2022
Moxy is MVP library for Android

Moxy This Moxy repository is deprecated and no longer supported. Please migrate to the actual version of the Moxy framework at Moxy communuty repo. De

Arello Mobile 1.6k Dec 1, 2022
This repository contains a detailed sample app that implements MVVM architecture using Hilt, Coroutines, Retrofit and Compose

Saber News App sample project to explain how to build solid, clean architected App using MVVM and repository architecture Techniques Kotlin Clean arch

null 1 Dec 26, 2021
A sample project in Kotlin to demonstrate AndroidX, MVVM, Coroutines, Hilt, Room, Data Binding, View Binding, Retrofit, Moshi, Leak Canary and Repository pattern.

This repository contains a sample project in Kotlin to demonstrate AndroidX, MVVM, Coroutines, Hilt, Room, Data Binding, View Binding, Retrofit, Moshi, Leak Canary and Repository pattern

Areg Petrosyan 39 Nov 5, 2022
A full-featured framework that allows building android applications following the principles of Clean Architecture.

EasyMVP A powerful, and very simple MVP library with annotation processing and bytecode weaving. EasyMVP eliminates the boilerplate code for dealing w

null 1.3k Nov 19, 2022
JeTaxi is built on Clean Architecture-MVVM with Kotlin and follows modern android development trends.

JeTaxi is built on Clean Architecture-MVVM with Kotlin and follows modern android development trends. Also, It uses some of Jetpack and popular libraries. These are Kotlin Coroutine-Flow, kotlinx.serialization, Hilt, Compose, Accompanist, Retrofit2, OkHttp3, Chucker, MockWebServer, Truth.

Tolga Bolatcan 13 Nov 2, 2022
Full Management is an application that helps you manage your tasks effectively. built with the latest tachs like Compose UI, Jetpack libraries, and MVVM design pattern.

Full Management is an application that helps you manage your tasks effectively. built with the latest tachs like Compose UI, Jetpack libraries, and MVVM design pattern.

Amr algnyat 4 Nov 1, 2022
MVVM RECIPE ANDROID APP Is an app where I show how to use MVVM, retrofit, dagger hilt, coroutine, liveData, Kotlin, navigation component, and so on...

MVVM RECIPE ANDROID APP Is an app where I show how to use MVVM, retrofit, dagger hilt, coroutine, liveData, kotlin, navigation component, and so on...

Isaias Cuvula 22 Oct 26, 2022
🎯 Einsen is a prioritization app that uses Eisenhower matrix technique as workflow to prioritize a list of tasks & built to Demonstrate use of Jetpack Compose with Modern Android Architecture Components & MVVM Architecture.

?? Einsen Einsen is a prioritization app that uses Eisenhower matrix technique as workflow to prioritize a list of tasks & built to Demonstrate use of

Sanju S 835 Nov 23, 2022
📊 A Minimal Expense Tracker App built to demonstrate the use of modern android architecture component with MVVM Architecture

Expenso ?? A Simple Expense Tracker App ?? built to demonstrate the use of modern android architecture component with MVVM Architecture ?? . Made with

Sanju S 798 Nov 20, 2022
Oasis is a simple gym progress-tracking app built on MVVM architecture.

Oasis About Oasis is a simple gym progress-tracking app built on MVVM architecture. Built with Kotlin Coroutines Flow Firebase Auth Firebase Firestore

null 1 Feb 7, 2022
Playground project built with MVVM with Clean Artchitect to try out new tech in Android 🌍

Clean-MVVM-Playground Playground project built with MVVM with Clean Artchitect to try out new tech in Android ?? Features ?? 100% Kotlin Following MVV

Somesh Kumar 7 Oct 9, 2022
Pick any of your favorite github repository and create a mini android app showing its details on an android app.

Github Browser Pick any of your favorite github repository and create a mini android app showing its details on an android app. Screens navigation gra

Prasoon 6 Oct 16, 2022
Chat App MVVM + Clean ArchitectureChat App MVVM + Clean Architecture

Chat App MVVM + Clean Architecture This Android application built using MVVM + Clean Architecture architecture approach and is written 100% in Kotlin.

null 2 Nov 18, 2022
Basic-MVVM-Example - Basic Android Application MVVM

Android's MVVM Architecture in Kotlin Why a simple app ? Because it's easier to

null 5 May 24, 2022
MVVM Redux is a lightweight lib to help you apply the redux concepts in your project based in MVVM.

MVVM Redux is a lightweight lib to help you apply the redux concepts in your project based in MVVM.

Gabriel Brasileiro 36 Oct 16, 2022
Android App using Kotlin, MVVM, ViewModel, LiveData, Coroutines, Room and DataBinding

Words Android App using Kotlin, MVVM, ViewModel, LiveData, Coroutines, Room and

Viacheslav Veselov 0 Jul 16, 2022