This is an Android Studio template for apps written in Kotlin, using Clean Architecture, MVP and packaging by feature
src/
├── com.my.package/
│ ├── di/
│ │ ├── component/
│ │ │ ├── AppComponent.kt
│ │ │ ├── BaseFeatureComponent.kt
│ │ │ ├── YourFeatureComponent.kt
│ │ │ └── ...
│ │ ├── module/
│ │ │ ├── AppModule.kt
│ │ │ ├── YourFeatureModule.kt
│ │ │ └── ...
│ │ ├── qualifier/
│ │ │ └── AppQualifier.kt
│ │ └── scope/
│ │ │ ├── AppScope.kt
│ │ │ ├── YourFeatureScope.kt
│ │ │ └── ...
│ └── presentation/
│ ├── base/
│ │ ├── BaseActivity.kt
│ │ ├── BaseContract.kt
│ │ ├── BaseFragment.kt
│ │ ├── BaseIntentBuilder.kt
│ │ ├── BasePresenter.kt
│ │ └── ViewTypeDelegate.kt
│ ├── common/
│ │ ├── AppSchedulerProvider.kt
│ │ ├── ObservableView.kt
│ │ └── SchedulerProvider.kt
│ ├── somefeature/
│ │ ├── YourFeatureActivity.kt
│ │ ├── YourFeatureContract.kt
│ │ ├── YourFeatureFragment.kt
│ │ └── YourFeaturePresenter.kt
│ └── ...
└── res/
└── layout/
├── activity_some_feature.xml
└── fragment_some_feature.xml
-
Your app must be written in Kotlin
-
The generated files will be located in the kotlin source set
app/src/main/kotlin
Add this to your module
build.gradle
sourceSets { main.java.srcDirs += 'src/main/kotlin' }
-
You must use:
AppCompat
for the base classesimplementation "com.android.support:appcompat-v7:$appCompatVersion" implementation "com.android.support:design:$designVersion"
- RxJava 2 for the
SchedulerProvider
used in the presentersimplementation "io.reactivex.rxjava2:rxjava:$rootProject.ext.rxJavaVersion" implementation "io.reactivex.rxjava2:rxandroid:$rootProject.ext.rxAndroidVersion"
- Dagger 2 for dependency injection.
BaseContract
,BaseActivity
andBaseFragment
are already implement an easy way of injecting your dependenciesimplementation "com.google.dagger:dagger:$daggerVersion" kapt "com.google.dagger:dagger-compiler:$daggerVersion"
- Copy the
CleanArchitectureMVP
directory to$ANDROID_STUDIO_FOLDER$/Contents/plugins/android/lib/templates/
- Restart Android Studio
- Copy the
CleanArchitectureMVP
directory to$ANDROID_STUDIO_FOLDER$\plugins\android\lib\templates\
- Restart Android Studio
- In Android Studio, select the
Project
view - Right click and select
New
>Clean + MVP
>Base and Common
. This will generate thepresentation/base
andpresentation/common
packages and files
- In Android Studio, select the
Project
view - Right click and select
New
>Clean + MVP
>DependencyInjection - App
. This will generate thedi/component
,di/module
,di/qualifier
anddi/scope
packages and files. - In you
Application
file create a companion object:
companion object {
lateinit var appComponent: AppComponent
}
- In the
onCreate
method add the following:
appComponent = DaggerAppComponent.builder()
.appModule(AppModule(this))
.build()
- In Android Studio, select the
Project
view - Right click and select
New
>Clean + MVP
>DependencyInjection - Feature
. This will generate acomponent
, amodule
and ascope
for the feature - In your
AppComponent
interface, add the following method:
fun instantiateComponent(module: YourFeatureModule): YourFeatureComponent
Where YourFeatureModule
should be replaced by the generated class in di/module
and YourFeatureComponent
should be replaced by the generated class in di/component
4. In YourFeatureComponent
add the fun inject()
methods required to inject your activities and fragments that depend on that component
5. In your Application
class, add the following:
5.1 a property to hold the component reference private var yourFeatureComponent: YourFeatureComponent? = null
5.2 the following methods to get and release the component:
fun instantiateYourFeatureComponent(activity: FragmentActivity): YourFeatureComponent? {
if (featureComponent == null) {
featureComponent = appComponent.instantiateComponent(FeatureModule(activity))
}
return featureComponent
}
fun releaseFeatureComponent() {
featureComponent = null
}
Where YourFeatureComponent
should be replaced by the generated class in di/component
and the method names should be meaningful, the first starting with instantiante
and the second one starting with release
- In Android Studio, select the
Project
view - Right click and select
New
>Clean + MVP
>Feature - Presentation
- Type in the
Name
of the feature, e.g.TopUp
,Checkout
,PaymentMethods
- Everything else is done automatically, following the guidelines and convetions defined by the team
- You can uncheck the boxes in case you don't want to create:
5.1 the
Contract
and thePresenter
5.2 theActivity
with layout 5.3 theFragment
with layout - If you created an activity don't forget to add it to the
AndroidManifest
- If you created an activity and/or a fragment, remember to check the
TODO
s.
- Don't do it
- They use
ApacheFreeMarker
(.ftl
extension) - This is probably the best docummentation online. Other than that there are several github repositories, this tutorial and this article
- Since
srcDir
andsrcOut
are only mapped to thejava source set
, there is a property inglobals.xml.ftl
namedkotlinMainSourceSet
which doessrcOut?replace('java','kotlin')
and is used inrecipe.xml.ftl
- Since
classToResource
would convertSomeCompositeName
tosome_composite_name
and that doesn't follow the recommended convetion for package names, there are several?replace('_', '')
inrecipe.xml.ftl
and in*.kt.ftl
files located at[TEMPLATE]\root\src\app_package
- Since
applicationIdSuffix
inbuild.gradle
would afftect where the files are generated there is a property inglobals.xml.ftl
namedkotlinMainSourceSet
which doessrcOut?replace('.debug|.staging|.systest', '', 'r')
that is used inrecipe.xml.ftl
and a property namedmainSourceSetPackage
which doespackageName?replace('.debug|.staging|.systest', '', 'r')
and is used in all*.kt.ftl
at[TEMPLATE]\root\src\app_package
- In the
?replace()
function the first argument can be a regex, and if that's the case than the funcion takesr
as the third argument