Compose
Graddle
Project Module
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
...
}
}
App Module
implementation "com.github.AlexExiv.Router-Android:router:$version"
implementation "com.github.AlexExiv.Router-Android:annotations:$version"
implementation "com.github.AlexExiv.Router-Android:compose:$version" // add support of compose
kapt "com.github.AlexExiv.Router-Android:processor:$version"
Code example
You can find an example project at sample-compose
Application
In the first step, we need to configure our Application
class.
Your Application
class should be inherited from the ComposeApplication
class and create and initialize the RouterComponentImpl
in the onCreateRouter
method.
If you're not using Component injection, the App class should look like this:
class App: ComposeApplication<RouterComponentImpl>()
{
override fun onCreateRouter()
{
routerComponent = RouterComponentImpl()
routerComponent.initialize(MainPath(), { _, _ -> AnimationControllerComposeSlide() })
}
}
Otherwise:
class App: ComposeApplication<RouterComponentImpl>()
{
lateinit var component: AppComponent
override fun onCreateComponent()
{
super.onCreateComponent()
component = DaggerAppComponent.builder()
.appModule(AppModule(AppData("App String")))
.userModule(UserModule(UserData()))
.build()
}
override fun onCreateRouter()
{
routerComponent = RouterComponentImpl()
routerComponent.initialize(MainPath(), { _, _ -> AnimationControllerComposeSlide() }, component)
}
}
MainActivity
The second step involves implementing a simple MainActivity
class. This class should inherit from the ComposeActivity
class from the bootstrap package.
Simple MainActivity
class:
class MainActivity: ComposeActivity()
{
/**
* Root content. It's entry point for your compose view
*/
@Composable
override fun Content()
{
RouterTheme {
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
ComposeNavigator(router = router)
}
}
}
}
It's enough if you're using single activity way. Now let's create our first Compose
view
SimpleView
To create a screen in Compose, you need to create a class or data class that inherits from the BaseViewCompose
class in the bootstrap package. Then, override the Root
method, which serves as the entry point.
/**
* This view represents screen
*/
class SimpleView: BaseViewCompose
{
@Composable
override fun Root() // this is a Root view for the screen here you can place your Compose code
{
Simple()
}
}
@Composable
fun Simple()
{
Box(modifier = Modifier.fillMaxSize()) {
Row {
Column {
Text(text = "I'm a simple Compose view")
}
}
}
}
SimplePath
Using with class we will navigate to the SimpleView
screen
class SimplePath: RoutePath
Now we have to connect SimplePath
with SimpleView
. In the case of Compose we have the same way of implementing of RouteControllers and Paths. Look at simple example bellow
@Route
abstract class SimpleRouteController: RouteController<SimplePath, SimpleView>()
It generates the onCreateView
method by default if you don't need to pass there extra parameters
Here, we have another example of a simple RouteController
. In this case, we aim to pass parameters to the screen. When you need to transmit data to your Compose view, you'll need to implement onCreateView
yourself and deliver the data to the view, perhaps in the constructor.
Important: Ensure that the data is serializable to be preserved in the state.
data class SimplePath(val title: String): RoutePath
@Route
class SimpleRouteController: RouteController<SimplePath, SimpleView>()
{
override fun onCreateView(path: SimplePath): SimpleView = SimpleView(path.title)
}
Code example with ViewModel
Now let's take a look at how RouteController
looks like when our ComposeView
has a ViewModel
RouteController
When working with ViewModels, it's beneficial to create a typealias
of RouteController
typealias RouteControllerApp<Path, VM, V> = RouteControllerVM<Path, VM, AndroidComposeViewModelProvider, V> // if you don't use Component fo injection
typealias RouteControllerApp<Path, VM, V> = RouteControllerVMC<Path, VM, AndroidComposeViewModelProvider, V, AppComponent> // otherwise
If you're not passing arguments to your screen, the definition of RouteController
remains almost the same, except for adding SimpleViewModel
to the RouteController.
class SimplePath: RoutePath // The same
// Simple case
@Route
abstract class SimpleRouteController: RouteControllerApp<SimplePath, SimpleViewModel, SimpleView>()
If you wish to pass arguments, you must override the onCreateViewModel
method and create the ViewModel as shown in the code below:
class SimplePath(val step: Int): RoutePath
// When you need to pass data to the ViewModel you have to override the onCreateViewModel method
@Route
abstract class SimpleRouteController: RouteControllerApp<SimplePath, SimpleViewModel, SimpleView>()
{
override fun onCreateViewModel(modelProvider: AndroidComposeViewModelProvider, path: SimplePath): SimpleViewModel =
modelProvider.getViewModel { SimpleViewModel(path.step, it) }
}
If you use Hilt as dependency injection framework use compose-hilt module and read documentation to know how to pass arguments.
SimpleView
But also we have to add ViewModel to the SimpleFragment
.
Define a base fragment class with ViewModel from the Fragment
class
class SimpleView: BaseViewCompose()
{
@Composable
override fun Root()
{
Simple(viewModel = routerViewModel())
}
}
@Composable
fun Simple(
viewModel: SimpleViewModel // our ViewModel
)
{
val router = LocalRouter.currentOrThrow // Access current router
Surface(modifier = Modifier.fillMaxSize()){
Column(modifier = Modifier.fillMaxSize()){
Row {
Text(text = "I'm a SimpleView with ViewModel")
}
}
}
}
SimpleViewModel
SimpleViewModel
should be inherited from the AndroidViewModel
class in the bootstrap package.
class SimpleViewModel(val step: Int, app: Application): AndroidViewModel(app)
It's a good practice to create a BaseViewModel
class. See example of BaseViewModel
See other examples here
You can find full example of project at sample-compose
Last updated
Was this helpful?