Android Jetpack
Posted on September 2, 2022
Tags: codeetc
1 Summary
Android uses UI - ViewModel - Repo stack which is MVVM (Model View ViewModel)
2 Activity
- Jetpack compose means there is only 1 activity
3 Intent and Intent Filters
- Intent filters are set in AndroidManifest.xml
- Intent are sent to Activities and Activities will only receive intents listed in the AndroidManifest.xml IntentFilter
- Typically Apps send intent between each other
4 Context
- Context is a bridge between vanilla kotlin and the android ecosystem
- A kotlin class is useless without the android ecosystem, a class that is passed a context can manipulate the android ecosystem, turn on camera, open files, etc
- You have Activity Context and Application Context
- Typically use Application Context
- Activity Context is used when asking for permissions
ActivityCompat.requestPermissions()
5 BackStack
- BackStack is just a Stack of Activities
- Task is a Stack of Stacks, which each stack representing a different App which we name a Task
- [TaskA TaskB] where TaskA = [ScreenX ScreenY ..] and TaskB = [ScreenG ScreenF ..]
Launch Modes
- Standard - Example: inside a browser Activity and you click a link you push a new Browser activity to the backstack
- Single Top - Example: inside a browser Activity and you click a link, nothing is pushed to the backstack
- Single Task - Example: From instagram you click a link that opens a browser, if you go back, you go back to Instagram not the browser
- Single Instance - Example: Typically used for Payment apps and rarely used
6 ViewModel
- This is effectively just the useEffect() and setState() but for android
- The ViewModel gives setters and getters of state for the UI
- Why? Naive state gets destroyed just by rotating the screen while the ViewModel persists state
7 DI
- Dependency injection is parametrization
f(x) = x + 2
->f(x,y) = x + y
- y is the dependency injected into f
- The dependency is the producer
- The injected is the consumer typically a class
Modern DI libraries goes a step further and does automatic instantiation of the parameter, meaning y is set a value automatically.
8 install library
go to libs.version.toml
[versions]
[libraries]
[plugins]
9 Hilt
- First things first is to:
- annotation your Application() Class with
@HiltAndroidApp
(lets us pass android application context in dependency functions)- What is Context? Remember a vanilla kotlin class knows nothing about android or its file system. The Context is the bridge between kotlin and Android ecosystem like opening a file or using the camera, etc.
- annotate your MainActivity with
@AndroidEntryPoint
- annotation your Application() Class with
@HiltAndroidApp
class MyApp: Application()
application>
<
android:name=".MyApp" ...
9.1 Dependency Injection Module (Producers)
@Module
tell us the object the contains dependencies(Producers) for injection.@InstallIn()
tells us when the dependencies are created/destroyed@InstallIn(SingletonComponent::class)
tell us the dependencies lives for the whole app- Not A Real Singleton: This DOES NOT make the dependencies itself a singleton
@InstallIn(ActivityComponent::class)
tell us the dependencies live only for the activity@InstallIn(ViewModelComponent::class)
tell us the dependencies live only for the ViewModel
provideMyApi(): MyApi
is a Producer dependency function declared under the Hilt @Module
Producer meaning whenever a Consumer class needs a MyApi
type it can be injected(Auto-instantiated) with @Inject
- Producer dependency function
provideMyApi(): MyApi
annotations@Provides
tells us this is a dependency@Singleton
is an actual singleton- without it: if you have multiple Consumer that wants to be injected, each Consumer would get a new instantiation of
MyApi
.
- without it: if you have multiple Consumer that wants to be injected, each Consumer would get a new instantiation of
Note: You will NEVER call the producer functions declared in @Module such as provideMyApi
or provideMyRepository
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideMyApi(): MyApi {
return Bleh
}
@Provides
@Singleton
fun provideMyRepository(api: MyApi): MyRepository {
//notice it passes another Dependency Producer MyApi as argument
//Since they are both in @Module MyApi will get injected from provideMyApi()
return api
}
@Provides
@Singleton
fun provideSomethingElse(app: Application) : SomethingElse {
//remember @HiltAndroidApp annotation lets us use android application context in dependencies
return Bleh(app)
}
}
9.2 Class @Inject (Consumers)
@HiltViewModel
tells us this class is a Consumer that wants dependencies to get injected in
@HiltViewModel
class MyViewModel @Inject constructor(
private val repository: MyRepository
): ViewModel() {
}
9.3 DI with Hilt
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
class MyText @Inject constructor() {
val text = "Hello from Hilt!"
}
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject
var myText: MyText
lateinit override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
()
enableEdgeToEdge{
setContent {
DemoOneTheme (modifier = Modifier.fillMaxSize()) { innerPadding ->
Scaffold{
Column
(
Greeting= "hiilo",
name = Modifier.padding(innerPadding)
modifier )
.d("MainActivity", "Injected text: ${myText.text}")
Log(myText.text)
Text
}
}
}
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
(
Text= "Hello $name!",
text = modifier
modifier )
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
{
DemoOneTheme ("Android")
Greeting}
}