前言
今天遇到apk设置了LAUNCHER但不显示图标的问题,于是开始好好了解了下Intent的属性和用法,在学习过程中找到了问题原因并成功解决了问题(问题放在第3部分内容),在这里总结下。
1. 显示调用
显示调用需要明确的指出被启动对象的类名;
- Intent第1个参数为当前类;
- 第2个参数为要跳转到的类
Intent intent = new Intent(MainActivity.this,xxxActivity.class);
startActivity(intent);
2. 隐式调用
需要Intent能匹配目标组件的IntentFilter中所设置的过滤信息.如果不匹配将无法启动目标Activity;
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Test">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
隐式调用主要是通过在Andriodmanifest.xml文件中给Activity添加过滤器,为该Activity设置属性,隐式调用时根据属性寻找匹配的Activity来启动
Intent intent = new Intent();
intent.setAction("android.intent.action.View");
startActivity(intent);
如果存在多个应用的Activity的属性均匹配,则需要选择应用启动;
如:在手机端播放音频,会弹出提示框询问你要使用 (QQ音乐、网易云音乐、本地播放器等) 哪种应用来播放。
------------------那么接下来总结下隐式Intent的主要属性和匹配规则------------------
1. Action
Action属性主要用来指定组件要执行的动作;
系统内置的部分Action如下所示:
Action常量 | 组件 | 动作 |
---|---|---|
ACTION_MAIN | Activity | Android Application的入口,每个Android应用必须且只能包含一个此类型的Action声明 |
ACTION_VIEW | Activity | 系统根据不同的Data类型,通过已注册的对应Application显示数据 |
ACTION_EDIT | Activity | 系统根据不同的Data类型,通过已注册的对应Application编辑示数据 |
ACTION_DIAL | Activity | 打开系统默认的拨号程序,如果Data中设置了电话号码,则自动在拨号程序中输入此号码 |
ACTION_CALL | Activity | 直接呼叫Data中所带的号码。 |
ACTION_ANSWER | Activity | 接听来电 |
ACTION_SEND | Activity | 由用户指定发送方式进行数据发送操作。 |
ACTION_SENDTO | Activity | 系统根据不同的Data类型,通过已注册的对应Application进行数据发送操作 |
ACTION_BOOT_COMPLETED | Broadcast | Android系统在启动完毕后发出带有此Action的广播 |
ACTION_TIME_CHANGED | Broadcast | Android系统的时间发生改变后发出带有此Action的广播 |
ACTION_PACKAGE_ADDED | Broadcast | Android系统安装了新的Application之后发出带有此Action的广播 |
ACTION_PACKAGE_CHANGED | Broadcast | Android系统中已存在的Application发生改变之后(如应用更新操作)发出带有此Action的广播 |
ACTION_PACKAGE_REMOVED | Broadcast | 卸载了Android系统已存在的Application之后发出带有此Action的广播 |
- 匹配规则
- 一个intent-filter中至少得有一个Action属性;
- 一个intent-filter中可以有多个Action,只要Intent中的Action能够和Activity过滤规则中的任何一个Action相同即可匹配成功。
2. Category
Category属性用于指定当前动作(Action)被执行的环境;
常用的Category如下所示:
Category常量 | 意义 |
---|---|
CATEGORY_DEFAULT | Android系统中默认的执行方式,按照普通Activity的执行方式执行 |
CATEGORY_HOME | 设置该组件为Home Activity,随系统启动而运行 |
CATEGORY_LAUNCHER | 设置该组件为在当前应用程序启动器中优先级最高的Activity,通常与入口ACTION_MAIN配合使用 |
CATEGORY_BROWSABLE | 设置该组件可以使用浏览器启动 |
- 匹配规则
- 一个intent-filter中可以不声明Category属性(默认为DEFAULT),也可以声明多个Category;
- Activity中存在的所有Category(个数可以少于Intent中存在的Category)必须与Intent中的Category相同才能匹配成功;
- Category属性是一个执行Action的附加信息,只通过Category属性匹配Activity是无法匹配的,需要和Action属性一起匹配来启动Activity。
3. Data
Data属性通常用于向Action属性提供操作的数据(如点击链接跳转到浏览器显示在输入框中);
Data 由2部分组成:
- MineType :指的是媒体类型(图片imgage/jpeg、视频viedo/*);
- URI:通用资源标识符,格式为scheme://host:port/path
URI的属性如下所示:
属性 | 意义 |
---|---|
Scheme | URL的模式,如果URI中没有指定Scheme,那么整个URI无效(默认值为content 和 file) |
Host | URI的host,①如果指定了scheme和port,path等其他参数,但是host未指定,那么整个URI无效,②如果只指定了scheme没有指定host和其他参数,URI是有效的 |
Port | URI端口,当URI指定了scheme 和 host 参数时port参数才有意义 |
path | 用来匹配完整的路径 |
pathPrefix | 用来匹配路径的开头部分 |
pathPattern | 用表达式来匹配整个路径 |
系统内置的部分Data属性常量如下:
Data取值 | 意义 |
---|---|
tel:// | 号码数据格式,后接电话号码 |
mailto:// | 邮件数据格式,后接邮件收件人地址 |
smsto:// | 短息数据格式,后接短信接收号码 |
content:// | 内容数据格式,后接需要读取的内容 |
file:// | 文件数据格式,后接文件路径 |
geo:// | 经纬数据格式,后接经纬度数据 |
http:// | 超文本,后接网络资源URI |
- 匹配规则
- 一个intent-filter中可以不声明Data属性,也可以声明多个Data属性;
- 如果intent-filter中未声明URI和MIME类型,则只有不含URI和MIME类型的隐形Intent才能匹配成功;
- 如果intent-filter中声明URI但是未声明MIME类型(也不能从URI中分析出MIME类型),则只有URI与intent-filter中URI相同且不包含MIME类型的隐式Intent才能匹配成功;
- 如果intent-filter中声明MIME类型但是未声明URI,只有包含相同MIME类型但是不包含URI的隐式Intent才能匹配成功;
- 如果intent-filter中声明了URI和MIME类型(既可以是直接设置,也可以是从URI分析出来),只有包含相同的URI和MIME类型的隐式Intent才能匹配成功。
------------------了解完Intent基础知识之后回来解决问题------------------
通常Intent隐式调用会在Andriodmanifest.xml中的MainActivity中默认生成
- 一个常量为MAIN的Action属性:将MainActivity设置为该程序的入口Activity;
- 一个常量为LAUNCHER的Category属性:将MainActivity列入系统的启动器,允许用户启动,会生成应用图标;
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
如果没有Category属性或Category属性为默认DEFAULT时,运行出来的apk是可以成功安装到设备上的,但是不会生成应用图标,也不会自动拉起运行,效果如下;
01/06 09:27:10: Launching 'app' on HIKVISION DS-KD94x3.
Install successfully finished in 8 s 154 ms.
Could not identify launch activity: Default Activity not found
Error while Launching activity
此时如果想运行该apk只能通过adb命令来启动;
adb shell am start -n com.example.test/.MainActivity
而客户的问题是这样的:
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*"/>
</intent-filter>
</activity>
中包含多个Action属性和多个Category属性,且Category属性中LAUNCHER和DEFAULT同时存在,在了解Intent之前我猜测应用图标不显示会不会是因为最后一个DEFAULT把前面的LAUNCHER值覆盖了,但是了解之后发现Category属性允许存在多个值,于是就转换思路去找解决办法;
原因:Activity中的intent-filter中设置了不同的Action和Data,会通过两种方式启动,所以不能放在一起;
解决办法就是把Data属性单拎出来写在一个中:
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<data android:mimeType="*/*"/>
</intent-filter>
</activity>
再次安装apk就会自动运行,并且系统中也会显示应用图标了。
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)