{"id":16552808,"url":"https://github.com/twisterrob/android-realistic","last_synced_at":"2026-04-30T14:34:48.558Z","repository":{"id":77774901,"uuid":"113509917","full_name":"TWiStErRob/android-realistic","owner":"TWiStErRob","description":"Android project example with real-life tools and problems solved.","archived":false,"fork":false,"pushed_at":"2022-10-30T10:05:19.000Z","size":318,"stargazers_count":12,"open_issues_count":0,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-16T11:29:16.422Z","etag":null,"topics":["android","architecture","example"],"latest_commit_sha":null,"homepage":"https://github.com/TWiStErRob/android-realistic","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TWiStErRob.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"TWiStErRob"}},"created_at":"2017-12-07T23:44:57.000Z","updated_at":"2025-02-05T06:58:23.000Z","dependencies_parsed_at":null,"dependency_job_id":"f16191d6-4d76-4539-9b46-b7de66427396","html_url":"https://github.com/TWiStErRob/android-realistic","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TWiStErRob%2Fandroid-realistic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TWiStErRob%2Fandroid-realistic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TWiStErRob%2Fandroid-realistic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TWiStErRob%2Fandroid-realistic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TWiStErRob","download_url":"https://codeload.github.com/TWiStErRob/android-realistic/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248935388,"owners_count":21185826,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","architecture","example"],"created_at":"2024-10-11T19:46:07.834Z","updated_at":"2026-04-30T14:34:46.222Z","avatar_url":"https://github.com/TWiStErRob.png","language":"Kotlin","funding_links":["https://github.com/sponsors/TWiStErRob"],"categories":[],"sub_categories":[],"readme":"This is an Android project example with real-life tools and problems solved. It strives to demonstrate best practices over over-simplified examples and God-activities / single-gradle build files; let's face it those are useful, but sometimes it's hard to integrate/scale them into a real project. By using `[marker]`s I'll try to link pieces together and document each marker in this `README.md`. Use `grep` or IDEA's *Edit \u003e Find \u003e Find in path...* as a navigation tool to connect the dots.\n\nSee the *Glossary* and *FAQ* if something is not clear.\n\n## Goals\n * Mimic real project structure\n * Promote and accumulate best practices, explain benefits\n * Over-document everything in this repo  \n   (not necessary to replicate this in any project as this is a documentation repo)\n * Use real libraries, tools, plugins (and a lot of them)\n * Use multiple languages (where possible, to demonstrate it's possible to deal with legacy code)\n * Test everything\n * Minimize project setup for team members\n * Minimize affected area for each modification by using fine-grained modules (also increases knowledge of dependencies, and inability to mis-use dependencies/libraries)\n * Minimize incremental build times\n\n## Structure\n * `.idea` (see `[share-ide]`)\n * `buildSrc` (see `[build-src]` and `[build-src-hack]`)\n   * `:class-gen`\n   * `:class-gen-tasks`\n * `gradle`\n * `:core`\n * `:feature`\n   * `:f:about`\n   * `:f:about-contract`\n   * `:f:base`\n   * `:f:main`\n * `:app`\n\n## Setup\n\nEverything is latest stable, no preview versions, unless absolutely gives a benefit.\n\n * Developed on Android Studio 3.0.1 and Gradle 4.2.1 (`gradle-wrapper.properties`)\n * SDK, language, tooling, plugin, library, etc. versions, see `gradle.properties`\n\n## Decisions\n\n * Feature module package names don't include package, because it would be long and noisy  \n   (`net.twisterrob.real.feature.main` VS `net.twisterrob.real.main`) \n * Every module is `'com.android.library'` until I figure out what `.feature` is for  \n   (it Lint warns about backup and icon, which I don't want to specify for feature modules)\n * `MainActivity` is its own feature, so that it can be decoupled from `app`  \n   (May be premature optimization preparing for instant apps, but still a useful separation.)\n\n## Opinionated decisions\n\n * In all Groovy (Gradle) files I use 'single' for hard-coded values and \"GString\" for interpolation.  \n   This means that while reading Groovy code it's easy to see if my eye should look for `${}`\n * `VERSION_FOO` in `gradle.properties`  \n   TODO \"IntelliJ IDEA doesn't help either way\"\n\n## Pain points\n\nResolving any of these in a nice way is very welcome!  \n**Please let me know, if you know how; even if just half a sentence!**\n\n * Navigator objects need to reference the classes by string names\n   * Required to hide feature module implementation details\n    (i.e. only contract classes visible to consumers)\n   * Proguard-safe, because we're talking about activities which are kept because of AndroidManifest.xml\n   * Not refactor-safe, because \"find string occurrences\" needs to be turned on in IDEA when renaming/repackaging activities\n * *Make Project* (hammer on toolbar) triggers `buildSrc` submodules by accident, failing to compile with message:\n    \u003e Information: `Gradle tasks [:app:assembleDebug, :class-gen:assemble, :class-gen-tasks:assemble]`  \n    \u003e Error:\n    \u003e ```\n    \u003e FAILURE: Build failed with an exception.\n    \u003e\n    \u003e * What went wrong:\n    \u003e Project 'class-gen' not found in root project 'real'.\n    \u003e ```\n    `[build-src-hack]` https://issuetracker.google.com/issues/71422483\n    To work around this error I included the `buildSrc` modules in the `rootProject`'s `settings.gradle` and relocated their source code. This lets AS run the `*:assemble` task to its heart content, it should be always `UP-TO-DATE` after first build, because it rarely changes.\n\n## Aspect References\n * `[multidex]` https://developer.android.com/studio/build/multidex.html  \n   Enable to use more than the dreaded 65536 method references.\n * `[big-gen]` generate some big classes to go over the dex limit fast, see also `[build-src]` on how this is achieved.\n * `[share-ide]`\n   Sharing some, but not all `.idea` files is really useful in teams and open-source projects.\n   * **It helps maintain the team standard** by catching issues early. For example: consider the cost of discovering and fixing an IDEA Inspection warning in the editor vs. a CI build failure after commit.\n   * **It minimizes set-up time**: most things are in Gradle configuration already, but that's mostly for how to produce a binary from sources. To help describing how to produce sources from nothing we need to share Code style, Inspections, Lint, Pre-commit actions (auto-format, organize imports, etc.), Run configurations. I've seen companies having long documents detailing how to import all these one-by-one from Wiki-attachments, a better way is obvious: version control them with code.\n   * All this is achieved by [clever `.gitignore` rules](https://stackoverflow.com/a/5534865/253468)\n     * Since the files are version controlled any deviation from the standard is obvious, because they show up in GIT's staging area.\n     * New files to \"un-ignored\" folders need to be added forcefully:\n\n         \u003e *`.idea/fileTemplates/includes $`* `git add \"File Header.java\"`  \n         The following paths are ignored by one of your .gitignore files:  \n         .idea/fileTemplates/includes/File Header.java  \n         Use -f if you really want to add them.\n\n       This is actually useful, so it's hard to accidentally commit local configuration.\n   * *This approach has been stress-tested with a team of 15 Android developers using Android Studio [2.2-3.0.1] on Windows and different Mac machines.*\n * `[build-src]` https://docs.gradle.org/4.2.1/userguide/organizing_build_logic.html#sec%3Abuild_sources\n   * To enable developing `buildSrc` in IDEA, import `buildSrc/build.gradle` as a separate standalone project.\n     Developing as a standalone project enables more control, and faster iteration. Running JUnit tests are tricky when not editing buildSrc as a standalone project, so it's suggested to import it in a separate window.\n     IDEA supports developing inline (as a module) as well, but build errors may be hard to figure out since any Gradle task executed from the IDE will need to build `buildSrc` first: chicken and egg. See also `[build-src-hack]`.\n * `[arch]` TODO MVP, Clean architecture\n * `[di]` TODO Dagger, ButterKnife\n * `[dagger-android]` for simplified injection of feature modules\n * `[nav]` TODO `ScreenFactory` + `Navigator`\n * `[vector]` TODO appcompat, SVG conversion\n * `[version]` gradle.properties + `\"...${}\"`\n * `[build-share]` android-setup.gradle\n * `[stetho]` Stetho is a library for sharing app-state with chrome://inspect. It's only added in debug builds to not expose internals in releases. Release code has only the skeleton to make it compile.\n    \n\n## Glossary\n * **Android**: a mobile platform building applications for smartphones\n * **Gradle**: a build system that helps combining multiple projects (modules) into a single build flow.\n * **Android Gradle Plugin** (**AGP**): a Gradle plugin that sets up project conventions for Android development and handles to heavy lifting of communicating with the Android SDK.\n * **Android Studio** (**AS**): an IDE by Google based on IntelliJ IDEA Community, specifically tailored for Android development.\n * IntellIJ **IDEA**: an IDE platform by JetBrains for polyglot software engineering. *I'll refer to IDEA in most places instead of AS to demonstrate that it's true if someone is using raw IntelliJ IDEA Community/Ultimate as their IDE.*\n * **module**: a gradle subproject used to hold a bit of functionality in the project. Self-contained: built, packaged, tested individually.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftwisterrob%2Fandroid-realistic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftwisterrob%2Fandroid-realistic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftwisterrob%2Fandroid-realistic/lists"}