Gestion des intentions Android entre les activités en utilisant Kotlin

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.

AndroidlyIntents

Source:
https://www.digitalocean.com/community/tutorials/android-intent-handling-between-activities-using-kotlin