初识Android(二):Intent的使用,在Activity中穿梭

使用Intent的目的:启动器点击图标只会进入程序的主Activity,如何进入其他的Activity,实现不同Activity之间的交互。使用intent来实现。

Intent是Android程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前空前要执行的动作,还可以在不同组件之间传递数据。

Intent一般可用于启动Activity、启动Service、发送广播等场景。

Intent大致分为两种:显式Intent、隐式Intent

1、使用显式Intent

第一步肯定要创建新的一个Activity,并给新的Activity一个新的layout布局。

Intent有多个构造函数的重载,其中一个是

Intent(Context packageContext, Class<?> cls)

第一个参数Context:要求提供一个启动Activity的上下文。

第二个参数Class:指定我们想要启动的目标Activity。

使用Intent:Activity类提供了startActivity()方法,专门用于启动Intent,它接收一个intent参数。

修改FirstActivity中的点击按钮事件,代码如下:

class FirstActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.first_layout)
        button1.setOnClickListener {
            Toast.makeText(this,"You clicked Button1",Toast.LENGTH_SHORT).show()
            val intent = Intent(this, SecondActivity::class.java)
            startActivity(intent)
        }
    }
}

第一个参数传入了this,即FirstActivity作为上下文。第二个参数传入SecondActivity::class.java,即打开SecondActivity。使用这种方式,意图很明显,称为显式Intent。

2、使用隐式Intent

隐式Intent不明确指明要启动哪一个Activity,二十指定一系列的 action 和 category等信息,由系统自动去分析这个Activity,并帮助我们找到合适的Activity去启动。

在AndroidManifest.xml中的SecondActivity中添加如下代码:

        <activity
            android:name=".SecondActivity"
            android:exported="false"
            android:label="This is the second Activity">
            <intent-filter>
                <action android:name="com.example.activitytest.ACTION_START"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

在<action>标签中我们指定了当前Activity可以相应com.example.activitytest.ACTION_START这个action。

在<category>中指明了当前Activity能够相应的Intent中可能带有的category。

只有<action>和<category>同时匹配Intent中的action和category时,这个Activity才能响应这个Intent。

在按钮点击事件中添加代码:

        button1.setOnClickListener {
            Toast.makeText(this,"You clicked Button1",Toast.LENGTH_SHORT).show()
            val intent = Intent("com.example.activitytest.ACTION_START")
            startActivity(intent)
        }

这是Intent的另一个构造函数,直接输入了action的字符串,就可以响应SecondActivity。

能启动SecondActivity的原因,是因为SecondActivity的category标签使用的是默认值DEFAULT。在调用 startActivity()时,会自动传入 默认的category。

每一个Intent只能传入一个 action ,但是可以指定多个 category 。当我们在点击事件中的Intent中再添加一个category,程序会崩溃,找不到这个Activity。

        button1.setOnClickListener {
            Toast.makeText(this,"You clicked Button1",Toast.LENGTH_SHORT).show()
            val intent = Intent("com.example.activitytest.ACTION_START")
            intent.addCategory("com.example.activitytest.MY_CATEGORY")
            startActivity(intent)
        }

程序会崩溃,查看错误日志(logcat中的error日志),可发现由于系统无法找到对应的Intent!!!

 解决办法:

在SecondActivity的<category>添加上缺少的category即可。

        <activity
            android:name=".SecondActivity"
            android:exported="false"
            android:label="This is the second Activity">
            <intent-filter>
                <action android:name="com.example.activitytest.ACTION_START"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="com.example.activitytest.MY_CATEGORY"/>
            </intent-filter>
        </activity>

3、更多隐式Intent用法

        隐式Intent不仅能够打开自己的Activity,还可以启动其他程序的Activity,从而实现不同应用程序之间的交互。

        可以通过按钮点击事件,使用隐式intent打开一个网址,具体代码如下:

        button1.setOnClickListener {
            Toast.makeText(this,"You clicked Button1",Toast.LENGTH_SHORT).show()
            val intent = Intent(Intent.ACTION_VIEW)
            intent.data = Uri.parse("https://www.csdn.net/")
            startActivity(intent)
        }

