【Android】我的手机在…自己下载…那个(浅析Intent基础运用)
在Android开发中,Intent(意图)是一个非常重要的概念。它不仅仅是用于在应用程序的各个组件之间进行通信的工具,也是启动新的Activity、Service,或者广播信息的关键机制。本文将深入探讨Intent的作用、类型以及使用方法。
什么是Intent?
简单来说,Intent是一种消息对象,用于在应用程序的不同组件(如Activity、Service、BroadcastReceiver)之间传递数据和启动操作。它可以描述一个操作要执行的动作,比如启动一个新页面或播放一段音频。
Intent主要有两种类型:显式Intent和隐式Intent。
1. 显式Intent
显式Intent明确指定了要启动的组件。在这种情况下,Intent对象包含了目标组件的类名,这样系统就知道要启动哪个Activity。
这里给出一个显示Intent在两个活动间切换的示例:
创建一个MainActivity的活动以及一个SecondActivity的活动,代码如下
MainActivity:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
findViewById(R.id.button_1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivity(intent);
}
});
}
}
MainActivity的XML文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="这是一个按钮哦"/>
</LinearLayout>
SecondActivity:
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_second);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.secondActivity), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
}
}
SecondActivity的XML文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/secondActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="你好!" />
</LinearLayout>
点击运行:
点一下这个这是一个按钮哦。
显式 Intent 的缺点
1. 仅适用于应用内通信
显式Intent主要用于同一应用程序内的组件之间的通信,不适合跨应用程序的通信场景。
2. 组件的耦合性
显式Intent通过指定类名的方式将组件绑定在一起,增加了组件之间的耦合性,不利于组件的解耦和复用。
2. 隐式Intent
Intent的结构
一个Intent包含了以下几个主要部分:
- Action(动作):定义了要执行的操作,比如
Intent.ACTION_VIEW
。 - Data(数据):要操作的数据,比如一个URL。
- Category(类别):附加信息,用来进一步指定操作的类型。
- Extras(额外数据):键值对,用于传递附加信息。
隐式Intent不明确指定目标组件,而是通过描述要执行的操作或携带的数据,由系统根据这些信息进行匹配,找到最适合处理该Intent的组件。这种Intent通常用于跨应用程序的通信,或当多个组件可以处理同一个操作时使用。
示例:
同样是上述的两个活动,将MainActivity中的按钮监听事件替换为:
findViewById(R.id.button_1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.activitytest.ACTION_START");
intent.addCategory("com.example.activitytest.MY_CATEGORY");
startActivity(intent);
}
});
- 获取按钮并设置点击监听器:通过
findViewById
获取按钮并设置点击监听器OnClickListener
。 - 创建隐式Intent:在
onClick
方法中创建一个新的Intent,指定其action
为"com.example.activitytest.ACTION_START"
。 - 添加类别:通过
addCategory
方法为Intent添加一个自定义类别"com.example.activitytest.MY_CATEGORY"
。 - 启动Activity:使用
startActivity(intent)
方法启动匹配该Intent的Activity。
而后在AndroidManifest文件里面修改SecondActivity的活动。
<activity
android:name=".SecondActivity"
android:exported="true" >
<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>
这段代码在AndroidManifest.xml文件中为一个Activity配置了一个<intent-filter>
,使该Activity能够响应特定的隐式Intent。具体配置如下:
- :定义一个Intent过滤器。
- :指定Intent的
action
为"com.example.activitytest.ACTION_START"
。这个Action告诉系统,当Intent的Action是这个字符串时,应该考虑这个过滤器。 - :指定Intent的类别
android.intent.category.DEFAULT
。这个是默认类别,表示这是一个普通的Intent。 - :再添加一个自定义类别
"com.example.activitytest.MY_CATEGORY"
,表明只有同时包含这个类别的Intent才能匹配到这个过滤器。
1. <intent-filter>
标签
<intent-filter>
标签用于在AndroidManifest.xml文件中定义一个Intent过滤器。Intent过滤器告诉系统该Activity可以处理哪些Intent。
2. <action>
标签
<action android:name="com.example.activitytest.ACTION_START"/>
<action>
标签定义了这个Intent过滤器能够处理的动作。在这个例子中,动作的名称是com.example.activitytest.ACTION_START
。这通常是一个自定义的动作名称,由开发者定义。
3. <category>
标签
<category android:name="android.intent.category.DEFAULT"/>
<category>
标签定义了这个Intent过滤器的类别。在这个例子中,类别是android.intent.category.DEFAULT
。这个类别表示这个Intent过滤器是默认的,如果一个Intent包含android.intent.category.DEFAULT
类别,那么这个过滤器可以匹配该Intent。
3. 隐式Intent其他用法
例如:可以通过Intent来下载…那个。
仍然是改变MainActivity中的点击事件
findViewById(R.id.button_1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://ys-api.mihoyo.com/event/download_porter/link/ys_cn/official/android_default"));
startActivity(intent);
}
});
点一下这个按钮。
就可以得到:
4. 向下一个活动传递数据
在Android应用程序中,Activity之间传递数据是一项常见的任务。数据传递通常通过Intent实现,可以通过Extras将数据附加到Intent中,并在目标Activity中接收这些数据。下面将详细介绍如何在两个Activity之间传递数据。
基本数据类型的传递:
示例:
仍然是重写onClick方法:
findViewById(R.id.button_1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String data = "hello laoziyuanxuezhang";
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
intent.putExtra("extra_data",data);
startActivity(intent);
}
});
Intent intent = new Intent(MainActivity.this, SecondActivity.class);:
- 创建一个Intent对象,用于启动SecondActivity。Intent的构造函数接收两个参数:当前Activity的上下文(MainActivity.this)和目标Activity的类(SecondActivity.class)。
intent.putExtra(“extra_data”, data);:
- 使用putExtra方法将字符串数据(data)添加到Intent中。数据被存储在Intent的附加信息(Extras)中,键名为"extra_data"。
startActivity(intent);:
- 使用startActivity方法启动SecondActivity,并将包含附加数据的Intent传递给它。
再在SecondActivity中修改代码,接收上一个活动传递过来的数据,并打印:
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_second);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.secondActivity), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
Intent intent = getIntent();
String data = intent.getStringExtra("extra_data");
Log.d("SecondActivity",data);
}
}
Intent intent = getIntent();:
- 获取启动这个Activity的Intent对象。
String data = intent.getStringExtra(“extra_data”);:
- 从Intent中提取附加数据。使用getStringExtra方法获取键名为"extra_data"的字符串数据。
Log.d(“SecondActivity”, data);:
- 使用Log.d方法将接收到的数据打印到Logcat,以便进行调试和查看。
运行,点击按钮,查看日志:
5. 返回数据给上一个活动
使用 ActivityResult API 传递数据
1. 在 MainActivity 中启动 SecondActivity 并接收结果
MainActivity.java
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private ActivityResultLauncher<Intent> activityResultLauncher;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化 ActivityResultLauncher
activityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
Intent data = result.getData();
if (data != null) {
String returnData = data.getStringExtra("return_data");
// 处理返回的数据
Log.d("MainActivity", "Received data: " + returnData);
}
}
}
);
findViewById(R.id.button_1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
activityResultLauncher.launch(intent);
}
});
}
}
2. 在 SecondActivity 中返回数据
SecondActivity.java
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
findViewById(R.id.button_return).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent returnIntent = new Intent();
returnIntent.putExtra("return_data", "Hello from SecondActivity");
setResult(RESULT_OK, returnIntent);
finish(); // 结束当前活动并返回结果
}
});
}
}
详细步骤解析
- 配置依赖项:确保你的项目中包含
activity-ktx
和fragment-ktx
库。 - MainActivity.java:
- 定义ActivityResultLauncher:使用
registerForActivityResult
方法来注册一个用于启动Activity的launcher。 - 启动SecondActivity:当按钮被点击时,通过
activityResultLauncher.launch(intent)
启动SecondActivity。
- 定义ActivityResultLauncher:使用
- SecondActivity.java:
- 返回数据:在SecondActivity中,创建一个包含数据的Intent,并通过
setResult(RESULT_OK, returnIntent)
设置结果,然后调用finish()
结束Activity。
- 返回数据:在SecondActivity中,创建一个包含数据的Intent,并通过
完整代码示例
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ActivityResultLauncher<Intent> activityResultLauncher;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化 ActivityResultLauncher
activityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
Intent data = result.getData();
if (data != null) {
String returnData = data.getStringExtra("return_data");
// 处理返回的数据
Log.d("MainActivity", "Received data: " + returnData);
}
}
}
);
findViewById(R.id.button_1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
activityResultLauncher.launch(intent);
}
});
}
}
SecondActivity.java
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
findViewById(R.id.button_return).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent returnIntent = new Intent();
returnIntent.putExtra("return_data", "Hello from SecondActivity");
setResult(RESULT_OK, returnIntent);
finish(); // 结束当前活动并返回结果
}
});
}
}
使用ActivityResult API
来实现Activity之间的数据传递和结果返回,替代过时的startActivityForResult
方法。
使用Intent的注意事项
- 明确使用显式或隐式Intent:根据需要选择适当的Intent类型,显式Intent用于内部组件通信,隐式Intent用于跨应用程序通信。
- 处理可能的异常:当使用隐式Intent时,确保应用程序能够处理目标Activity不存在的情况。
- 安全性考虑:避免通过Intent传递敏感数据,使用安全的方式进行数据传递和保护。
结论
Intent是Android开发中非常强大且灵活的工具。通过理解和熟练使用Intent,开发者可以在应用程序的不同组件之间高效地进行通信和操作。无论是启动Activity、Service,还是发送广播,Intent都扮演着至关重要的角色。