In deze tutorial zullen we Android Intents bespreken en ze implementeren met behulp van Kotlin in onze applicatie.
Wat Ga Je Leren?
- Wat zijn Intents?
- Soorten Intents?
- Gebruik van Intents tussen Activiteiten
- Data verzenden met behulp van Android Intents
- Gebruik van Parcelable en Serializable voor het doorgeven van objecten
- Creëren van verkorte Intents
Android Intents
Zoals de naam al zegt, is een Intent iets dat wordt gebruikt om een bepaalde actie uit te voeren met betrekking tot de stroom van de Android-applicatie. Intents kunnen worden gebruikt om:
- Het starten van een nieuwe activiteit en het doorgeven van gegevens.
- Het starten van fragmenten/communicatie tussen fragmenten.
- Starten/stoppen van een service.
- Activiteiten starten vanuit een broadcast receiver
In deze tutorial zullen we voornamelijk kijken naar intents om activiteiten te beheren. Een intent-definitie bestaat voornamelijk uit een instantie van de huidige activiteit. We stellen de componentnaam in, die kan zijn: De volledig gekwalificeerde klassenaam van de te bellen activiteit. Dit type Intent is een expliciete intentie. Een actie zoals een URL, telefoonnummer, locatie. Het zal alle beschikbare toepassingen van die soorten weergeven. Dit valt onder de categorie impliciete intentie. In Kotlin is dit de manier om een activiteit te creëren.
val intent = Intent(this, OtherActivity::class.java)
startActivity(intent)
startActivity
zou OtherActivity
aan de activiteitenstapel toevoegen en starten. Hoe weet onze applicatie welke activiteit als eerste moet worden aangeroepen? In het AndroidManifest.xml stellen we het intent-filter in met de actie android.intent.action.MAIN
en de categorie android.intent.category.LAUNCHER
op de eerste activiteit die moet worden gestart wanneer onze applicatie wordt geopend. finish()
wordt gebruikt om een activiteit te vernietigen en uit de stapel te verwijderen.
Intent-vlaggen
Vlaggen zijn als opties die kunnen worden ingesteld op intenties om het startproces aan te passen. Als je elke keer dezelfde activiteit start, wordt er telkens een nieuwe instantie gemaakt en aan de activiteitenstapel toegevoegd. Om dit te voorkomen, kun je de vlaggen gebruiken: FLAG_ACTIVITY_SINGLE_TOP
– Als ingesteld, wordt de activiteit niet gestart als deze al wordt uitgevoerd bovenaan de activiteitenstapel.
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
Vergelijkbaar zal het gebruik van de vlag FLAT_ACTIVITY_CLEAR_TOP
geen andere instantie van de activiteit starten als deze al bestaat. Deze vlag wist alle activiteiten boven de aangeroepen activiteit en plaatst deze bovenaan de stapel.
Data doorgeven via intenties
Om gegevens door te geven aan nieuwe activiteiten gebruiken we sleutel-waardeparen binnen de functie putExtra
, putStringArrayListExtra
, enz. putExtra geeft over het algemeen de basisgegevenstypen door, zoals Int, Float, Char, Double, Boolean, String samen met IntArray… enz.
val intent = Intent(this, OtherActivity::class.java)
intent.putExtra("keyString", "Androidly String data")
Deze Extra-velden worden onder de motorkap verpakt in het Bundle
-object dat uiteindelijk alle gegevens bevat die moeten worden doorgegeven. Om de gegevens in de andere activiteit op te halen, moeten we de extras
-eigenschap gebruiken via de bundles
. Gegevens ophalen in de nieuwe activiteit
val bundle: Bundle? = intent.extras
val string: String? = intent.getString("keyString")
val myArray: ArrayList<String>? = intent.getStringArrayList("myArray")
intent
, extras
zijn equivalent aan getIntent()
, getExtras()
in Java. We hebben een optioneel type Bundle?
gebruikt om NullPointerExceptions
te voorkomen wanneer er geen gegevens beschikbaar zijn. Op dezelfde manier hebben we voor de gegevens die worden opgehaald met behulp van de sleutels, optionele typen gebruikt om NPE te voorkomen die kan optreden wanneer de sleutel onjuist is.
Gebruik van Parcelable en Serializable gegevens
Soms moeten we een compleet object van de ene activiteit naar de andere doorgeven. Dit is niet mogelijk tenzij we de Parcelable- of Serializable-interface implementeren. Verschil tussen Parcelable en Serializable
- Parcelable-interface is een onderdeel van de Android SDK. Serializable is een standaardinterface van Java.
- In Parcelable moet u alle gegevens instellen die u wilt doorgeven in een Parcel-object en ook de writeToParcel() methodes overschrijven, enzovoort. Bij Serializable is het voldoende om de interface te implementeren om de gegevens door te geven.
- Parcelable is sneller dan Serializable.
Verzenden van Parcelable-gegevens
Kotlin biedt enkele handige annotaties om ons te redden van het overschrijven van de writeToParcel()-methode om de gegevens in Parcelable in te stellen. In plaats daarvan kunnen we de @Parcelize-annotatie gebruiken zoals hieronder getoond:
@Parcelize
data class Student(
val name: String = "Anupam",
val age: Int = 24
) : Parcelable
Let op: Momenteel moet u de volgende code toevoegen aan uw build.gradle voor de @Parcelize-annotatie om te werken:
android {
androidExtensions {
experimental = true
}
//..
....
}
In uw Activity doet u het volgende:
val student = Student()
val intent = Intent(this, OtherActivity::class.java)
intent.putExtra("studentData", student)
startActivity(intent)
Verzenden van Serializable-gegevens
data class Blog(val name: String = "Androidly", val year: Int = 2018) : Serializable
val blog = Blog("a", 1)
val intent = Intent(this, OtherActivity::class.java)
intent.putExtra("blogData", blog as Serializable)
startActivity(intent)
Laten we de zojuist opgedane kennis gebruiken in ons Android Studio-project.
Projectstructuur
Opmaakcode
De code voor de lay-out activity_main.xml
wordt hieronder gegeven:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/btnSimpleIntent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SIMPLE INTENT" />
<Button
android:id="@+id/btnSimpleIntentAndData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SIMPLE INTENT WITH DATA" />
<Button
android:id="@+id/btnParcelableIntent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Parcelable Intent" />
<Button
android:id="@+id/btnSerializableIntent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Serializable Intent" />
<Button
android:id="@+id/btnBrowserIntent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Browser Intent" />
<Button
android:id="@+id/btnMapsIntent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Maps Intent" />
<Button
android:id="@+id/btnGenericIntent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Generic Intent" />
</LinearLayout>
De code voor de lay-out activity_other.xml
wordt hieronder gegeven:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Intent Data goes here" />
</LinearLayout>
Activiteitscode
De code voor de klasse MainActivity.kt wordt hieronder gegeven:
package net.androidly.androidlyintents
import android.app.Activity
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Parcelable
import android.view.View
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.activity_main.*
import java.io.Serializable
@Parcelize
data class Student(
val name: String = "Anupam",
val age: Int = 24
) : Parcelable
data class Blog(val name: String = "Androidly", val year: Int = 2018) : Serializable
class MainActivity : AppCompatActivity(), View.OnClickListener {
fun Context.gotoClass(targetType: Class<*>) =
ComponentName(this, targetType)
fun Context.startActivity(f: Intent.() -> Unit): Unit =
Intent().apply(f).run(this::startActivity)
inline fun <reified T : Activity> Context.start(
noinline createIntent: Intent.() -> Unit = {}
) = startActivity {
component = gotoClass(T::class.java)
createIntent(this)
}
var arrayList = ArrayList<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnSimpleIntent.setOnClickListener(this)
btnSimpleIntentAndData.setOnClickListener(this)
btnParcelableIntent.setOnClickListener(this)
btnSerializableIntent.setOnClickListener(this)
btnBrowserIntent.setOnClickListener(this)
btnMapsIntent.setOnClickListener(this)
btnGenericIntent.setOnClickListener(this)
arrayList.add("Androidly")
arrayList.add("Android")
arrayList.add("Intents")
}
override fun onClick(v: View?) {
when (v?.id) {
R.id.btnSimpleIntent -> {
val intent = Intent(this, OtherActivity::class.java)
startActivity(intent)
}
R.id.btnSimpleIntentAndData -> {
val intent = Intent(this, OtherActivity::class.java)
with(intent)
{
putExtra("keyString", "Androidly String data")
putStringArrayListExtra("arrayList", arrayList)
putExtra("keyBoolean", true)
putExtra("keyFloat", 1.2f)
}
startActivity(intent)
}
R.id.btnParcelableIntent -> {
val student = Student()
val intent = Intent(this, OtherActivity::class.java)
intent.putExtra("studentData", student)
startActivity(intent)
}
R.id.btnSerializableIntent -> {
val blog = Blog("a", 1)
val intent = Intent(this, OtherActivity::class.java)
intent.putExtra("blogData", blog as Serializable)
startActivity(intent)
}
R.id.btnBrowserIntent -> {
val url = "https://www.androidly.net"
val uri = Uri.parse(url)
val intent = Intent(Intent.ACTION_VIEW, uri)
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
} else {
Toast.makeText(applicationContext, "No application found", LENGTH_LONG).show()
}
}
R.id.btnMapsIntent -> {
val loc = "12.9538477,77.3507442"
val addressUri = Uri.parse("geo:0,0?q=" + loc)
val intent = Intent(Intent.ACTION_VIEW, addressUri)
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
} else {
Toast.makeText(applicationContext, "No application found", LENGTH_LONG).show()
}
}
else -> start<OtherActivity> {
putExtra("keyString", "Androidly Generic Intent")
}
}
}
}
In de bovenstaande code hebben we knoppen gebruikt voor elk type Intent. We hebben de `with`-expressie van Kotlin gebruikt om te voorkomen dat we elke keer gegevens over het `intent`-object instellen. Bovendien hebben we drie verschillende intents gemaakt naast degenen die hierboven al zijn besproken. Een browser-intent wordt gebruikt om de URL die aanwezig is in het intent in de browser-app te openen. Hiervoor wordt `Intent(Intent.ACTION_VIEW, uri)` gebruikt. Een locatie-intent wordt gebruikt om de locatie met lat,lng in de kaarten-applicatie te openen. Beide zijn impliciete intents. Ten slotte hebben we een generieke intent gebruikt waarbij we de extensiefuncties en lambda-expressies van Kotlin gebruiken om een verkorte functie te maken om een intent te starten. Hiervoor gebruiken we de volgende functies:
fun Context.gotoClass(targetType: Class<*>) =
ComponentName(this, targetType)
fun Context.startActivity(createIntent: Intent.() -> Unit): Unit =
Intent().apply(createIntent).run(this::startActivity)
inline fun <reified T : Activity> Context.start(
noinline createIntent: Intent.() -> Unit = {}
) = startActivity {
component = gotoClass(T::class.java)
createIntent(this)
}
startActivity is een extensiefunctie die zoekt naar een hogere-orde functie als parameter. Dankzij dit kunnen we nu intenties starten in slechts een paar regels als: start<OtherActivity>
De code voor de OtherActivity.kt-klasse staat hieronder.
package net.androidly.androidlyintents
import android.content.Context
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_other.*
class OtherActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_other)
val bundle: Bundle? = intent.extras
bundle?.let {
bundle.apply {
//Intent met gegevens
val string: String? = getString("keyString")
textView.text = string
val myArray: ArrayList? = getStringArrayList("myArray")
showToast(message = "MyArrayList size:${myArray?.size}")
val arrayList: ArrayList? = getStringArrayList("arrayList")
showToast(message = "ArrayList size:${arrayList?.size}")
val float: Float? = bundle.get("keyFloat") as Float?
var boolean = bundle.get("boolean") as? Boolean
showToast(message = "Float data is:$float")
showToast(message = "Boolean data is:$boolean")
boolean = bundle.get("keyBoolean") as? Boolean
showToast(message = "Boolean correct key data is:$boolean")
}
bundle.apply {
//Seriaal gegevens
val blog = getSerializable("blogData") as Blog?
if (blog != null) {
textView.text = "Blog name is ${blog?.name}. Year started: ${blog?.year}"
}
}
bundle.apply {
//Parcelable gegevens
val student: Student? = getParcelable("studentData")
if (student != null) {
textView.text = "Name is ${student?.name}. Age: ${student?.age}"
}
}
}
}
private fun showToast(context: Context = applicationContext, message: String, duration: Int = Toast.LENGTH_SHORT) {
if (!message.contains("null"))
Toast.makeText(context, message, duration).show()
}
}
We hebben let
en apply
gebruikt om optionele typen te behandelen en te voorkomen dat we bundle.field in elke regel moeten gebruiken. De uitvoer van de bovenstaande applicatie in actie wordt hieronder gegeven: Hiermee komt er een einde aan deze tutorial over Android-intenties in Kotlin. U kunt het project downloaden vanaf de onderstaande link.