首先、通过指定Intent的action是Intent.ACTION_VIEW,这是Android内置的一个动作,其常量值为android.intent.action.VIEW

然后、通过Uri.parse(),将一个网址字符串解析成一个Uri对象。再通过Intent的setData() 方法,将uri对象传递进入Intent对象。这里的 intent.data 是语法糖。系统内部自动调用setData方法。

setData()方法:这个方法其实并不复杂,它接收一个Uri对象,主要用于指定当前Intent正在操作的数据,而这些数据通常是以字符串形式传入Uri.parse()方法中解析产生的。

可以在<intent-filter>中添加<data>标签,用于当前Activity能更精确的响应对应的数据。<data>标签包含以下配置:

android:scheme。用于指定数据的协议部分,如上例中的https部分。
android:host。用于指定数据的主机名部分,如上例中的www.baidu.com部分。
android:port。用于指定数据的端口部分,一般紧随在主机名之后。
android:path。用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内
容。
android:mimeType。用于指定可以处理的数据类型,允许使用通配符的方式进行指定。

只有当<data>标签中指定的内容和Intent中的内容完全一致时,此Activity才能响应该Intent。

例子:

创建一个新的ThirdActivity,并创建一个新的third_layout,代码如下:

<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".ThirdActivity">

    <Button
        android:id="@+id/button3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button 3"/>

</LinearLayout>

在AndroidManiTest.xml中进行注册:

        <activity
            android:name=".ThirdActivity"
            android:exported="true" >
            <intent-filter tools:ignore="AppLinkUrlError">
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="https" />
            </intent-filter>
        </activity>

补充:这里的android:exported 此元素是设置当前Activity是否可以由其他应用程序启动:

设置为true:则任何应用都可以访问该Activity,并且可以通过其确切的类名启动。即允许不同进程间进行通信。

设置为false:则Activity只能由相同应用程序的组件、具有相同用户 ID 的应用程序或特权系统组件启动。这是没有意图过滤器时的默认值。

当mainActivity中有<intent-filter>标签时,应该设置android:exported为true,否则会报错。

 因为我们对ThirdActivity也赋予了相应的<intent-filter>并且它的action也为android.intent.action.VIEW,响应的data也为https,因此当点击按钮时,会默认弹出一个列表,可供选择,进入网页还是进入新的ThirdActivity。

除了,调用https协议之外,还可以调用很多其他协议,例如 geo 表示地理位置,tel 表示拨打电话

通过按钮进行电话拨打的代码如下:

        button1.setOnClickListener {
            Toast.makeText(this,"You clicked Button1",Toast.LENGTH_SHORT).show()
            val intent = Intent(Intent.ACTION_DIAL)
            intent.data = Uri.parse("tel:10086")
            startActivity(intent)
        }

设置Intent的action为Intent.ACTION_DIAL,然后再data部分调用Uri.parse(),协议为tel.

其它的类似。

4、向下一个Activity传递数据

Intent不仅可以用来打开其它的Activity,还可以用来进行数据传输。

传输方法很简单,Intent提供了一系列的 putExtra() 方法重载,可以把想要传输的数据暂时封存到Intent中,启动新的Activity后,再从Intent中取出。

打开Activity 时,先将strData存放在了intent中,代码如下:

        button1.setOnClickListener {
            val strData = "Message"
            val intent = Intent(this, SecondActivity::class.java)
            intent.putExtra("extra_name", strData)
            startActivity(intent)
        }

取出代码如下,需要在SecondActivity 的 onCreate() 函数中自行取出,代码如下:

class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.second_layout)
        val extraData = intent.getStringExtra("extra_data")
        Log.d("SecondActivity","extra data is $extraData")
    }
}

