Code Monkey home page Code Monkey logo

archi's Introduction

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.

archi's People

Contributors

ivacf avatar jonathan-caryl avatar ritave avatar vprus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

archi's Issues

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.

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

Should test sources depend on android framework?(app-mvp)

I was told that make src/test codes depend on android frame work is not good practice. Instead framework dependant codes should be in src/androidTes'.

The motivation for me to clone this repos is to find advice on wether to put ViewModel more close to View (framework dependant, operate directly on android Views) or otherwise more close to Model (Only POJO).

But thank you anyway, this repo is a good showcase of three different architectures.

[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!

MainActivityBinding is missing

uk.ivanc.archimvvm.databinding.MainActivityBinding is referenced in uk.ivanc.archimvvm.view.MainActivity but miss missing

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.

how about fragment in mvp

  • Does each Fragment have a matching presenter like Activity? I wanna use your mvp architecture to build app :)
  • Thanks in advanced @ivacf

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?

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)

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.

Navigation in mvvm

  1. I want startactivityforresult or setresult and finish activity, how can handle it in view model of activity ?
  2. Same question with view model of recyclerview.viewholder

[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

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

Better separation between MVP presenter and view

In the MVP example the view directly issues commands on the presenter, for example the MainActivity directly calls MainPresenter#loadRepositories whereas it should rather use a passive callback like Presenter#onUsernameSubmitted. The main reason for this is to hand over navigation responsibility to the presenter away from the view (which should be a dumb view).

I've created this issue for discussion, since this is obviously a matter of architecture style and code separation.

missinng ItemRepoPresenter

ItemRepoViewModel exists however is missing and logic is bundled with the RepositoryAdapter.

it would be nice to have a separate ItemRepoPresenter so:

  1. the RecyclerView.Adapter is separated form business logic
  2. we have clear comparison between viewmodels and presenters

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.