{"id":42466,"date":"2019-08-21T15:04:06","date_gmt":"2019-08-21T15:04:06","guid":{"rendered":"https:\/\/owncloud.com\/?p=42466"},"modified":"2020-07-13T15:07:18","modified_gmt":"2020-07-13T15:07:18","slug":"re-architecting-the-owncloud-app-for-android","status":"publish","type":"post","link":"https:\/\/owncloud.com\/de\/blogs\/re-architecting-the-owncloud-app-for-android\/","title":{"rendered":"Re-Architecting the ownCloud App for Android"},"content":{"rendered":"<div class=\"headline-wrap\">\n<h1>Re-Architecting the ownCloud App for Android<\/h1>\n<div class=\"excerpt bold\">\n<p>The Android team is currently rewriting the ownCloud app to change the architecture. The first improvements will be released soon. What can you learn from this?<\/p>\n<\/div>\n<\/div>\n<div class=\"content\">\n<h2>Renew or Die<\/h2>\n<p>8 years ago, in August 2011, the ownCloud Android repository received its first commit. It marked a turning point in the way of uploading files to a private cloud and sharing them with others, everything from the palm of our hands.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-19592\" src=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/1.-First-commit-oC-Android-1-1024x195.png\" sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/1.-First-commit-oC-Android-1-1024x195.png 1024w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/1.-First-commit-oC-Android-1-300x57.png 300w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/1.-First-commit-oC-Android-1-768x146.png 768w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/1.-First-commit-oC-Android-1-1800x342.png 1800w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/1.-First-commit-oC-Android-1-1320x251.png 1320w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/1.-First-commit-oC-Android-1.png 1966w\" alt=\"First commit ownCloud Android\" width=\"551\" height=\"105\" \/><figcaption><em>The first commit in the ownCloud Android app.<\/em><\/figcaption><\/figure>\n<\/div>\n<p>As it happens to all software in the world, the\u00a0ownCloud app for Android was getting older. Catching up with the latest Android features was being increasingly more difficult. Besides, there were many parts of the code needing a refactoring.<\/p>\n<p>Meanwhile, Android was getting more mature, modern and\u00a0Kotlin\u00a0was set as\u00a0official language for Android development. Additionally, the Android team introduced the\u00a0<strong>Android architecture components<\/strong>\u00a0a couple of years ago, a collection of libraries to develop robust, testable and more maintainable apps.<\/p>\n<p>So around a year ago, we finally gave a step forward and started to design what it would finally turn into a\u00a0<strong>new architecture<\/strong>\u00a0for the ownCloud app for Android.<\/p>\n<h2>Moving to a New Architecture<\/h2>\n<p>Before moving every kind of software to a new architecture, you should define a strategy to follow. In our case, we chose a simple use case like\u00a0getting shares from server and showing them in a list\u00a0and started to transform it from the old architecture to a new one \u2013 I will use this use case to explain everything related to new architecture in this blogpost.<\/p>\n<h3>From MVC to MVVM<\/h3>\n<p>Let\u2019s introduce these two design patterns that belongs to the\u00a0<a href=\"https:\/\/en.wikipedia.org\/wiki\/Multitier_architecture\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"(opens in a new tab)\">presentation layer<\/a>\u00a0and how they affect the ownCloud app for Android.<\/p>\n<h4>What Is the MVC Pattern?<\/h4>\n<p>The\u00a0MVC architecture pattern\u00a0(model \u2013 view \u2013 controller) is what we have traditionally been using in the ownCloud app for Android and consists of:<\/p>\n<ul>\n<li>Model: contains the information which the system works with and provides it to the view so it can be displayed. Besides, allows applying changes in the view from the controller. An example of model in our app is\u00a0<em>OCShare<\/em>, which contains all the information needed to work with a share such as\u00a0<em>name<\/em>,\u00a0<em>file path<\/em>,\u00a0<em>user<\/em>\u00a0to share with,\u00a0<em>permissions<\/em>\u00a0and so on.<\/li>\n<li>Controller: responds to user actions, modifying the model when needed. It also communicates with the view to update it with the latest changes in the model. A controller in our app is\u00a0<em>ShareActivity<\/em>.<\/li>\n<li>View: it presents model information to the user. Some views in our app are\u00a0<em>ShareActivity<\/em>\u00a0and\u00a0<em>ShareFragment<\/em>.<\/li>\n<\/ul>\n<p>One of the\u00a0most common mistakes when implementing MVC in Android\u00a0has always been\u00a0using an\u00a0<em>Activity<\/em>\u00a0as a controller,\u00a0making it responsible of tasks that should not take care of, like calling directly the model to modify data, when this should be a controller task. This is clearly a violation of the\u00a0<a href=\"https:\/\/en.wikipedia.org\/wiki\/Single_responsibility_principle\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"(opens in a new tab)\">single responsibility principle<\/a>\u00a0and when using an\u00a0<em>Activity<\/em>\u00a0as a controller we are tying it to the Android platform so its code could be affected if the\u00a0<em>Activity<\/em>\u00a0is destroyed by the system.<\/p>\n<p>If we want to properly use MVC in Android,\u00a0activities and fragments should only take care of showing data and notifying user events to a controller,\u00a0being the only components linked to the Android platform. Hence, controllers and models should be separate classes without any Android dependency so that can be easier to test. But this is not the case of the ownCloud app for Android since there were\u00a0some activities with a controller role, assuming responsibilities that should not involve them.<\/p>\n<h4>And the MVVM Pattern?<\/h4>\n<p>On the other hand,\u00a0MVVM architecture pattern\u00a0is what we are going to use in the\u00a0ownCloud app for Android from now\u00a0on. It consists of:<\/p>\n<ul>\n<li><strong>Model:<\/strong>\u00a0as in MVC, it represents data and business logic. The model in the ownCloud app for Android would keep being\u00a0<em>OCShare<\/em>.<\/li>\n<li><strong>View:\u00a0<\/strong>shows information and is active, reacting to model changes, similar to an active MVC pattern.\u00a0<em>ShareActivity<\/em>,\u00a0<em>ShareFragment<\/em>\u00a0are the views but with no controller responsibilities.<\/li>\n<li><strong>View model:<\/strong>\u00a0is the intermediary between model and view and contains presentation logic. There was no existing classes of this type, so we have created\u00a0<em>OCShareViewModel<\/em>.<\/li>\n<\/ul>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-19593\" src=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/2.-MVVMPattern.png\" sizes=\"(max-width: 771px) 100vw, 771px\" srcset=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/2.-MVVMPattern.png 771w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/2.-MVVMPattern-300x90.png 300w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/2.-MVVMPattern-768x231.png 768w\" alt=\"Model-View-Viewmodel Pattern\" width=\"552\" height=\"166\" \/><figcaption><em>The Model-View-Viewmodel pattern.<\/em><\/figcaption><\/figure>\n<\/div>\n<p>Now that we have introduced these two patterns,\u00a0why have we decided to use MVVM in favor of MVC in the app?<\/p>\n<ul>\n<li>In MVVM, the view will depend only on the viewmodel to get data and modify it and will directly observe changes in the model using databinding. Therefore, we will\u00a0decouple code from the view.<\/li>\n<li>The model in MVC usually has many responsibilities such as obtaining data from data sources, informing the controller about changes on that data and prepare them to be displayed in the view. In MVVM, the\u00a0model is totally decoupled from the view and only contains information, never actions to manipulate it.<\/li>\n<li>In MVVM, the\u00a0presentation logic is handled by the viewmodel, meanwhile in MVC this responsibility is barely clear.<\/li>\n<\/ul>\n<p>So with MVVM we are basically distributing responsibilities in a better way to reduce dependencies and make the code easier to test and debug.<\/p>\n<h3>Android Architecture Components<\/h3>\n<p>These components released by the Android team a couple of years ago\u00a0make our life easier when it comes to implementing a MVVM pattern in Android, as well as achieving more robust, maintainable and easier to test apps. They consist of:<\/p>\n<ul>\n<li><strong>LiveData<\/strong>: objects that notify the view when there is any change in database and are lifecycle aware so it can help us to avoid crashes when an activity is stopped. In the app we use a list of shares as livedata.<\/li>\n<li><strong>ViewModel<\/strong>: responsible for preparing and handling\u00a0<em>Activity<\/em>\u00a0or\u00a0<em>Fragment<\/em>\u00a0data. It exposes the information through a\u00a0<em>LiveData\u00a0<\/em>observed from the view. Regarding getting shares usecase,\u00a0<em>ShareFileFragment\u00a0<\/em>observes changes in shares livedata.<\/li>\n<li><strong>Room<\/strong>:\u00a0<em>ORM (Object-Relational mapping)\u00a0<\/em>library which converts SQLite to Java\/Kotlin objects automatically. It allows SQL validation in compile time and returns\u00a0<em>LiveData<\/em>\u00a0objects to observe changes in database.<\/li>\n<\/ul>\n<p>You can see below a diagram representing the\u00a0getting shares use case implemented with MVVM and Android architecture components.<\/p>\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-19594\" src=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/3.-New-arch-get-public-shares-1024x768.png\" sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/3.-New-arch-get-public-shares.png 1024w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/3.-New-arch-get-public-shares-300x225.png 300w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/3.-New-arch-get-public-shares-768x576.png 768w\" alt=\"New ownCloud architecture get public shares\" width=\"551\" height=\"413\" \/><figcaption><em>How the app gets public shares with the new architecture.<\/em><\/figcaption><\/figure>\n<p>So you can have a look at the diagram above and see the flow to get shares and show them in the view:<\/p>\n<ol>\n<li><em>ShareFileFragment<\/em>\u00a0observes the list of shares stored in a livedata object exposed by\u00a0<em>OCShareViewModel.<\/em><\/li>\n<li><em>OCShareViewModel obtains the shares from the OCShareRepository without knowing where they come from, is a completely transparent transaction, thanks to repository pattern.<\/em><\/li>\n<li><em>OCShareRepository<\/em>\u00a0obtains the shares from\u00a0<em>OCRemoteSharesDataSource,\u00a0<\/em>which uses the ownCloud Android Library to fetch the shares from server. After that, it updates the database with the new shares by using\u00a0<em>OCLocalSharesDataSource<\/em>.<\/li>\n<li>As soon as new shares are available in database,\u00a0<em>ShareFileFragment\u00a0<\/em>\u00a0is automatically notified through the observer and shows the shares to the user.<\/li>\n<\/ol>\n<p>In the diagram you will also have noticed some classes with a light blue background such as\u00a0<em>XMLLocalSharesDataSource<\/em>\u00a0or\u00a0<em>FirebaseRemoteSharesDataSource<\/em>, which represent the extensibility of this solution that allows changing the data sources in the future and getting the shares from XML, JSON files, different APIs and so on.<\/p>\n<h3>Modularizing the App<\/h3>\n<p>MVVM and also MVC are design patterns used in the presentation layer, but\u00a0an application is more than just one layer. To represent the different layers it is normal to use several modules, one for each layer.<\/p>\n<p>You might be wondering what is a module here. A\u00a0module is a component of an Android app that we can build, test and debug independently.<\/p>\n<p>Originally, the\u00a0ownCloud Android project consisted of two modules, the app itself and the library\u00a0but\u00a0from now on\u00a0we will have\u00a0four layers divided in four different modules, as you can see in the picture below.<\/p>\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-19595\" src=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/4.-ownCloud-Android-app-modularization-1024x768.png\" sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/4.-ownCloud-Android-app-modularization-1024x768.png 1024w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/4.-ownCloud-Android-app-modularization-300x225.png 300w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/4.-ownCloud-Android-app-modularization-768x576.png 768w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/4.-ownCloud-Android-app-modularization.png 1152w\" alt=\"ownCloud Android app modularization\" width=\"551\" height=\"413\" \/><figcaption><em>The different modularization layers of the new architecture.<\/em><\/figcaption><\/figure>\n<p>What are the advantages of doing this modularization?<\/p>\n<ul>\n<li><strong>Development scalability<\/strong>: several developers working in different modules independently.<\/li>\n<li><strong>Maintainability<\/strong>: gradle can build the modules separately, speeding up the build process and CI.<\/li>\n<li><strong>Less tests to run when there\u2019s a new change:\u00a0<\/strong>we need to run the tests in the module affected by the new change and anything else that depends on it. We do not need to run all the tests if other modules are not impacted by the changes.<\/li>\n<li><strong>Less coupled code.<\/strong><\/li>\n<li><strong>Module switching:<\/strong>\u00a0if in the future we want an app with a different UI and a different way to handle the information to show, we would just need to replace the\u00a0<em>:ownCloudApp<\/em>\u00a0module. And the same for the rest of modules, if one day we want to handle data differently to the current implementation, replacing the\u00a0<em>:ownCloudData<\/em>\u00a0module should be enough.<\/li>\n<\/ul>\n<h2>What Have We Already Achieved?<\/h2>\n<p>We have totally rewritten the sharing feature in Kotlin, following the architecture detailed above.<\/p>\n<p>As you can see in the graphs below, we have also\u00a0increased the use of Kotlin\u00a0in the app if we compare it with previous versions,\u00a0from 1.1% to almost 30%, without taking into account the xml resources.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-19596\" src=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/5.-Kotlin-vs-Java-before-new-arch.png\" sizes=\"(max-width: 350px) 100vw, 350px\" srcset=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/5.-Kotlin-vs-Java-before-new-arch.png 350w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/5.-Kotlin-vs-Java-before-new-arch-283x300.png 283w\" alt=\"Kotlin vs Java before new ownCloud architecture\" width=\"300\" height=\"318\" \/><figcaption><em>Kotlin vs Java before redesigning Sharing according to the new ownCloud architecture\u2026<\/em><\/figcaption><\/figure>\n<\/div>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-19597\" src=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/6.-Kotlin-vs-Java-new-arch.png\" sizes=\"(max-width: 328px) 100vw, 328px\" srcset=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/6.-Kotlin-vs-Java-new-arch.png 328w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/6.-Kotlin-vs-Java-new-arch-265x300.png 265w\" alt=\"Kotlin vs Java new architecture\" width=\"300\" height=\"339\" \/><figcaption><em>\u2026and afterwards.<\/em><\/figcaption><\/figure>\n<\/div>\n<p>This is a huge achievement because Kotlin code is easier to maintain and to read than Java. It is also safer, helping us to\u00a0reduce the amount of crashes\u00a0in the app for instance. In addition, it makes it easier for the community to contribute.<\/p>\n<p>Tests are an important part in software development so the number of both unit and UI tests has also been increased, reaching\u00a0224 new tests.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-19618\" src=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/ownCloud-Android-architecture-tests-table.png\" sizes=\"(max-width: 592px) 100vw, 592px\" srcset=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/ownCloud-Android-architecture-tests-table.png 592w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/ownCloud-Android-architecture-tests-table-300x102.png 300w\" alt=\"ownCloud Android architecture tests table\" width=\"551\" height=\"188\" \/><\/figure>\n<\/div>\n<p>Using a proper programming language and increasing the number of tests is decisive; but users do not usually notice this sort of changes in the app. What the users can see, among others, is the memory used by the app and how fast it reacts.<\/p>\n<p>The diagrams below shows the memory used by the app when using the share view. It is 5 MB lower than when the sharing was using the old architecture:<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-19603\" src=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/7.-Memory-before-new-arch.png\" sizes=\"(max-width: 559px) 100vw, 559px\" srcset=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/7.-Memory-before-new-arch.png 559w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/7.-Memory-before-new-arch-285x300.png 285w\" alt=\"Memory before new architecture\" width=\"550\" height=\"579\" \/><figcaption><em>Resources when using share view before new architecture<\/em><\/figcaption><\/figure>\n<\/div>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-19604\" src=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/8.-Memory-new-arch.png\" sizes=\"(max-width: 443px) 100vw, 443px\" srcset=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/8.-Memory-new-arch.png 443w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/8.-Memory-new-arch-300x284.png 300w\" alt=\"Resources when using share view with the new ownCloud architecture\" width=\"550\" height=\"521\" \/><figcaption><em>Resources when using share view with the new architecture<\/em><\/figcaption><\/figure>\n<\/div>\n<p>We have also measured how long it takes to open the share view after pressing the share icon of a file. The time has reduced as you can see below:<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-19605\" src=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/9.-Time-to-open-shares-view.png\" sizes=\"(max-width: 600px) 100vw, 600px\" srcset=\"https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/9.-Time-to-open-shares-view.png 600w, https:\/\/owncloud.org\/wp-content\/uploads\/2019\/08\/9.-Time-to-open-shares-view-300x186.png 300w\" alt=\"ownCloud Android Architecture Time to open shares view\" width=\"550\" height=\"340\" \/><\/figure>\n<\/div>\n<h2>Next Steps<\/h2>\n<p>We expect that these performance improvements will also happen in the other parts of the app which will be part of the rewrite.<\/p>\n<p>The next topic to address within the new architecture is the modularization of the app, as described above. To complete this modularization we would need to decouple some objects related to authorization such as the ownCloud clients and accounts.<\/p>\n<p>This process will come hand in hand with a complete refactorization of the login. Afterwards, files and synchronization will be the next challenge.<\/p>\n<p>Do you want to try out our current improvements? The beta is already out! Get it at the playstore:<\/p>\n<p><a class=\"button-oc\" href=\"https:\/\/central.owncloud.org\/t\/android-2-12-beta-test-the-rewritten-sharing-mechanism\/21294\" target=\"_blank\" rel=\"noopener noreferrer\">Join the Beta testers!<\/a><\/p>\n<p>What do you think about this progress? Leave a comment below or share this article on social media!<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>The Android team is currently rewriting the ownCloud app to change the architecture. The first improvements will be released soon. What can you learn from this?<\/p>\n","protected":false},"author":7,"featured_media":42468,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","inline_featured_image":false,"footnotes":""},"categories":[43],"tags":[],"class_list":["post-42466","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"acf":[],"_links":{"self":[{"href":"https:\/\/owncloud.com\/de\/wp-json\/wp\/v2\/posts\/42466","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/owncloud.com\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/owncloud.com\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/owncloud.com\/de\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/owncloud.com\/de\/wp-json\/wp\/v2\/comments?post=42466"}],"version-history":[{"count":0,"href":"https:\/\/owncloud.com\/de\/wp-json\/wp\/v2\/posts\/42466\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/owncloud.com\/de\/wp-json\/wp\/v2\/media\/42468"}],"wp:attachment":[{"href":"https:\/\/owncloud.com\/de\/wp-json\/wp\/v2\/media?parent=42466"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/owncloud.com\/de\/wp-json\/wp\/v2\/categories?post=42466"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/owncloud.com\/de\/wp-json\/wp\/v2\/tags?post=42466"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}