代码中的intent实际上是调用父类的getIntent()方法,从而来获得启动SecondActivity 的intent。然后调用getStringExtra()方法并传入相应的键值,就可以得到传递的数据了。这里由于我们传递的是字符串,所以使用getStringExtra()方法来获取传递的数据。如果传递的是整型数据,则使用getIntExtra()方法;如果传递的是布尔型数据,则使用getBooleanExtra()方法,以此类推。

5、向上一个Activity传递数据

由于返回上一个Activity,仅需back即可。没有专门的Intent,并不能像向下传递消息一样。

Activity类提供了一个启动Activity的 startActivityForResult() 方法

button1.setOnClickListener {
    val intent = Intent(this, SecondActivity::class.java)
    startActivityForResult(intent, 1)
}

接下来在SecondActivity中添加点击事件:

        button2.setOnClickListener {
            val intent = Intent()
            intent.putExtra("data_return", "Hello FirstActivity")
            setResult(RESULT_OK, intent)
            finish()
        }

着同样创建了一个intent,并没有意图,仅用来进行数据传输。

紧接着把要传递的数据存放在Intent中,然后调用了setResult()方法。这个方法非常重要,专门用于向上一个Activity返回数据。

setResult()方法接收两个参数:

第一个参数用于向上一个Activity返回处理结果,一般只使用RESULT_OK或RESULT_CANCELED这两个值;

第二个参数则把带有数据的Intent传递回去。最后调用了finish()方法来销毁当前Activity。

Tips:当前返回数据是通过SecondActivity中的按钮来返回,但是一般返回上一Activity直接使用back,因此需要另一种写法:

由于我们是使用startActivityForResult()方法来启动SecondActivity的,在SecondActivity被销毁之后会回调上一个Activity的onActivityResult()方法,因此我们需要在FirstActivity中重写这个方法来得到返回的数据,如下所示:

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when (requestCode) {
            1 -> if (resultCode == RESULT_OK) {
                val returnedData = data?.getStringExtra("data_return")
                Log.d("FirstActivity", "returned data is $returnedData")
            }
        }
    }

onActivityResult()方法带有3个参数:第一个参数requestCode,即我们在启动Activity时传入的请求码;第二个参数resultCode,即我们在返回数据时传入的处理结果;第三个参数data,即携带着返回数据的Intent。由于在一个Activity中有可能调用startActivityForResult()方法去启动很多不同的Activity,每一个Activity返回的数据都会回调到onActivityResult()这个方法中,因此我们首先要做的就是通过检查requestCode的值来判断数据来源。确定数据是从SecondActivity返回的之后,我们再通过resultCode的值来判断处理结果是否成功。最后从data中取值并打印出来,这样就完成了向
上一个Activity返回数据的工作。

但是目前版本已经被Google淘汰,需要使用更新的  Activity Result API,用法如下:

参考Activity Result API详解,是时候放弃startActivityForResult了_guolin的博客-CSDN博客_startactivityforresult废弃如果你将项目中的appcompat库升级到1.3.0或更高的版本,你会发现startActivityForResult()方法已经被废弃了。这个方法相信所有做过Android的开发者都用过,它主要是用于在两个Activity之间交换数据的。那么为什么这个如此常用的方法会被废弃呢?官方给出的说法是,现在更加建议使用Activity Result API来实现在两个Activity之间交换数据的功能。我个人的观点是,startActivityForResult()方法并没有什么致命的问题,只是https://guolin.blog.csdn.net/article/details/121063078?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3.pc_relevant_aa&utm_relevant_index=6

    private val requestDataLauncher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
            if (it.resultCode == RESULT_OK) {
                val returnData = it.data?.getStringExtra("data_return")
                Log.d("FirstActivity","data return is $returnData")
            }
        }

通过  registerForActivityResult()  来注册对Activity的结果的监听。

registerForActivityResult()方法接收两个参数:

第一个参数是一种Contract类型,由于我们是希望从另外一个Activity中请求数据,因此这里使用了StartActivityForResult。

第二个参数是一个Lambda表达式,当有结果返回时则会回调到这里,然后我们在这里获取并处理数据即可。
 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值