当前位置: 首页 > news >正文

【Android】Intent

目录

一、什么是Intent

二、显式Intent

三、隐式Intent

四、复杂数据传递

五、跨应用权限管理

六、常见问题


一、什么是Intent

1. 跨组件通信桥梁

  • 实现组件间通信(Activity/Service/BroadcastReceiver)
  • 封装操作指令与数据传输逻辑
目标组件启动方法数据返回方式
ActivitystartActivity()onActivityResult()
ServicestartService()/bindService()Binder/Messenger
BroadcastReceiversendBroadcast()无(单向通信)

【Android】四大组件之Activity-CSDN博客文章浏览阅读1.2k次,点赞20次,收藏24次。Activity‌ 是 Android 应用的核心交互组件。_android之activity https://blog.csdn.net/qq_15711195/article/details/147526174【Android】四大组件之Service-CSDN博客文章浏览阅读1k次,点赞15次,收藏11次。Service是Android应用的核心后台组件。_android之service https://blog.csdn.net/qq_15711195/article/details/147531108【Android】四大组件之BroadcastReceiver-CSDN博客文章浏览阅读714次,点赞14次,收藏20次。BroadcastReceiver用于监听系统或应用发出的广播事件,实现跨组件通信。 https://blog.csdn.net/qq_15711195/article/details/1476434862. 两种类型

类型特点适用场景
显式明确指定目标组件类名,如Intent(A.this, B.class)应用内部通信
隐式通过Action/Category等属性匹配组件跨应用或系统功能调用,如启动系统相机

3. 核心属性

属性名功能说明示例用法
Component显式指定目标组件类名intent.setClass(this, SecondActivity.class) 
Action定义执行动作intent.setAction(Intent.ACTION_VIEW) 
Category补充Action的附加信息intent.addCategory(Intent.CATEGORY_DEFAULT) 
Data指定操作数据URIintent.setData(Uri.parse("https://www.example.com")) 
Type设置MIME类型(与Data互斥)intent.setType("image/*") 
Extras通过Bundle携带附加数据intent.putExtra("username", "John") 
Flags控制启动模式intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)

二、显式Intent

1‌. Activity跳转

源activity跳转:

// 基础跳转:无返回函数调用
Intent intent = new Intent(MainActivity.this, DetailActivity.class);
startActivity(intent);// 带返回值跳转:在onActivityResult中接收返回值
startActivityForResult(intent, 100); // 请求码为100

目标Activity返回数据:

// 目标Activity返回数据
Intent resultIntent = new Intent();
resultIntent.putExtra("result", "Success");
setResult(RESULT_OK, resultIntent);
finish();

源activity接收返回结果:

// 接收返回结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {if(requestCode == 100 && resultCode == RESULT_OK) {String result = data.getStringExtra("result"); // 获取返回数据}
}

2. 启动Service

// 启动后台服务
Intent serviceIntent = new Intent(this, DownloadService.class);
serviceIntent.putExtra("url", "https://example.com/file.zip");
startService(serviceIntent);  // 执行一次性任务
  • 避免在onPause()后执行startActivityForResult()
  • 及时解绑Service防止内存泄漏

三、隐式Intent

1. 调用系统功能

// 打开网页
Intent webIntent = new Intent(Intent.ACTION_VIEW);
webIntent.setData(Uri.parse("https://www.android.com"));
if (webIntent.resolveActivity(getPackageManager()) != null) {startActivity(webIntent);  // 安全检测避免崩溃
}// 分享文本
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, "Check this out!");
startActivity(Intent.createChooser(shareIntent, "Share via"));

2. 自定义Action处理

AndroidManifest.xml声明:

<!-- AndroidManifest.xml声明 -->
<activity android:name=".CustomActivity"><intent-filter><action android:name="com.example.ACTION_CUSTOM"/><category android:name="android.intent.category.DEFAULT"/><data android:mimeType="text/*"/></intent-filter>
</activity>

发送自定义Intent:

Intent customIntent = new Intent("com.example.ACTION_CUSTOM");
customIntent.putExtra("custom_data", "Hello Custom");
startActivity(customIntent);

3. 使用resolveActivity()检测可用组件避免崩溃  

if (intent.resolveActivity(packageManager) != null) {startActivity(intent)
}

四、复杂数据传递

1. Bundle封装

发送方:

Bundle bundle = new Bundle();
bundle.putString("name", "Android");
bundle.putInt("version", 13);Intent intent = new Intent(this, TargetActivity.class);
intent.putExtras(bundle);

接收方:

Bundle receivedBundle = getIntent().getExtras();
if(receivedBundle != null) {String name = receivedBundle.getString("name");
}

 2. Parcelable对象传输

// 自定义Parcelable类
public class User implements Parcelable {private String name;private int age;// 实现Parcelable接口方法@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(name);dest.writeInt(age);}public static final Creator<User> CREATOR = new Creator<User>() {@Overridepublic User createFromParcel(Parcel in) {return new User(in);}}; // 完整实现需补充
}// 传递对象
User user = new User("John", 25);
intent.putExtra("user", user);

3. 类型冲突处理

同时设置Data和Type时使用setDataAndType():

intent.setDataAndType(Uri.parse("content://contacts/people/1"),"text/vnd.android.cursor.item"
);

五、跨应用权限管理

场景类型权限需求典型示例
启动外部组件声明使用其他应用暴露的权限调用系统相机、地图应用
暴露自身组件定义自定义权限保护自身组件允许特定应用访问私有Activity

1. 声明使用其他应用暴露的权限

示例:调用系统相机拍照并保存到应用私有目录。

