טיפול ב-Intent בין פעילויות ב-Android באמצעות Kotlin

במדריך זה, נדבר על Android Intents ונממש אותם באמצעות Kotlin באפליקציה שלנו.

מה תלמד?

  • מהם Intents?
  • סוגי Intents?
  • שימוש ב-Intents בין לבין פעילויות
  • שליחת נתונים באמצעות Android Intents
  • שימוש ב-Parcelable וב-Serializable לשליחת אובייקטים
  • יצירת Intents מקצרים

Android Intents

כפי שהשם מרמז, Intent הוא משהו שמשמש לביצוע פעולה מסוימת ביחס לזרימת האפליקציה של Android. Intents ניתן להשתמש בהם על מנת:

  • להתחיל פעולות חדשות ולשלוח נתונים.
  • להתחיל Fragmentים / לתקשר בינהם.
  • להתחיל / לסיים שירות.
  • להשיק פעולות ממקבל השדרוגים.

במדריך זה, נתמקד בעיקר ב-intents לטיפול בפעולויות. הגדרת Intent בעיקר מורכבת ממופע של פעולה הנוכחית. אנו מגדירים את שם הרכיב, שיכול להיות: שם המחלקה המובילה מלאה של הפעולה שיש לקרוא לה. סוג זה של Intent הוא intent ישיר. פעולה כמו URL, מספר טלפון, מיקום. זה יציג את כל היישומים הזמינים של אותם סוגים. זה נכנס לקטגוריית intent משתמש. ב-Kotlin, הנה הדרך ליצירת פעולה.

val intent = Intent(this, OtherActivity::class.java)
startActivity(intent)

startActivity תוסיף את OtherActivity לערימת הפעילויות ותפעיל אותה. איך האפליקציה שלנו מבינה איזו פעילות היא הראשונה שתיקרא? ב־AndroidManifest.xml אנו מגדירים את מסנני הכוונת עם הפעולה android.intent.action.MAIN והקטגוריה android.intent.category.LAUNCHER על הפעילות הראשונה שתיפתח כאשר האפליקציה שלנו נפתחת. finish() משמש להשמיד פעילות ולהסיר אותה מהערימה.

דגלי Intent

דגלים הם כמו אפשרויות שניתן להגדיר על ידי Intent כדי להתאים אישית את תהליך ההפעלה. אם אתה מפעיל את אותה פעילות תמיד, יווצרה מופע חדש ויתווסף לערימת הפעילויות. כדי למנוע זאת, ניתן להשתמש בדגלים: FLAG_ACTIVITY_SINGLE_TOP – אם מוגדר, הפעילות לא תיפתח אם היא כבר רצה בחלק העליון של ערימת הפעילויות.

intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP

באופן דומה, בשימוש בדגל FLAT_ACTIVITY_CLEAR_TOP לא יופעל מופע נוסף של הפעילות אם היא כבר קיימת. דגל זה ינקה את כל הפעילויות מעל הפעילות שנקראה ויקבע אותה בחלק העליון של הערימה.

מעבר נתונים דרך Intents

להעביר נתונים לפעילויות החדשות, אנו משתמשים בזוגות ערכים מפתח בתוך הפונקציה putExtra, putStringArrayListExtra וכו '. בדרך כלל, putExtra מעביר סוגי בסיס כגון Int, Float, Char, Double, Boolean, String בנוסף ל- IntArray… וכו '.

val intent = Intent(this, OtherActivity::class.java)
intent.putExtra("keyString", "Androidly String data")

שדות אלה של Extras מסתתרים תחת ה- Bundle ובסופו של דבר מחזיקים את כל הנתונים שיש להעביר. כדי לאחזר את הנתונים בפעילות השנייה, עלינו להשתמש במאפיין extras מעל ה- bundles. אחזור נתונים בפעילות החדשה

val bundle: Bundle? = intent.extras
val string: String? = intent.getString("keyString")
val myArray: ArrayList<String>? = intent.getStringArrayList("myArray")

intent, extras הם שקולים ל- getIntent(), getExtras() ב-Java. השתמשנו בסוג nullable Bundle? כדי למנוע מופעים של NullPointerExceptions כאשר אין נתונים. באופן דומה, לנתונים שמתקבלים באמצעות המפתחות, השתמשנו בסוגי nullable כדי למנוע NPE שעשוי להתרחש כאשר המפתח אינו תקין.

