Dans ce tutoriel, nous discuterons des Intentions Android et les mettrons en œuvre en utilisant Kotlin dans notre application.
Que apprendrez-vous?
- Quelles sont les Intentions?
- Types d’Intentions?
- Utilisation des Intentions entre les activités
- Envoi de données en utilisant les Intentions Android
- Utilisation de Parcelable et Serializable pour passer des objets
- Création d’intentions abrégées
Intentions Android
Comme son nom l’indique, une Intention est quelque chose qui est utilisé pour effectuer une action par rapport au flux de l’application Android. Les Intentions peuvent être utilisées pour :
- Démarrer une nouvelle activité et passer des données.
- Démarrer des fragments/Communiquer entre les fragments.
- Démarrer/Arrêter un service.
- Lancer des activités à partir d’un récepteur de diffusion
Dans ce tutoriel, nous examinerons principalement les intentions pour gérer les activités. Une définition d’intention consiste principalement en une instance de l’activité actuelle. Nous définissons le nom du composant qui peut être : Le nom de classe complètement qualifié de l’activité à appeler. Ce type d’intention est une intention explicite. Une action telle qu’une URL, un numéro de téléphone, un emplacement. Il affichera toutes les applications disponibles de ces types. Cela relève de la catégorie des intentions implicites. En Kotlin, voici la manière de créer une activité.
val intent = Intent(this, OtherActivity::class.java)
startActivity(intent)
startActivity
ajouterait OtherActivity
à la pile d’activités et la lancerait. Comment notre application réalise-t-elle quelle activité doit être invoquée en premier? Dans le fichier AndroidManifest.xml, nous définissons le filtre d’intention avec l’action android.intent.action.MAIN
et la catégorie android.intent.category.LAUNCHER
sur la première activité à lancer lorsque notre application s’ouvre. finish()
est utilisé pour détruire une activité et la supprimer de la pile.
Drapeaux d’intention
Les drapeaux sont comme des options qui peuvent être définies sur des intentions pour personnaliser le processus de lancement. Si vous démarrez la même activité à chaque fois, une nouvelle instance serait créée et ajoutée à la pile d’activités. Pour éviter cela, vous pouvez utiliser les drapeaux : FLAG_ACTIVITY_SINGLE_TOP
– Si défini, l’activité ne sera pas lancée si elle est déjà en cours d’exécution en haut de la pile d’activités.
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
De même, l’utilisation d’un drapeau FLAT_ACTIVITY_CLEAR_TOP
ne lancera pas une autre instance de l’activité si elle existe déjà. Ce drapeau effacerait toutes les activités au-dessus de l’activité appelée et la placerait en haut de la pile.
Transmettre des données via des intentions
Pour transmettre des données aux nouvelles activités, nous utilisons des paires clé-valeur à l’intérieur de la fonction putExtra
, putStringArrayListExtra
, etc. putExtra transmet généralement les types de base tels que Int, Float, Char, Double, Boolean, String, ainsi que IntArray, etc.
val intent = Intent(this, OtherActivity::class.java)
intent.putExtra("keyString", "Androidly String data")
Ces champs Extras sont enveloppés dans l’objet Bundle
qui contient finalement toutes les données à transmettre. Pour récupérer les données dans l’autre activité, nous devons utiliser la propriété extras
sur les bundles
. Récupération des données dans la nouvelle activité
val bundle: Bundle? = intent.extras
val string: String? = intent.getString("keyString")
val myArray: ArrayList<String>? = intent.getStringArrayList("myArray")
intent
, extras
sont équivalents à getIntent()
, getExtras()
en Java. Nous avons utilisé un type nullable Bundle?
pour éviter les NullPointerExceptions
lorsque les données n’existent pas. De même, pour les données récupérées à l’aide des clés, nous avons utilisé des types nullable pour éviter les NPE qui peuvent se produire lorsque la clé est incorrecte.
Utilisation de données Parcelable et Serializable
Parfois, nous avons besoin de transmettre un objet complet d’une activité à une autre. Cela n’est pas possible à moins d’implémenter l’interface Parcelable ou Serializable. Différence entre Parcelable et Serializable
- L’interface Parcelable fait partie de l’API Android. Serializable est une interface standard de Java.
- Dans Parcelable, vous devez définir toutes les données que vous devez transmettre dans un objet Parcel et également substituer les méthodes writeToParcel(), etc. Dans Serializable, implémenter l’interface est suffisant pour transmettre les données.
- Parcelable est plus rapide que Serializable.
Envoi de données Parcelable
Kotlin propose quelques annotations pratiques pour nous éviter de devoir substituer la méthode writeToParcel() pour définir les données sur Parcelable. À la place, nous pouvons utiliser l’annotation @Parcelize comme indiqué ci-dessous:
@Parcelize
data class Student(
val name: String = "Anupam",
val age: Int = 24
) : Parcelable
Note : Actuellement, dans votre build.gradle, vous devez ajouter le code suivant pour que l’annotation @Parcelize fonctionne :
android {
androidExtensions {
experimental = true
}
//..
....
}
Dans votre Activity, vous faites :
val student = Student()
val intent = Intent(this, OtherActivity::class.java)
intent.putExtra("studentData", student)
startActivity(intent)
Envoi de données Serializable
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)
Utilisons les connaissances ci-dessus dans notre projet Android Studio.
Structure du projet
Code de mise en page
Le code de la mise en page activity_main.xml
est donné ci-dessous:
<?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>
Le code de la mise en page activity_other.xml est donné ci-dessous:
<?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>
Code d’activité
Le code de la classe MainActivity.kt est donné ci-dessous:
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")
}
}
}
}
Dans le code ci-dessus, nous avons utilisé des boutons pour chaque type d’intent. Nous avons utilisé l’expression with
de Kotlin pour éviter de définir les données sur l’objet intent
à chaque fois. De plus, nous avons créé trois intents différents en dehors de ceux déjà discutés ci-dessus. Un intent de navigateur est utilisé pour lancer l’URL présente dans l’intent dans l’application de navigateur. Il utilise Intent(Intent.ACTION_VIEW, uri)
. Un intent de localisation est utilisé pour lancer la localisation lat,lng dans l’application Maps. Tous deux sont des intents implicites. Enfin, nous avons utilisé un intent générique dans lequel nous utilisons les fonctions d’extension de Kotlin et les expressions lambda pour créer une fonction abrégée pour lancer un intent. Pour cela, nous utilisons les fonctions suivantes:
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 est une fonction d’extension qui recherche une fonction d’ordre supérieur en tant que paramètre. Grâce à cela, nous pouvons maintenant lancer des intents en aussi peu de lignes que : start<OtherActivity>
Le code de la classe OtherActivity.kt est donné ci-dessous.
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 avec des données
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 {
//Données sérialisables
val blog = getSerializable("blogData") as Blog?
if (blog != null) {
textView.text = "Blog name is ${blog?.name}. Year started: ${blog?.year}"
}
}
bundle.apply {
//Données Parcelable
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()
}
}
Nous avons utilisé let
et apply
pour gérer les types nullable et éviter de faire bundle.field à chaque ligne. La sortie de l’application ci-dessus en action est donnée ci-dessous : Cela met fin à ce tutoriel sur les intents Android en Kotlin. Vous pouvez télécharger le projet à partir du lien ci-dessous.