在Android中使用Kotlin的Intents入门

205 阅读9分钟

在靠近用户的地方部署容器

本工程教育(EngEd)计划由科支持。

在全球范围内即时部署容器。Section是经济实惠、简单而强大的。

免费入门

在Android中使用Kotlin的Intents入门

2022年2月22日

意图是一个Android元素,它可以促进从一个屏幕到另一个屏幕的导航。它们也被用来在活动之间或跨应用程序之间传递数据。

本教程将逐步指导你创建一个使用intent的应用程序,并了解与之相关的更多概念。

目标

在本教程结束时,你将能够理解。

  • 究竟什么是意图。
  • 不同类型的意图。
  • 如何构建一个完整的意图。
  • 如何将意图纳入你的应用程序中。
  • 什么是恶意的意图,以及如何消解它。
  • 在Android中,意图的解决意味着什么。

本教程推荐给希望建立Android意图知识的初学者和中级开发者。

前提条件

Note: 根据你的机器上运行的操作系统,选择你的安卓系统的最佳选项。确保你的机器至少有8GB的内存,否则,在建立一个项目时,它将耗尽内存,使你的电脑变慢。因此,内存越大,项目完成的速度就越快。

  • 具备Kotlin编程语言的基本知识。
  • 懂得如何从头开始一个Android项目。点击这里开始。

目录

让我们开始吧!

简要介绍一下意图

一个意图通常是一个命令,它有助于以下列方式在应用程序的活动(屏幕)中进行导航。

  • 启动一个新的活动
  • 启动服务
  • 传递一个广播接收器
  • 在两个或多个屏幕之间传递信息

意图使用的方法,如

  • startActivity() - 用来启动一个新的活动或激活一个现有的活动。
  • startService() - 使用这种保留方法启动服务,并向已经运行的服务发送修改过的指令。
  • sendBroadcast() - 使用这种方法,广播接收者由意图对象系统地选择,并向他们发送预定的信息。

意向也可以定义为连续的信息,允许应用程序组件向其他Android功能请求支持。同样地,同一设备上的两个应用程序最大限度地利用意图来分享信息。例如,一个行动可以启动一个外部活动,如使用相机捕捉图像或从内存中获取数据。

意图的类型

意图大致分为以下几种。

隐式意图- 应用程序中的元素没有通过隐式意图来指定。在这种情况下,意图提供了应该被执行的、可从系统中获得的组件的信息。

例如,当你点击一个按钮时,它将带你到预定的应用程序。假设你的设备有一个以上的共享应用程序。在这种情况下,选项框将出现并显示所有具有共享功能的应用程序。

应用的选择取决于用户对哪种模式最满意,以及其他个人考虑,如数据的安全性,等等。

明确的意图--这些意图连接同一应用程序的元素。也就是说,所有的组件都驻扎在同一个应用程序中。使用明确的目的,你可以将数据从一个活动传递到另一个活动。例如,当你点击一个按钮时,它将引导你到一个设备文件管理器,你可以查看设备内存内的媒体。

意向结构

一个完整的意图对象应该有一个存储数据的包,这些数据可以帮助应用程序确定首先启动哪个活动,以及同一应用程序中的一个元素用于以正确的程序进行操作的信息。

意向结构化中使用的关键术语

  • Element name - 这是一个额外的信息。但它仍然是最重要的,因为它有助于使一个意图明确,表明该意图必须只传递给由元素名称定义的应用元素。

如果意图没有一个元素名称,它将是隐含的。在这种情况下,系统会根据最后可用的意图数据决定哪个元素应该首先接收该意图。

  • Action - 这是一个字符串,表示intent应该执行的一般行动。行动就像变量一样,这意味着你可以声明你自己的行动来被应用程序的意图使用。

构建意图时使用的动作的例子包括。

private const Val ACTION_EDIT = "com.davis.action.EDIT"

只有当要编辑的标识符被声明时,代码才会编辑信息。

请确保在你编写的任何自定义动作之前包括你的应用程序的包名,例如。 ***com.davis***就是一个包的名称。

  • Data - 它表示意图数据的明确类型。在大多数情况下,类型是由数据本身推导出来的。

你可以通过设置该属性来禁用该处理并强制使用显式类型。URI是数据中最关键的元素,因为它掌握着数据的去向,可以被特定活动的意图所处理。

  • Category - 它是描述性的信息,说明适合引导意图的元素。

意图中的类别的例子。 CATEGORY_EMBED - 在一个主要活动容器内的功能是可能的。 CATEGORY_DESK_DOCK - 每当设备被连接到汽车码头时,就会启动一个活动。

  • Extras - 它指的是收集任何额外的数据。它被用来为组件提供更多的信息。

例如,如果我们有一个发送电子邮件信息的动作,我们可以输入额外的数据以提供主题、正文和其他与正在发送的信息有关的信息。

private const Val EXTRA_EMAIL = "com.davis.EXTRA_EMAIL"

上面的代码是一个String ,其中包含了信息应该被发送到的不同的电子邮件地址。

  • Flags - 在意图类中,标志被用来作为一个意图的标识符。

根据一个活动的标记方式,Android操作系统可能知道如何开始和如何进行该活动。

隐式和显式意图的例子

我们将在一个简单的应用程序中实现这两种类型的意图。

步骤1:创建一个新的Android Studio项目

启动Android Studio IDE并创建一个新的空活动项目。

Creating a project

Configuring your project

第2步:使用main_activity.xml文件工作