在应用AndroidManifest.xml声明所需权限,在FileProvider声明中配置路径:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.app"><!-- 权限声明区域 --><uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application><!-- FileProvider 组件声明 --><providerandroid:name="androidx.core.content.FileProvider"android:authorities="com.example.fileprovider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_paths" /> <!-- 关联外部路径文件 --></provider><!-- 其他组件声明(Activity/Service 等) --></application></manifest>

动态申请危险权限:

private static final int REQUEST_CAMERA_PERMISSION = 100;private void checkCameraPermission() {if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA},REQUEST_CAMERA_PERMISSION);} else {launchCamera();}
}

处理权限请求结果:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {if (requestCode == REQUEST_CAMERA_PERMISSION) {if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {launchCamera();} else {Toast.makeText(this, "需要相机权限", Toast.LENGTH_SHORT).show();}}
}

创建带权限的Intent:

private void launchCamera() {Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);if (takePictureIntent.resolveActivity(getPackageManager()) != null) {File photoFile = createImageFile(); // 创建临时文件Uri photoURI = FileProvider.getUriForFile(this,"com.example.fileprovider", // 与manifest中配置一致photoFile);// 授予临时访问权限takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);// 系统默认相机应用// 或其他支持 MediaStore.ACTION_IMAGE_CAPTURE Action 的第三方相机应用startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);}
}

2. 定义自定义权限保护自身组件

示例:定义私有Activity只允许持有特定权限的应用访问。

在提供方应用的AndroidManifest.xml定义自定义权限:

<permissionandroid:name="com.example.PRIVATE_ACCESS"android:label="私有访问权限"android:protectionLevel="signature" /> <!-- 只允许相同签名的应用 --><activityandroid:name=".PrivateActivity"android:permission="com.example.PRIVATE_ACCESS"><intent-filter><action android:name="com.example.action.ACCESS_PRIVATE" /><category android:name="android.intent.category.DEFAULT" /></intent-filter>
</activity>

在使用方应用的AndroidManifest.xml声明使用该权限 :

<uses-permission android:name="com.example.PRIVATE_ACCESS" />

使用方发起请求:

public void openPrivateActivity() {try {Intent intent = new Intent("com.example.action.ACCESS_PRIVATE");startActivity(intent);} catch (SecurityException e) {Log.e("Permission", "缺少访问权限: " + e.getMessage());// 处理无权限情况}
}

3. 临时URI权限授予

当通过Intent传递文件URI时,

发送方授予读取权限:

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

接收方需在onCreate()中保留权限:

@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getIntent().setFlags(getIntent().getFlags()& ~Intent.FLAG_GRANT_READ_URI_PERMISSION);
}

4. 包可见性适配(Android 11+)

<!-- 在调用方清单文件中声明目标包名 -->
<queries><package android:name="com.target.package" /><!-- 或通过intent-filter声明 --><intent><action android:name="android.intent.action.VIEW" /><data android:scheme="https" /></intent>
</queries>

5. 运行时权限检查

// 检查是否具有自定义权限
private boolean checkCustomPermission() {int result = checkCallingOrSelfPermission("com.example.PRIVATE_ACCESS");return result == PackageManager.PERMISSION_GRANTED;
}// 在组件入口处验证
public class PrivateActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (!checkCustomPermission()) {finish();return;}// 继续执行}
}
  1. 最小权限原则‌:只申请必要的权限
  2. 防御式编程‌:关键操作前进行权限检查
  3. 错误处理‌:捕获SecurityException并提供友好提示
  4. 权限文档‌:在应用描述中说明权限用途
  5. 兼容性测试‌:在不同API级别验证权限行为

六、常见问题

问题1SecurityException: Permission Denial

原因分析‌:

  • 组件未声明所需权限
  • 调用方未声明使用权限
  • 签名不匹配(针对protectionLevel="signature"

排查步骤‌:

  1. 检查双方应用的AndroidManifest权限声明
  2. 使用adb shell dumpsys package [package名]查看权限授予状态
  3. 验证APK签名是否一致

问题2:FileProvider权限失效

解决方案‌:

// 授予接收方临时权限列表
List<ResolveInfo> resInfoList = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {grantUriPermission(resolveInfo.activityInfo.packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}

相关文章:

  • LeetCode 560. 和为 K 的子数组 | 前缀和与哈希表的巧妙应用
  • LeetCode算法题 (移除链表元素)Day15!!!C/C++
  • 如何在linux服务器下载gitee上的模型
  • 开启 Spring AI 之旅:从入门到实战
  • 开发规范-Restful
  • Linux 常用命令 - tar【归档与压缩】
  • C++负载均衡远程调用学习之UDP SERVER功能
  • MATLAB技巧——norm和vecnorm两个函数讲解与辨析
  • 组件通信-$attrs
  • 重构编程范式:解码字节跳动 AI 原生 IDE Trae 的技术哲学与实践价值
  • 数据结构学习之算法复杂度
  • 2025大模型安全研究十大框架合集(10份)
  • C++之类和对象基础
  • 微服务中组件扫描(ComponentScan)的工作原理
  • 【黑马JavaWeb+AI知识梳理】后端Web基础02 - Web基础
  • 单片机-STM32部分:1、STM32介绍
  • 【C++】认识map和set
  • Vue3源码学习4-effect中为什么使用WeakMap,Set?
  • 深入理解 MyBatis 代理机制
  • 数据结构6 · BinaryTree二叉树模板
  • “五一”第三天郑州铁路局预计发送旅客76万人
  • 德雷克海峡发生7.4级地震,震源深度10千米
  • 年轻人能为“老有意思”做点什么
  • 《探秘海昏侯国》数字沉浸特展亮相首届江西文化旅游产业博览交易会
  • 解放日报:浦东夯实“热带雨林”式科创生态
  • 揭秘神舟十九号返回舱“软着陆”关键:4台发动机10毫秒内同时点火