使用 Kotlin 在活动之间处理 Android Intent

在本教程中,我们将讨论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.LAUNCHERFinish()用于销毁活动并将其从堆栈中移除。

意图标志

标志就像可以在意图上设置的选项,以定制启动过程。如果每次都启动相同的活动,则会创建一个新实例并将其添加到活动堆栈中以防止出现这种情况,您可以使用标志:FLAG_ACTIVITY_SINGLE_TOP-如果设置了该标志,则如果该活动已在活动堆栈的顶部运行,则不会启动该活动。

1intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP

同样,如果活动的另一个实例已经存在,则使用标志FLAT_ACTIVITY_CLEAR_TOP将不会启动该实例。该标志将清除调用的活动之上的所有活动,并将其设置在堆栈的顶部。

通过意图传递数据

为了将数据传递到新的活动中,我们在函数putExtraputStringArrayListExtra等中使用键值对。putExtra通常沿着withandroid-intent-put-extra-typesIntarray...传递基本类型,如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")

intentExtras等效于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项目中使用以上知识。

项目结构

Android-Intent-Project-Structure

布局代码

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}

我们已经使用了letapply来处理可空的types,并防止每行都做bundle.field。上面运行的应用程序的输出如下所示:android-intent-output这结束了本教程中关于用Kotlin编写的Android intents的内容。您可以从下面的链接下载该项目。

AndroidlyIntents

Published At
Categories with 技术
Tagged with
comments powered by Disqus