main_activity.xml 文件中添加以下代码。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="375dp"
        android:layout_height="295dp"
        android:layout_marginStart="10dp"
        android:layout_marginTop="16dp"
        android:layout_marginBottom="20dp"
        android:src="@drawable/car"
        app:layout_constraintBottom_toTopOf="@id/rl1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <RelativeLayout
        android:id="@+id/rl1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="20dp"
        app:layout_constraintBottom_toTopOf="@id/rl2"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        tools:layout_editor_absoluteX="17dp">

        <androidx.cardview.widget.CardView
            android:id="@+id/cardViewY"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="8dp"
            android:layout_marginBottom="8dp"
            app:cardBackgroundColor="@color/teal_200"
            app:cardCornerRadius="16dp">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_margin="2dp"
                    android:text="@string/explicit_intent"
                    android:textSize="15sp"
                    android:textColor="@color/black" />

                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_horizontal"
                    android:orientation="horizontal">

                    <Button
                        android:id="@+id/btnGallery"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginHorizontal="10dp"
                        android:text="Gallery" />

                    <Button
                        android:id="@+id/btnCamera"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="30dp"
                        android:text="Camera" />
                </LinearLayout>
            </LinearLayout>
        </androidx.cardview.widget.CardView>
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/rl2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="10dp"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        tools:layout_editor_absoluteX="17dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:layout_marginEnd="49dp"
            android:layout_toStartOf="@+id/btnShare"
            android:text="@string/implicit_intent"
            android:textColor="@color/black"
            android:textSize="15sp"/>

        <Button
            android:id="@+id/btnShare"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:text="share" />
    </RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

**注意:**你可以选择使用矢量资产而不是按钮,把它们添加到可绘制资源文件中。然后在XML布局中添加一个图像视图,并使用src 方法引用该图像。

你的设计应该类似于下图所示。

Examples of intents design

步骤3:使用ActivityMain.kt文件工作

在我们使用main_activity.kt ,我们将向我们的应用程序文件添加额外的代码,以确保它完全满足我们的目标。

Grandle Scripts-> *build.grandle*添加以下代码。

 buildFeatures{ding
     // enable viewBinding
        viewBinding true
    }

记住要同步该项目。

在Androidmanifests folder* -> 双击AndroidManifest.xml ,并添加以下权限,以便能够访问设备媒体和相机应用程序。

<uses-permission android:name=
"android. permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>

为了使你的应用程序在点击事件上发挥作用,在MainActivity.kt ,添加以下代码。

class MainActivity : AppCompatActivity() {
    private val my_request_code: Int = 0
    private lateinit var imageView: ImageView
    var binding: ActivityMainBinding? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding!!.root)

        binding!!.btnGallery.setOnClickListener {
            Intent(Intent.ACTION_GET_CONTENT).also {
                it.type = "image/*"
                startActivityForResult(it, 0)
            }
        }

        // Access the camera
        binding!!.btnCamera.setOnClickListener {
            val snapPhotoIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            if (snapPhotoIntent.resolveActivity(this.packageManager) != null) {
                startActivityForResult(snapPhotoIntent, my_request_code)
            } else {
                Toast.makeText(this, "Unable to execute Camera", Toast.LENGTH_SHORT).show()
            }
        }

        // Share plain text via intent
        binding!!.btnShare.setOnClickListener {
            val sendIntent: Intent = Intent().apply {
                action = Intent.ACTION_SEND
                putExtra(Intent.EXTRA_TEXT, "I am sharing ->")
                type = "text/plain"
            }
            val shareIntent = Intent.createChooser(sendIntent, "Share with?")
            startActivity(shareIntent)
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode == RESULT_OK && requestCode == 0) {
            val bitmap = data?.extras?.get("data") as Bitmap
            val uri = data.data
            imageView.setImageURI(uri)
            imageView.setImageBitmap(bitmap)
        }
    }
}

点击这里访问完整的代码。

如何识别恶意的意图

你的应用程序可以使用意图来遍历组件或代表另一个应用程序进行操作。

当应用程序对所提供的intent的extracelled被应用程序解开以创建一个嵌套的intent并发生StrictMode ,就会实现非法intent。

在Kotlin中,下面的代码是检测不安全意图的程序化方法。

fun onCreate() {
    StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder()
        .detectUnsafeIntentLaunch()
        .penaltyDialogue //Whenever a fault happens, a pop up with violation details appears.
        .penaltyLog()
        .penaltyDeath() //Immediately terminate the current application when the violation condition is triggered.
        .build())
}

**注意:**在较新的Android版本即12版中,当使用detectAll() 方法在声明VmPolicydetectUnsafeIntentLaunch 是非自愿调用的。

意图解析

为你的意图搜索相关应用组件的行为被称为意图解析。

意图解析主要用于隐式意图,因为它们不提供组件名称,这有助于系统寻找能够进行活动的应用组件名称。

系统执行以下步骤以获得组件名称。

  • 行动测试:在这里,系统确定预期行动和意图过滤器中的意图是否匹配。如果它们是相同的,则测试成功。否则,测试失败。
  • 类别测试。在这里,系统将类别名称与意图过滤器中指定的名称进行比较。如果两者相同,则该测试通过,否则失败。
  • 数据测试:这里,系统将意图MIME中的数据与意图过滤器中的信息进行比较。如果两者相同,则该检查成功,反之亦然。

总结

在本教程中,我们讨论了意图、现有的意图类型以及它们的例子。我们还了解到,由于intents在活动和应用之间的导航方面有许多用途,因此它是必不可少的。


同行评议的贡献者。Eric Gacoki

类似文章

[

How to Create a Reusable React Form component Hero Image

语言

如何创建一个可重复使用的React表单组件

阅读更多

](www.section.io/engineering…

Building a payroll system with next.js Hero Image

语言, Node.js

用Next.js构建一个薪资系统

阅读更多

](www.section.io/engineering…

Creating and Utilizing Decorators in Django example image

架构

在Django中创建和使用装饰器

阅读更多信息

](www.section.io/engineering…)