隐式Intent解析
回顾Android
中的隐式Intent
的相关知识点。
-
-
- 概述
- 使用
- action标签
- category标签
- data标签
- mimeType
- scheme
- host
- port
- path
- pathPrefix
- pathPattern
- data总结
- 从网页启动app
-
概述
隐式启动主要解决了界面间的跳转解耦,主要涉及intent-filter
中的三个标签:
- category
- action
data
它们构成了隐式启动的匹配项,通过不同的配置完成不同的路由跳转。
使用
列一个例子,新建一个APP
有两个界面,一为MainActivity
,一个为ActionActivity
,MainActivity
中有一个按钮,通过按钮启动隐式Intent
来启动ActionActivity
。
布局和代码非常简单:
MainActivity
的布局和代码:
//布局中只有一个按钮<?xml version="1.0" encoding="utf-8"?>"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=".MainActivity"> //代码public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btn = findViewById(R.id.bt_action); }}
ActionActivity
的布局和代码:
//布局中就是一行文字说明<?xml version="1.0" encoding="utf-8"?>"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" tools:context=".ActionActivity">"我是跳转的页面" android:layout_width="match_parent" android:layout_height="wrap_content" /> //代码public class ActionActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_action); }}
action标签
给MainActiity
的按钮添加代码,如果找不到的话会抛出异常,因此捕获并打印启动失败的信息:
btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try{ //Intent action1 = new Intent("action1");//可以使用构造传入action参数 Intent action1 = new Intent(); action1.setAction("action1"); startActivity(action1); }catch (Exception e){ Toast.makeText(MainActivity.this,"启动失败",Toast.LENGTH_LONG).show(); e.printStackTrace(); } });
清单文件中的ActionActivity
的配置,可以看到只使用了action
标签:
<activity android:name=".ActionActivity"> <intent-filter> <action android:name="action1"/> intent-filter> activity>
启动MainActivity
,点击按钮,结果抛出异常:
异常结果为:
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=action1 }
所以实际上ActionActivity
只配置action
标签是不够的。
category标签
增加默认的android.intent.category.DEFAULT
:
<activity android:name=".ActionActivity"> <intent-filter> <category android:name="android.intent.category.DEFAULT"/> <action android:name="action1"/> intent-filter> activity>
intent
的代码不做变动,这时点击按钮可以正常跳转:
说明这里category 是必须要配置的,Intent
虽然没有设置category
,但是默认就是这个android.intent.category.DEFAULT
,所以能够匹配到。
再增加一个action
试试:
<activity android:name=".ActionActivity"> <intent-filter> <category android:name="android.intent.category.DEFAULT"/> <action android:name="action1"/> <action android:name="action2"/> intent-filter> activity>
intent
的代码不做变动,点击按钮依旧可以正常跳转,效果不再贴出。
如果给Intent
增加一个intent-filter
标签中没有的action
试试:
Intent action1 = new Intent(); action1.setAction("action1"); action1.setAction("action3"); startActivity(action1);
点击抛出ActivityNotFoundException
异常,,效果不再贴出。
通过上面的测试说明intent
设置的action
必须为目标页面intent-filter
中action
的子集才能正常跳转,并且是区分大小写的。
测试完了action
,更换下category
为自定义的category1
试试:
<activity android:name=".ActionActivity"> <intent-filter> <category android:name="category1"/> <action android:name="action1"/> intent-filter> activity>
代码中:
Intent action1 = new Intent(); action1.setAction("action1"); action1.addCategory("category1"); startActivity(action1);
运行点击抛出ActivityNotFoundException
异常,效果不再贴出。
然后增加android.intent.category.DEFAULT
这个默认的action
在测试:
<activity android:name=".ActionActivity"> <intent-filter> <category android:name="android.intent.category.DEFAULT"/> <category android:name="category1"/> <action android:name="action1"/> intent-filter> activity>
运行点击按钮可以正常跳转,效果不再贴出。
说明android.intent.category.DEFAULT
这个默认的action
是必须要在intent-filter
标签中声明的。
如果存在多个action
匹配的页面,那么启动后会弹出选择对话框,比如编写一个新的界面为Action2Activity
,它也接受action1
的动作:
布局:
<?xml version="1.0" encoding="utf-8"?><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" tools:context=".Action2Activity"> <TextView android:text="我也是跳转的页面!" android:textSize="32dp" android:layout_width="match_parent" android:layout_height="wrap_content" />LinearLayout>
清单文件:
<activity android:name=".Action2Activity"> <intent-filter> <category android:name="android.intent.category.DEFAULT" /> <action android:name="action1" /> intent-filter> activity>
代码只设置action1
:
Intent action1 = new Intent(); action1.setAction("action1"); startActivity(action1);
运行效果:
如果再增加一个自定义的category2
试试:
<activity android:name=".ActionActivity"> <intent-filter> <category android:name="android.intent.category.DEFAULT"/> <category android:name="category1"/> <category android:name="category2"/> <action android:name="action1" /> intent-filter> activity>
代码不做变动,点击按钮可以正常跳转。
如果在代码中增加一个category3
试试:
Intent action1 = new Intent(); action1.addCategory("category1"); action1.addCategory("category3"); action1.setAction("action1"); startActivity(action1);
运行点击抛出ActivityNotFoundException
异常,效果不再贴出。
同样说明intent
中的category
,必须为目标页面intent-filter
中category
的子集才能正常跳转,和action
的匹配规则是一样的。
另外说明下,只使用category
而不添加任何action
也是无法匹配的,说明intent
中的action
是必须要设置的。而且如果配置了多个intent-filter
标签也是按照一组一组进行匹配的,直到与其中一组匹配成功。
data标签
data
标签自然不是必须的,主要为URL
的表现形式,它的格式如下:
<data android:mimeType=""/>//媒体类型 例如 "image/*"就是匹配图片类型 <data android:scheme=""/>//例如: http,https <data android:host=""/>//例如:www.csdn.net <data android:port=""/>//例如:8080 <data android:path=""/> // 路径:如 /nav/blockchain <data android:pathPrefix=""/> <data android:pathPattern=""/>// 正则表达式标识的路径 <data android:ssp=""/> <data android:sspPrefix=""/> <data android:sspPattern=""/>
data的属性比较多:
mimeType
媒体类型 例如image/*
就是匹配图片类型,mimeType
类型比较多 ,这里不再列出;scheme
类似如http
,https
host
类似www.csnd.com
port
类似8080
path
路径:/nav/blockchain
pathPrefix
路径前缀:/nav
pathPattern
路径的正则表达式方式ssp
//可以匹配系统特定intent 相关文章通过android:ssp高效过滤Android IntentssspPrefix
//可以匹配系统特定intentsspPattern
//可以匹配系统特定intent类似这样
,:// : [ | | ]
例如action://action1:44/abc/xyz
。
mimeType
改动下上面的例子:
<activity android:name=".ActionActivity"> <intent-filter> <category android:name="android.intent.category.DEFAULT"/> <action android:name="action1"/> <data android:mimeType="image/*"/>//指定媒体类型为图片的类型 intent-filter> activity>
代码中不设置action
,只设置mimeType
:
Intent action1 = new Intent(); action1.setType("image/png");//指定了媒体类型为png的图片类型 startActivity(action1);
运行效果:
这里可以看到只要有任何能够匹配的mimeType
为image/png
的应用都会在底部的列表弹出,但是如果Intent
不设置mimeType
而只设置action
,那么是无法匹配的,说明mimeType
的需要优先匹配的。
如果action
和mimeType
完全匹配,就可以更为精准的匹配。
需要注意的是清单文件中设置了mimeType
而不设置scheme
的话,intent
中的默认的scheme
是content
或者file
才能进行匹配(在API 24
以后只能对应content
的scheme
了),意味着mimeType
其实对应了默认的scheme
。
看下代码实现:
Intent action1 = new Intent(); action1.setDataAndType(Uri.parse("content://action1"),"image/png"); action1.setAction("action1"); startActivity(action1);
这里setDataAndType
方法才能同时设置data
和mimeType
,单独使用setData
或者setType
两者都会将对方清空。
同样如果清单文件中指定了多个mimeType
那么,只要Intent
匹配到一个就可以。
scheme
在上面的例子中scheme就是content://action1
中的content
了,更改个自定义的scheme
测试:
<activity android:name=".ActionActivity"> <intent-filter> <category android:name="android.intent.category.DEFAULT" /> <action android:name="action1" /> <data android:mimeType="image/*"/> <data android:scheme="action"/> intent-filter> activity>
Intent action1 = new Intent(); action1.setDataAndType(Uri.parse("action://action1"),"image/png"); action1.setAction("action1"); startActivity(action1);
运行可以正常启动的,这里不再帖效果。当然清单文件不设置mimeType
的话,Intent
就可以使用setData
方法来设置URL
的。
host
上面例子的action://action1
中action1
就是host
了,需要注意的是如果清单文件中没有指定host
的话, port
,path
,pathPrefix
,pathPattern
都不会生效。
port
port
需要和host
放在同一个data
标签内才能生效:
<activity android:name=".ActionActivity"> <intent-filter> <category android:name="android.intent.category.DEFAULT" /> <action android:name="action1" /> <data android:scheme="action"/> <data android:host="action1" android:port="44"/> <data /> intent-filter> activity>
代码:
Intent action1 = new Intent(); action1.setData(Uri.parse("action://action1:44")); action1.setAction("action1"); startActivity(action1);
可以正常跳转。
path
代码增加/abc/xyz
:
Intent action1 = new Intent(); action1.setData(Uri.parse("action://action1:44/abc/xyz")); action1.setAction("action1"); startActivity(action1);
清单文件:
<activity android:name=".ActionActivity"> <intent-filter> <category android:name="android.intent.category.DEFAULT" /> <action android:name="action1" /> <data android:scheme="action"/> <data android:host="action1" android:port="44"/> <data android:path="/abc/xyz"/>//必须以/开头 <data /> intent-filter> activity>
这样完全匹配。
pathPrefix
匹配path
的前缀,上面例子中就是/abc
<activity android:name=".ActionActivity"> <intent-filter> <category android:name="android.intent.category.DEFAULT" /> <action android:name="action1" /> <data android:scheme="action"/> <data android:host="action1" android:port="44"/> <data android:pathPrefix="/abc"/> <data /> intent-filter> activity>
pathPattern
利用正则表达式/.*
匹配/abc
:
<activity android:name=".ActionActivity"> <intent-filter> <category android:name="android.intent.category.DEFAULT" /> <action android:name="action1" /> <data android:scheme="action"/> <data android:host="action1" android:port="44"/> <data android:pathPattern="/.*/xyz"/> intent-filter> activity>
.*
就是表示匹配任意字符,这样也能够灵活匹配,需要注意正则表达式中的符号如果当做字符处理需要进行转义。
data总结
比如要匹配action://action1:44/abc/xyz
这样的URL
的话,清单文件中至少需要写到scheme
:
<data android:scheme="action"/>
其实也就是说Intent
中的data
应该为清单文件中data
的子集。
从网页启动app
隐式Intent
也可以从网页中启动Activity
,比如有一个远程网页内容如下:
<html lang="en"><head> <meta charset="UTF-8"> <title>Titletitle>head><body><a href="action://action1:44/abc/xyz?m=1&n=2">启动页面a>body>html>
a
标签中的href
为自定义链接,对应的在清单文件中做出改动:
<activity android:name=".ActionActivity"> <intent-filter> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <action android:name="android.intent.action.VIEW" /> <data android:scheme="action" android:host="action1" android:port="44" android:path="/abc/xyz" /> intent-filter> activity>
ActionActivity
中可以获取各种数据:
public class ActionActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_action); Uri data = getIntent().getData(); if (data != null){ Log.d("url",data.toString()); String scheme = data.getScheme(); Log.e("scheme", scheme); String host = data.getHost(); Log.e("host", host); int port = data.getPort(); Log.e("port", port+""); String path = data.getPath(); Log.e("path", path); List<String> pathSegments = data.getPathSegments();//路径分割 String params = data.getQuery(); Log.e("params", params); String value = data.getQueryParameter("m"); Log.e("m值", value); } }}
如果从浏览器中打开页面,点击a
标签链接,可以成功跳转并看到打印结果:
08-20 11:33:01.181 4491-4491/cn.franky.test E/scheme: action08-20 11:33:01.182 4491-4491/cn.franky.test E/host: action108-20 11:33:01.182 4491-4491/cn.franky.test E/port: 4408-20 11:33:01.182 4491-4491/cn.franky.test E/path: /abc/xyz08-20 11:33:01.182 4491-4491/cn.franky.test E/params: m=1&n=208-20 11:33:01.182 4491-4491/cn.franky.test E/m值: 1
隐式Intent
总结到此。
更多相关文章
- android 关掉Eclipse的自动代码提示
- 学习android笔记1 之工具篇
- 简单音乐播放实例的实现,Android(安卓)Service AIDL 远程调用服
- Android(安卓)混淆 以及 java代码方式实现混淆配置
- android 之访问WebService显示手机号码归属地
- Android积累之《Android(安卓)strings.xml文件定义字符串中的标
- android 使用ContentProvider共享数据
- Android(安卓)两个Activity之间信息的交互
- android 打包时报错解决