במדריך זה, נדבר על 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. ניתן להוריד את הפרויקט מהקישור למטה.