שימוש בנתונים דרך Parcelable ו- Serializable

לעיתים קרובות אנו זקוקים להעביר אובייקט מלא מפעילות אחת לאחרת. זה אינו אפשרי אלא אם נממש את ממשקי Parcelable או Serializable. השונות בין Parcelable ו- Serializable

  • ממשק Parcelable הוא חלק מ-SDK של אנדרואיד. Serializable הוא ממשק סטנדרטי של Java.
  • ב-Parcelable יש להגדיר את כל הנתונים שברצונך להעביר באמצעות אובייקט Parcel ולדרוס את השיטות writeToParcel() וכדומה. ב-Serializable, המימוש של הממשק מספיק להעברת הנתונים.
  • Parcelable מהיר יותר מ-Serializable.

שליחת נתונים באמצעות Parcelable

ב-Kotlin ישנן אננוטציות שימושיות שמצילות אותנו מהצורך לדרוס את השיטה writeToParcel() כדי להגדיר את הנתונים ב-Parcelable. במקום זאת, נוכל להשתמש ב-@Parcelize, כפי שמוצג למטה:

@Parcelize
data class Student(
        val name: String = "Anupam",
        val age: Int = 24
) : Parcelable

הערה: כרגע יש להוסיף את הקוד הבא ב-fuild.gradle שלך כדי שה-@Parcelize יעבוד:

android {
    androidExtensions {
        experimental = true
    }
//..
....
}

ב-Activity שלך עשה את זה:

val student = Student()
val intent = Intent(this, OtherActivity::class.java)
intent.putExtra("studentData", student)
startActivity(intent)

שליחת נתונים באמצעות 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)

בואו נשתמש בידע שלמעלה בפרויקט שלנו ב-Android Studio.

מבנה הפרויקט

קוד תצוגה

הקוד עבור תצוגת activity_main.xml ניתן להלן:

<?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>

הקוד עבור תצוגת activity_other.xml ניתן להלן:

<?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>

קוד פעילות

הקוד עבור מחלקת MainActivity.kt ניתן להלן:

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")
            }
        }
    }

}

בקוד לעיל, השתמשנו בכפתורים עבור כל סוג של Intent. השתמשנו בביטוי with של Kotlin כדי למנוע הגדרת נתונים על האובייקט intent בכל פעם. בנוסף, יצרנו שלושה Intents שונים מלבד אלה שכבר נדונו לעיל. כדי להפעיל את ה-URL המצוי ב-intent באפליקציית הדפדפן, השתמשנו ב-intent של דפדפן. הוא משתמש בIntent(Intent.ACTION_VIEW, uri). ל-Intent השני, שימוש בכתובת lat,lng על מנת להפעיל אותה באפליקציית המפות. שניהם הם Intents מרמזיים. לבסוף, השתמשנו ב-Intent גנרי שבו אנו משתמשים בפונקציות הרחבה של Kotlin ובביטויי למבד על מנת ליצור פונקציה קצרה להפעלת Intent. לשם כך, אנו משתמשים בפונקציות הבאות:

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 היא פונקציית הרחבה המחפשת פונקציה מסדר גבוה כפרמטר שלה. בזכות זה, אנו יכולים כעת להשיג מטרות בכמה שורות קוד כגון: start<OtherActivity> הקוד עבור מחלקת OtherActivity.kt ניתן להלן.

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 עם נתונים
                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 {
                //נתונים סדורים
                val blog = getSerializable("blogData") as Blog?
                if (blog != null) {
                    textView.text = "Blog name is ${blog?.name}. Year started: ${blog?.year}"

                }
            }

            bundle.apply {
                //נתונים 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()
    }
}

השתמשנו ב- let ו- apply כדי לטפל בסוגי nullable ולמנוע מבצע פעולת bundle.field בכל שורה. פלט היישום לעיל מוצג להלן: זה מסיים את המדריך על כוונת Android בשפת Kotlin. ניתן להוריד את הפרויקט מהקישור למטה.

AndroidlyIntents

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