├── .directory ├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── navigationdemo │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── navigationdemo │ │ │ └── MainActivity.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── navigationdemo │ └── ExampleUnitTest.kt ├── bar ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── bar │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── bar │ │ │ ├── BarFragment.kt │ │ │ └── BarViewModel.kt │ └── res │ │ ├── layout │ │ └── fragment_bar.xml │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── example │ └── bar │ └── ExampleUnitTest.java ├── build.gradle ├── foo ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── foo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── foo │ │ │ ├── FooFragment.kt │ │ │ └── FooViewModel.kt │ └── res │ │ ├── layout │ │ └── fragment_foo.xml │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── example │ └── foo │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── navigation ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── navigation │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ └── res │ │ ├── navigation │ │ └── nav_graph.xml │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── example │ └── navigation │ └── ExampleUnitTest.java ├── resources ├── Android Architecture.png └── nav_graph.png └── settings.gradle /.directory: -------------------------------------------------------------------------------- 1 | [Dolphin] 2 | Timestamp=2019,5,26,10,8,16 3 | Version=4 4 | 5 | [Settings] 6 | HiddenFilesShown=true 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .DS_Store 5 | /build 6 | /captures 7 | .externalNativeBuild 8 | 9 | !gradle-wrapper.jar 10 | 11 | *.class 12 | *.log 13 | .mtj.tmp/ 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Using The Navigation Component in a Single Activity Multi-Module Android App 2 | ## Summary 3 | 4 | Google has made a point not to dictate how you structure your app. However, surprisingly, they have now made recommendations to help guide developers. Since Jetpack was announced in May 17, 2017 the way Google recommends you structure the project and the semantic meaning of the Android components has been evolving. 5 | 6 | Each section below serves as an overview. Under each of the sections I provide all the resources I used to come to grips with what eventually became our architecture. So if the overviews are too brief please peruse the resources to get a better understanding. 7 | 8 | - [Jetpack](https://developer.android.com/jetpack) 9 | 10 | ## Single Activity Architecture 11 | 12 | One of the core components Jetpack introduced are the architecture components. The navigation component is one of these architecture components. The development of these architecture components lead to Google being more explicit with how to use Android components. Specifically, Google now officially recommend new Android applications are created as single activity applications. 13 | 14 | > Today we are introducing the Navigation component as a framework for structuring your in-app UI, with a focus on making a single-Activity app the preferred architecture. 15 | 16 | Google defines an activity as the entry point of your application. Therefore, having multiple activities indicates a user should be able to enter the app at the start of any one those activities. 17 | 18 | - [Single Activity: Why, When, and How](https://www.youtube.com/watch?v=2k8x8V77CrU&feature=youtu.be) 19 | - [A Single-Activity Android Application. Why not?!](https://medium.com/rosberryapps/a-single-activity-android-application-why-not-fa2a5458a099) 20 | - [Introducing Jetpack](https://android-developers.googleblog.com/2018/05/use-android-jetpack-to-accelerate-your.html?m=1) 21 | 22 | ## Multi-Module App 23 | 24 | Google also introduced a new application serving model called Dynamic Delivery. This defers APK generation to Google Play. Google Play uses Android App Bundles to create better optimized APKs for wider support. This now also gives developers the opportunity to use dynamic feature modules. Allowing certain features and assets to be downloaded later as the users need them. 25 | 26 | Over and above the obvious benefits of modular applications Dynamic Delivery creates a large incentive for designing modular apps. Furthermore, Google also recommends you modularize your apps. 27 | 28 | - [Build a Modular Android App Architecture (Google I/O'19)](https://www.youtube.com/watch?v=PZBg5DIzNww) 29 | - [Modularize your app](https://developer.android.com/studio/projects/dynamic-delivery#modularize) 30 | - [Intro to app modularization](https://proandroiddev.com/intro-to-app-modularization-42411e4c421e) 31 | - [Optimize your app](https://developer.android.com/studio/build/optimize-your-build) 32 | 33 | ## Jetpack | Architecture | Navigation Component 34 | 35 | > Jetpack is a suite of libraries, tools, and guidance to help developers write high-quality apps easier. These components help you follow best practices, free you from writing boilerplate code, and simplify complex tasks, so you can focus on the code you care about. 36 | 37 | Google introduced the navigation component as part of the Jetpack architecture components. This component handles fragment transactions, back stack management, transitions and animations, deep linking, and UI patterns. 38 | 39 | - [Navigation Getting Started](https://developer.android.com/guide/navigation/navigation-getting-started) 40 | - [Deeplinking with navigation component](https://medium.com/incwell-innovations/deeplink-and-navigation-in-android-architecture-component-part-3-b882ed5d5b32) 41 | - [Splash screen using the navigation component](https://proandroiddev.com/android-navigation-component-tips-tricks-implementing-splash-screen-f0f5ce046a09) 42 | 43 | ## Our solution 44 | 45 | Given the latest developments in Android we wanted to adhere to best practices as far as possible. This meant creating a modular, single activity app using the latest architecture components. However, there wasn't a lot of official documentation on using all of these best practices and structural recommendations together. So we struggled. But we tried to do it incrementally. And this is what we found. 46 | 47 | ### Modularization 48 | 49 | After some deliberation we settled on creating high-level feature modules with the intent of modularizing further when the need arises. We also had a module which depended on these feature modules and essentially coordinated them. Across the project there was a lot of code that was used by all the modules. Examples include the communication interfaces, navigation, input validations, and authentication. Therefore, a common module was created called _core_. The architecture can be visualized below. 50 | 51 | ![Multi-module architecture](https://github.com/DuartBreedt/Android-Navigation-in-a-Single-Activity-Multi-Module-App/blob/master/resources/Android%20Architecture.png "Multi-Module Architecture") 52 | 53 | _feature one_ has to be aware and therefore dependent on _feature two_ in order to navigate to it. Conversely, _feature two_ has to be aware and therefore dependent on _feature one_ in order to navigate to it. If this is a scenario then there will be circular dependency between the two features. Therefore, static objects were made in _core_ with interfaces defining navigation which could be consumed by the features. The _app_ feature then overrided the interface methods to define the behaviour. This was a gross way of solving navigation but it worked until we implemented the navigation component. 54 | 55 | ### Single Activity 56 | 57 | Initially we had two activities. One for login and another for the app's main page. After doing some reading it seemed Google recommended creating a single activity and swapping out fragments within that activity using the Navigation component. Since we wanted to solve the hacky navigation job it seemed single activity app architecture was the way to go. 58 | 59 | First off, we had to convert our existing activities to fragments. Then we had to create a new activity called _MainActivity_ - very creative, I know - which would then swap these activities in and out. At first this seemed quite straight forward, but there were a few gotchas. 60 | 61 | Most notably, we could no longer navigate to another screen which in this case was now a fragment. If we did want to navigate between fragments we would need to use the `FragmentManager` and `FragmentTransactions`. But this was a lot of work to be done only to be replaced by the navigation component. Therefore, for the time being our app could simply not navigate. 62 | 63 | Another issue was that `setSupportedToolbar` is a method which belongs to activities. So how the hell do we add toolbars to fragments? We ignored this problem in hopes that navigation components will maagically solve this for us, which they thankfully did. 64 | 65 | ### Jetpack | Architecture | Navigation Component 66 | 67 | Please go read up a bit on the navigational component if this doesn't make complete sense. 68 | 69 | The navigational component requires the following to be defined: navigation host, navigation graph, and navigation controller. 70 | 71 | #### Navigation host 72 | 73 | The navigation host is an empty container where the destinations are swapped in and out. This is typically an XML fragment. In our case the navigation host was located in the newly created _MainActivity_. 74 | 75 | #### Navigation graph 76 | The navigation graph is a resource which describes destinations (fragments) and those destinations' possible actions (moves to other destinations). 77 | Note that this doesn't create a direct dependency to the fragments but simply catalogs them using their fully qualified name. 78 | 79 | All features and fragments need full awareness of this navigation graph if they wish to navigate to a fragment defined in it. Therefore, this made the _core_ module the optimal place to keep the navigation graph. 80 | 81 | > ![Navigation Graph](https://github.com/DuartBreedt/Android-Navigation-in-a-Single-Activity-Multi-Module-App/blob/master/resources/nav_graph.png "Navigation Graph") 82 | 83 | Typically you can use the navigation graph editor to detect the navigation host, add new destinations, and add new actions. 84 | However, due to the project being separated into multiple modules Android Studio isn't smart enough to detect the destinations and navigation host through the graph editor. Therefore, you do not have the luxury of using the graph editor but since the resources squash down to the same file, at compile time it all works itself out in the end. 85 | 86 | ### Navigation controller 87 | 88 | The navigation controller is an object provided by the navigation host. This can be accessed by a fragment, view, or activity. This simply gives you the ability to navigate to one of the destinations described in the navigation graph. 89 | 90 | - [Using Navigation Architecture Component in a large banking app](https://medium.com/google-developer-experts/using-navigation-architecture-component-in-a-large-banking-app-ac84936a42c2) 91 | - [A quick glance on single activity approach with navigation component](https://android.jlelse.eu/a-quick-glance-on-single-activity-approach-with-navigation-component-f3b96b3b0a58) 92 | - [GitHub | Navigation Single Activity](https://github.com/GabrielSamojlo/navigation-single-activity) 93 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | android { 8 | compileSdkVersion 28 9 | defaultConfig { 10 | applicationId "com.example.navigationdemo" 11 | minSdkVersion 16 12 | targetSdkVersion 28 13 | versionCode 1 14 | versionName "1.0" 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | implementation project(path: ':navigation') 27 | implementation project(path: ':foo') 28 | implementation project(path: ':bar') 29 | 30 | implementation fileTree(dir: 'libs', include: ['*.jar']) 31 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 32 | implementation 'androidx.appcompat:appcompat:1.0.2' 33 | implementation 'androidx.core:core-ktx:1.0.2' 34 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 35 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 36 | implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' 37 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.0.0' 38 | testImplementation 'junit:junit:4.12' 39 | androidTestImplementation 'androidx.test:runner:1.1.1' 40 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 41 | implementation 'androidx.navigation:navigation-fragment-ktx:2.0.0' 42 | implementation 'androidx.navigation:navigation-ui-ktx:2.0.0' 43 | } 44 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/navigationdemo/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.navigationdemo 2 | 3 | import androidx.test.InstrumentationRegistry 4 | import androidx.test.runner.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getTargetContext() 22 | assertEquals("com.example.navigationdemo", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/navigationdemo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.navigationdemo 2 | 3 | import androidx.appcompat.app.AppCompatActivity 4 | import android.os.Bundle 5 | 6 | class MainActivity : AppCompatActivity() { 7 | 8 | override fun onCreate(savedInstanceState: Bundle?) { 9 | super.onCreate(savedInstanceState) 10 | setContentView(R.layout.activity_main) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuartBreedt/Android-Navigation-in-a-Single-Activity-Multi-Module-App/c6ee8f773278cd8120acfdafd15d9959ddd59989/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuartBreedt/Android-Navigation-in-a-Single-Activity-Multi-Module-App/c6ee8f773278cd8120acfdafd15d9959ddd59989/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuartBreedt/Android-Navigation-in-a-Single-Activity-Multi-Module-App/c6ee8f773278cd8120acfdafd15d9959ddd59989/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuartBreedt/Android-Navigation-in-a-Single-Activity-Multi-Module-App/c6ee8f773278cd8120acfdafd15d9959ddd59989/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuartBreedt/Android-Navigation-in-a-Single-Activity-Multi-Module-App/c6ee8f773278cd8120acfdafd15d9959ddd59989/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuartBreedt/Android-Navigation-in-a-Single-Activity-Multi-Module-App/c6ee8f773278cd8120acfdafd15d9959ddd59989/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuartBreedt/Android-Navigation-in-a-Single-Activity-Multi-Module-App/c6ee8f773278cd8120acfdafd15d9959ddd59989/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuartBreedt/Android-Navigation-in-a-Single-Activity-Multi-Module-App/c6ee8f773278cd8120acfdafd15d9959ddd59989/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuartBreedt/Android-Navigation-in-a-Single-Activity-Multi-Module-App/c6ee8f773278cd8120acfdafd15d9959ddd59989/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuartBreedt/Android-Navigation-in-a-Single-Activity-Multi-Module-App/c6ee8f773278cd8120acfdafd15d9959ddd59989/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Navigation Demo 3 | 4 | 5 | Hello blank fragment 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/example/navigationdemo/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.navigationdemo 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /bar/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /bar/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | android { 6 | compileSdkVersion 28 7 | 8 | 9 | defaultConfig { 10 | minSdkVersion 16 11 | targetSdkVersion 28 12 | versionCode 1 13 | versionName "1.0" 14 | 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | 26 | } 27 | 28 | dependencies { 29 | implementation project(path: ':navigation') 30 | 31 | implementation fileTree(dir: 'libs', include: ['*.jar']) 32 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 33 | implementation 'androidx.appcompat:appcompat:1.0.2' 34 | implementation 'androidx.core:core-ktx:1.0.2' 35 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 36 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 37 | implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' 38 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.0.0' 39 | testImplementation 'junit:junit:4.12' 40 | androidTestImplementation 'androidx.test:runner:1.1.1' 41 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 42 | implementation 'androidx.navigation:navigation-fragment-ktx:2.0.0' 43 | implementation 'androidx.navigation:navigation-ui-ktx:2.0.0' 44 | } 45 | -------------------------------------------------------------------------------- /bar/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /bar/src/androidTest/java/com/example/bar/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.example.bar; 2 | 3 | import android.content.Context; 4 | import androidx.test.InstrumentationRegistry; 5 | import androidx.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.example.bar.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bar/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /bar/src/main/java/com/example/bar/BarFragment.kt: -------------------------------------------------------------------------------- 1 | package com.example.bar 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import androidx.lifecycle.ViewModelProviders 9 | 10 | class BarFragment : Fragment() { 11 | 12 | companion object { 13 | fun newInstance() = BarFragment() 14 | } 15 | 16 | private lateinit var viewModel: BarViewModel 17 | 18 | override fun onCreateView( 19 | inflater: LayoutInflater, container: ViewGroup?, 20 | savedInstanceState: Bundle? 21 | ): View? { 22 | return inflater.inflate(R.layout.fragment_bar, container, false) 23 | } 24 | 25 | override fun onActivityCreated(savedInstanceState: Bundle?) { 26 | super.onActivityCreated(savedInstanceState) 27 | viewModel = ViewModelProviders.of(this).get(BarViewModel::class.java) 28 | // TODO: Use the ViewModel 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /bar/src/main/java/com/example/bar/BarViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.example.bar 2 | 3 | import androidx.lifecycle.ViewModel; 4 | 5 | class BarViewModel : ViewModel() { 6 | // TODO: Implement the ViewModel 7 | } 8 | -------------------------------------------------------------------------------- /bar/src/main/res/layout/fragment_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | -------------------------------------------------------------------------------- /bar/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | bar 3 | 4 | -------------------------------------------------------------------------------- /bar/src/test/java/com/example/bar/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.example.bar; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.3.31' 5 | repositories { 6 | google() 7 | jcenter() 8 | 9 | } 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:3.4.1' 12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | jcenter() 22 | 23 | } 24 | } 25 | 26 | task clean(type: Delete) { 27 | delete rootProject.buildDir 28 | } 29 | -------------------------------------------------------------------------------- /foo/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /foo/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | android { 6 | compileSdkVersion 28 7 | 8 | 9 | defaultConfig { 10 | minSdkVersion 16 11 | targetSdkVersion 28 12 | versionCode 1 13 | versionName "1.0" 14 | 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | 26 | } 27 | 28 | dependencies { 29 | implementation project(path: ':navigation') 30 | 31 | implementation fileTree(dir: 'libs', include: ['*.jar']) 32 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 33 | implementation 'androidx.appcompat:appcompat:1.0.2' 34 | implementation 'androidx.core:core-ktx:1.0.2' 35 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 36 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 37 | implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' 38 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.0.0' 39 | testImplementation 'junit:junit:4.12' 40 | androidTestImplementation 'androidx.test:runner:1.1.1' 41 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 42 | implementation 'androidx.navigation:navigation-fragment-ktx:2.0.0' 43 | implementation 'androidx.navigation:navigation-ui-ktx:2.0.0' 44 | } 45 | -------------------------------------------------------------------------------- /foo/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /foo/src/androidTest/java/com/example/foo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.example.foo; 2 | 3 | import android.content.Context; 4 | import androidx.test.InstrumentationRegistry; 5 | import androidx.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.example.foo.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /foo/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /foo/src/main/java/com/example/foo/FooFragment.kt: -------------------------------------------------------------------------------- 1 | package com.example.foo 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import androidx.lifecycle.ViewModelProviders 9 | import androidx.navigation.fragment.findNavController 10 | import kotlinx.android.synthetic.main.fragment_foo.* 11 | 12 | class FooFragment : Fragment() { 13 | 14 | companion object { 15 | fun newInstance() = FooFragment() 16 | } 17 | 18 | private lateinit var viewModel: FooViewModel 19 | 20 | override fun onCreateView( 21 | inflater: LayoutInflater, container: ViewGroup?, 22 | savedInstanceState: Bundle? 23 | ): View? { 24 | return inflater.inflate(R.layout.fragment_foo, container, false) 25 | } 26 | 27 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 28 | super.onViewCreated(view, savedInstanceState) 29 | 30 | go_somwhere_button.setOnClickListener { findNavController().navigate(R.id.barFragment) } 31 | } 32 | 33 | override fun onActivityCreated(savedInstanceState: Bundle?) { 34 | super.onActivityCreated(savedInstanceState) 35 | viewModel = ViewModelProviders.of(this).get(FooViewModel::class.java) 36 | // TODO: Use the ViewModel 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /foo/src/main/java/com/example/foo/FooViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.example.foo 2 | 3 | import androidx.lifecycle.ViewModel; 4 | 5 | class FooViewModel : ViewModel() { 6 | // TODO: Implement the ViewModel 7 | } 8 | -------------------------------------------------------------------------------- /foo/src/main/res/layout/fragment_foo.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 27 | -------------------------------------------------------------------------------- /foo/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Foo 3 | 4 | -------------------------------------------------------------------------------- /foo/src/test/java/com/example/foo/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.example.foo; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu May 23 09:48:55 SAST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /navigation/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /navigation/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | 6 | 7 | defaultConfig { 8 | minSdkVersion 16 9 | targetSdkVersion 28 10 | versionCode 1 11 | versionName "1.0" 12 | 13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 14 | 15 | } 16 | 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | 24 | } 25 | 26 | dependencies { 27 | implementation fileTree(dir: 'libs', include: ['*.jar']) 28 | 29 | implementation 'androidx.appcompat:appcompat:1.0.2' 30 | testImplementation 'junit:junit:4.12' 31 | androidTestImplementation 'androidx.test:runner:1.1.1' 32 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 33 | implementation 'androidx.navigation:navigation-fragment:2.0.0' 34 | implementation 'androidx.navigation:navigation-ui:2.0.0' 35 | } 36 | -------------------------------------------------------------------------------- /navigation/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /navigation/src/androidTest/java/com/example/navigation/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.example.navigation; 2 | 3 | import android.content.Context; 4 | import androidx.test.InstrumentationRegistry; 5 | import androidx.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.example.navigation.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /navigation/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /navigation/src/main/res/navigation/nav_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 10 | 11 | 12 | 14 | 15 | -------------------------------------------------------------------------------- /navigation/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Navigation 3 | 4 | -------------------------------------------------------------------------------- /navigation/src/test/java/com/example/navigation/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.example.navigation; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /resources/Android Architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuartBreedt/Android-Navigation-in-a-Single-Activity-Multi-Module-App/c6ee8f773278cd8120acfdafd15d9959ddd59989/resources/Android Architecture.png -------------------------------------------------------------------------------- /resources/nav_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuartBreedt/Android-Navigation-in-a-Single-Activity-Multi-Module-App/c6ee8f773278cd8120acfdafd15d9959ddd59989/resources/nav_graph.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':foo', ':bar', ':navigation' 2 | --------------------------------------------------------------------------------