在本教程中,我们将讨论Android意图,并在我们的应用程序中使用Kotlin实现它们。
你会学到什么?
- 意图是什么?
- 意图的类型?
- 在活动之间使用意图
- 使用Android意图发送数据
- 使用Parcelable和Serializable传递对象
- 创建速记意图
Android Intents
顾名思义,意图是用来执行与Android应用程序流相关的操作的东西。意图可用于:
- 开始新的活动,传递一些数据。
- 开始片段/片段之间的通信。
- 开始/结束服务。
- 从广播接收器启动活动
在本教程中,我们将主要关注处理活动的意图。意图定义主要由当前活动的实例组成。我们设置组件名称,它可以是:要调用的活动的全限定类名。这种意图是一种显性意图 。URL、电话号码、位置等操作。它将显示这些类型的所有可用应用程序。这属于** 隐含意图** 类别。在科特林,以下是创建活动的方法。
1val intent = Intent(this, OtherActivity::class.java)
2startActivity(intent)
startActivity
将在活动堆栈上添加OtherActivity
并启动它。我们的应用程序如何实现第一个调用哪个活动? 在androidManifest.xml中,我们在应用程序打开时要启动的第一个活动上设置了意图过滤器,动作为android.intent.action.MAIN
,类别为android.intent.ategory.LAUNCHER
。Finish()
用于销毁活动并将其从堆栈中移除。
意图标志
标志就像可以在意图上设置的选项,以定制启动过程。如果每次都启动相同的活动,则会创建一个新实例并将其添加到活动堆栈中以防止出现这种情况,您可以使用标志:FLAG_ACTIVITY_SINGLE_TOP
-如果设置了该标志,则如果该活动已在活动堆栈的顶部运行,则不会启动该活动。
1intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
同样,如果活动的另一个实例已经存在,则使用标志FLAT_ACTIVITY_CLEAR_TOP
将不会启动该实例。该标志将清除调用的活动之上的所有活动,并将其设置在堆栈的顶部。
通过意图传递数据
为了将数据传递到新的活动中,我们在函数putExtra
、putStringArrayListExtra
等中使用键值对。putExtra通常沿着withIntarray...传递基本类型,如Int、Float、Char、Double、Boolean、String...等。
1val intent = Intent(this, OtherActivity::class.java)
2intent.putExtra("keyString", "Androidly String data")
这些Extras字段隐藏在Bundle
对象中,该对象最终保存要传递的所有数据。要检索另一个活动中的数据,我们需要在bundles
上使用Extras
属性。在新活动中检索数据
1val bundle: Bundle? = intent.extras
2val string: String? = intent.getString("keyString")
3val myArray: ArrayList<String>? = intent.getStringArrayList("myArray")
intent
、Extras
等效于Java中的getIntent()
、getExtras()
。我们使用了一个可以为空的类型Bundle?
来防止不存在数据时的NullPointerExceptions
。同样,对于使用键获取的数据,我们使用了可为空的类型来防止在键不正确时可能发生的NPE。
使用可打包和可序列化的数据
有时我们需要将一个完整的对象从一个活动传递到另一个活动。除非我们实现Parcelable或Serializable接口,否则不可能做到这一点。可打包与可串行化的区别
- Parcelable接口是Android SDK的一部分。Serializable是Java的标准接口。
- 在Parcelable中,您需要设置需要在Parcel对象中传递的所有数据,还需要覆盖WriteToParcel()方法等。在Serializable中,实现接口就足以传递数据。
- Parcelable比Serializable更快。
发送可包裹数据
Kotlin提供了一些方便的注释,使我们不必重写WriteToParcel()方法来设置Parcelable上的数据。相反,我们可以使用@Parcelize注释,如下所示:
1@Parcelize
2data class Student(
3 val name: String = "Anupam",
4 val age: Int = 24
5) : Parcelable
注意:当前在您的build.gradle中,您必须添加以下代码才能使@Parcelize注释正常工作:
1android {
2 androidExtensions {
3 experimental = true
4 }
5//..
6....
7}
在你的活动中,你需要:
1val student = Student()
2val intent = Intent(this, OtherActivity::class.java)
3intent.putExtra("studentData", student)
4startActivity(intent)
发送可序列化数据
1data class Blog(val name: String = "Androidly", val year: Int = 2018) : Serializable
2
3val blog = Blog("a", 1)
4val intent = Intent(this, OtherActivity::class.java)
5intent.putExtra("blogData", blog as Serializable)
6startActivity(intent)
让我们在Android Studio项目中使用以上知识。
项目结构
布局代码
active_main.xml
布局代码如下:
1<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:tools="http://schemas.android.com/tools"
4 android:layout_width="match_parent"
5 android:layout_height="match_parent"
6 android:gravity="center"
7 android:orientation="vertical"
8 tools:context=".MainActivity">
9
10 <Button
11 android:id="@+id/btnSimpleIntent"
12 android:layout_width="wrap_content"
13 android:layout_height="wrap_content"
14 android:text="SIMPLE INTENT" />
15
16 <Button
17 android:id="@+id/btnSimpleIntentAndData"
18 android:layout_width="wrap_content"
19 android:layout_height="wrap_content"
20 android:text="SIMPLE INTENT WITH DATA" />
21
22 <Button
23 android:id="@+id/btnParcelableIntent"
24 android:layout_width="wrap_content"
25 android:layout_height="wrap_content"
26 android:text="Parcelable Intent" />
27
28 <Button
29 android:id="@+id/btnSerializableIntent"
30 android:layout_width="wrap_content"
31 android:layout_height="wrap_content"
32 android:text="Serializable Intent" />
33
34 <Button
35 android:id="@+id/btnBrowserIntent"
36 android:layout_width="wrap_content"
37 android:layout_height="wrap_content"
38 android:text="Browser Intent" />
39
40 <Button
41 android:id="@+id/btnMapsIntent"
42 android:layout_width="wrap_content"
43 android:layout_height="wrap_content"
44 android:text="Maps Intent" />
45
46 <Button
47 android:id="@+id/btnGenericIntent"
48 android:layout_width="wrap_content"
49 android:layout_height="wrap_content"
50 android:text="Generic Intent" />
51
52</LinearLayout>
Activity_ther.xml布局的代码如下所示:
1<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:tools="http://schemas.android.com/tools"
4 android:layout_width="match_parent"
5 android:layout_height="match_parent"
6 android:gravity="center"
7 android:orientation="vertical"
8 tools:context=".MainActivity">
9
10 <TextView
11 android:id="@+id/textView"
12 android:layout_width="wrap_content"
13 android:layout_height="wrap_content"
14 android:text="Intent Data goes here" />
15
16</LinearLayout>
活动编码
MainActivity.kt类的代码如下所示:
1package net.androidly.androidlyintents
2
3import android.app.Activity
4import android.content.ComponentName
5import android.content.Context
6import android.content.Intent
7import android.net.Uri
8import android.support.v7.app.AppCompatActivity
9import android.os.Bundle
10import android.os.Parcelable
11import android.view.View
12import android.widget.Toast
13import android.widget.Toast.LENGTH_LONG
14import kotlinx.android.parcel.Parcelize
15import kotlinx.android.synthetic.main.activity_main.*
16import java.io.Serializable
17
18@Parcelize
19data class Student(
20 val name: String = "Anupam",
21 val age: Int = 24
22) : Parcelable
23
24data class Blog(val name: String = "Androidly", val year: Int = 2018) : Serializable
25
26class MainActivity : AppCompatActivity(), View.OnClickListener {
27
28 fun Context.gotoClass(targetType: Class<*>) =
29 ComponentName(this, targetType)
30
31 fun Context.startActivity(f: Intent.() -> Unit): Unit =
32 Intent().apply(f).run(this::startActivity)
33
34 inline fun <reified T : Activity> Context.start(
35 noinline createIntent: Intent.() -> Unit = {}
36 ) = startActivity {
37 component = gotoClass(T::class.java)
38 createIntent(this)
39 }
40
41 var arrayList = ArrayList<String>()
42
43 override fun onCreate(savedInstanceState: Bundle?) {
44 super.onCreate(savedInstanceState)
45 setContentView(R.layout.activity_main)
46 btnSimpleIntent.setOnClickListener(this)
47 btnSimpleIntentAndData.setOnClickListener(this)
48 btnParcelableIntent.setOnClickListener(this)
49 btnSerializableIntent.setOnClickListener(this)
50 btnBrowserIntent.setOnClickListener(this)
51 btnMapsIntent.setOnClickListener(this)
52 btnGenericIntent.setOnClickListener(this)
53
54 arrayList.add("Androidly")
55 arrayList.add("Android")
56 arrayList.add("Intents")
57 }
58
59 override fun onClick(v: View?) {
60 when (v?.id) {
61 R.id.btnSimpleIntent -> {
62 val intent = Intent(this, OtherActivity::class.java)
63 startActivity(intent)
64 }
65 R.id.btnSimpleIntentAndData -> {
66 val intent = Intent(this, OtherActivity::class.java)
67 with(intent)
68 {
69 putExtra("keyString", "Androidly String data")
70 putStringArrayListExtra("arrayList", arrayList)
71 putExtra("keyBoolean", true)
72 putExtra("keyFloat", 1.2f)
73 }
74 startActivity(intent)
75 }
76 R.id.btnParcelableIntent -> {
77
78 val student = Student()
79 val intent = Intent(this, OtherActivity::class.java)
80 intent.putExtra("studentData", student)
81 startActivity(intent)
82 }
83 R.id.btnSerializableIntent -> {
84 val blog = Blog("a", 1)
85 val intent = Intent(this, OtherActivity::class.java)
86 intent.putExtra("blogData", blog as Serializable)
87 startActivity(intent)
88 }
89 R.id.btnBrowserIntent -> {
90 val url = "https://www.androidly.net"
91 val uri = Uri.parse(url)
92 val intent = Intent(Intent.ACTION_VIEW, uri)
93
94 if (intent.resolveActivity(packageManager) != null) {
95 startActivity(intent)
96 } else {
97 Toast.makeText(applicationContext, "No application found", LENGTH_LONG).show()
98 }
99 }
100 R.id.btnMapsIntent -> {
101 val loc = "12.9538477,77.3507442"
102
103 val addressUri = Uri.parse("geo:0,0?q=" + loc)
104 val intent = Intent(Intent.ACTION_VIEW, addressUri)
105
106 if (intent.resolveActivity(packageManager) != null) {
107 startActivity(intent)
108 } else {
109 Toast.makeText(applicationContext, "No application found", LENGTH_LONG).show()
110 }
111 }
112 else -> start<OtherActivity> {
113 putExtra("keyString", "Androidly Generic Intent")
114 }
115 }
116 }
117
118}
在上面的代码中,我们为每种类型的意图使用了Buttons。我们使用了Kotlin的with
表达式来防止每次都在intent
对象上设置数据。此外,除了上面已经讨论的那些,我们还创建了三个不同的意图。浏览器意图用于启动浏览器应用程序中的意图中存在的URL。使用Intent(Invent.ACTION_view,uri)
。位置意图用于在地图应用程序中启动最新的LNG位置。这两个都是含蓄的意图。最后,我们使用了一个通用的Intent,其中我们使用了Kotlin的扩展函数和lambda表达式来创建一个速记函数来启动Intent。为此,我们使用以下函数:
1fun Context.gotoClass(targetType: Class<*>) =
2 ComponentName(this, targetType)
3
4 fun Context.startActivity(createIntent: Intent.() -> Unit): Unit =
5 Intent().apply(createIntent).run(this::startActivity)
6
7 inline fun <reified T : Activity> Context.start(
8 noinline createIntent: Intent.() -> Unit = {}
9 ) = startActivity {
10 component = gotoClass(T::class.java)
11 createIntent(this)
12 }
startActivity是一个扩展函数,它寻找高阶函数作为它的参数。由于这一点,我们现在可以在几行中启动intent:start<OtherActivity>
下面给出了Intent Activity.kt类的代码。
1package net.androidly.androidlyintents
2
3import android.content.Context
4import android.support.v7.app.AppCompatActivity
5import android.os.Bundle
6import android.widget.Toast
7import kotlinx.android.synthetic.main.activity_other.*
8
9class OtherActivity : AppCompatActivity() {
10
11 override fun onCreate(savedInstanceState: Bundle?) {
12 super.onCreate(savedInstanceState)
13 setContentView(R.layout.activity_other)
14
15 val bundle: Bundle? = intent.extras
16
17 bundle?.let {
18
19 bundle.apply {
20 //Intent with data
21 val string: String? = getString("keyString")
22 textView.text = string
23
24 val myArray: ArrayList<String>? = getStringArrayList("myArray")
25 showToast(message = "MyArrayList size:${myArray?.size}")
26
27 val arrayList: ArrayList<String>? = getStringArrayList("arrayList")
28 showToast(message = "ArrayList size:${arrayList?.size}")
29
30 val float: Float? = bundle.get("keyFloat") as Float?
31 var boolean = bundle.get("boolean") as? Boolean
32
33 showToast(message = "Float data is:$float")
34 showToast(message = "Boolean data is:$boolean")
35 boolean = bundle.get("keyBoolean") as? Boolean
36 showToast(message = "Boolean correct key data is:$boolean")
37
38 }
39
40 bundle.apply {
41 //Serializable Data
42 val blog = getSerializable("blogData") as Blog?
43 if (blog != null) {
44 textView.text = "Blog name is ${blog?.name}. Year started: ${blog?.year}"
45
46 }
47 }
48
49 bundle.apply {
50 //Parcelable Data
51 val student: Student? = getParcelable("studentData")
52 if (student != null) {
53 textView.text = "Name is ${student?.name}. Age: ${student?.age}"
54 }
55 }
56 }
57 }
58
59 private fun showToast(context: Context = applicationContext, message: String, duration: Int = Toast.LENGTH_SHORT) {
60 if (!message.contains("null"))
61 Toast.makeText(context, message, duration).show()
62 }
63}
我们已经使用了let
和apply
来处理可空的types,并防止每行都做bundle.field。上面运行的应用程序的输出如下所示:这结束了本教程中关于用Kotlin编写的Android intents的内容。您可以从下面的链接下载该项目。