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

【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);
}

http://www.xdnf.cn/news/3497.html

相关文章:

  • Android Framework学习二:Activity创建及View绘制流程
  • 2025大模型安全研究十大框架合集(10份)
  • 010302-oss_反向代理_负载均衡-web扩展2-基础入门-网络安全
  • 多模态RAG演进-MRAG1.0->MRAG2.0->MRAG3.0
  • 游戏引擎学习第254天:重新启用性能分析
  • 白蚁检测数据集VOC+YOLO格式949张2类别
  • 【计算机视觉】三维视觉:Instant-NGP:实时神经辐射场的革命性突破
  • MSP430G2553驱动0.96英寸OLED(硬件iic)
  • docker安装jenkins v2.504.1集群
  • 【业务领域】InfiniBand协议总结
  • Flowable7.x学习笔记(十七)审批我的待办
  • MySQL 第一讲---基础篇 安装
  • Linux 下使用tcpdump进行网络分析原
  • 颠覆者DeepSeek:从技术解析到实战指南——开源大模型如何重塑AI生态
  • 紫荆阁电玩平台环境搭建与系统运行实录(蒙特卡洛系列)
  • 单片机-STM32部分:1、STM32介绍
  • 【SpringBoot】Spring中事务的实现:声明式事务@Transactional、编程式事务
  • 纯前端专业PDF在线浏览器查看器工具
  • 【数据结构】String字符串的存储
  • 当MCP撞进云宇宙:多芯片封装如何重构云计算的“芯“未来?
  • 循环插入数据库行
  • LEETERS题解
  • 【速写】prune与activate
  • 尝试leaflet+webassemly
  • 【Python-Day 8】从入门到精通:Python 条件判断 if-elif-else 语句全解析
  • day09-面向对象综合训练
  • 实验三 软件黑盒测试
  • 【记录】台式机安装GTX1660驱动过程
  • 【RocketMQ 生产者消费者】- 同步、异步、单向发送消费消息
  • 学习与规划的融合Dyna-Q:python从零实现