The most important Android components:
Activity
: The visible part of your app, displaying View objectsFragment
: Allows flexible modularisation of Views within ActivitiesService
: Runs code in the background without a ViewContentProvider
: Provides data for your appBroadcastReceiver
: Used to receive messages between activies or even appsIntent
: Allows inter-component communication, used e.g. to start Activities and transfer
information between themAn activity has essentially four states:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onStart() {
super.onStart()
}
override fun onRestart() {
super.onRestart()
}
override fun onResume() {
super.onResume()
}
override fun onPause() {
super.onPause()
}
override fun onStop() {
super.onStop()
}
override fun onDestroy() {
super.onDestroy()
}
}
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
...
}
}
...
}
// launches a new activity
abstract void startActivity(Intent intent)
//launches a new service
abstract ComponentName startService(Intent service)
//Registers a BroadCast Receiver
abstract Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
val dialIntent = Intent()
dialIntent.action = Intent.ACTION_DIAL //specifiy the action to execute
dialIntent.data = Uri.parse("tel:0711-1234") //provide action data
startActivity(dialIntent)
<intent-filter>
element in your manifest file. <intent-filter>
element in the app's manifest file,
nested in the corresponding app component (such as an <activity>
element). <intent-filter>
, you can specify the type of intents to accept using one or
more of these three elements:<action>
- Declares the intent action accepted, in the name attribute. The value must be the
literal string value of an action, not the class constant.<data>
- Declares the type of data accepted, using one or more attributes that specify
various aspects of the data URI (scheme, host, port, path) and MIME type.<category>
- Declares the intent category accepted, in the name attribute. The value must be
the literal string value of an action, not the class constant.<activity android:name="MainActivity">
<!-- This activity is the main entry, should appear in app launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Note: To receive implicit intents, you must include the CATEGORY_DEFAULT category in the intent filter.
putExtra()
method of the
Intent
class can be usedval intent = Intent(applicationContext, LoginActivity::class.java)
intent.putExtra("Name", "Login")
startActivity(intent)
Note: An explicit intent is always delivered to its target, regardless of any intent filters the component declares.
Install time verification
Application sandboxing (process separation)
Permissions
INTERNET
, READ_CONTACTS
,...SecurityException
s<uses-permission>
tags app manifest must be
used <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.app.myapp" >
<uses-permission android:name="android.permission.RECEIVE_SMS" />
...
</manifest>
To request a dangerous permission at runtime, some additional code is required in your Activity class:
// Assume thisActivity is the current activity
val permissionCheck = ContextCompat.checkSelfPermission(LocalContext.current, Manifest.permission.WRITE_CALENDAR)
// ...
// Should we show an explanation?
if (shouldShowRequestPermissionRationale(
LocalContext.current as Activity,
Manifest.permission.READ_CALENDAR)
) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// ... see next slide
// ...
else {
val permissionLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
// Permission granted
} else {
// Handle permission denial
}
}
permissionLauncher.launch(Manifest.permission.READ_CONTACTS)
}
// ...
val uri = Uri.parse("https://www.google.com")
val intent = Intent(Intent.ACTION_VIEW, uri)
context.startActivity(intent)
AndroidView()
loadUrl()
@Composable
fun WebView() {
AndroidView(factory = {
WebView(it).apply {
//any other configuration
}
}, update = {
it.loadUrl("https://www.google.com")
})
}
<uses-permission android:name="android.permission.INTERNET" />
this.webViewClient = WebViewClient()
WebView
s settings but you also have to add @SuppressLint("SetJavaScriptEnabled")
annotation:this.settings.javaScriptEnabled = true
WebChromeClient
like this:var currentProgress by remember { mutableStateOf(0f) }
...
this.webChromeClient = object : WebChromeClient() {
override fun onProgressChanged(view: WebView?, newProgress: Int) {
super.onProgressChanged(view, newProgress)
currentProgress = newProgress/100f
}
}
LinearProgressIndicator(progress = { currentProgress }, modifier = Modifier.fillMaxWidth())
Note: A progress bar can be used for other purposes too of course.