Uri详解

转载出处:

http://blog.csdn.net/harvic880925/article/details/44679239

http://blog.csdn.net/harvic880925/article/details/44781557

http://www.cnblogs.com/yejiurui/p/3413796.html



 

Uri详解之——Uri结构与代码提取

分类: 5、andriod开发   1366人阅读  评论(1)  收藏  举报

目录(?)[+]

前言:依然没有前言……


上几篇给大家讲了ContentProvider,里面有用到Uri,可能很多同学对Uri是什么,怎么来的,这些都不是很熟悉,今天就给大家具体讲讲Uri

一、URI与Uri

大家可能经常会看到在开发时,怎么有的时候是URI,有的时候是Uri,这是怎么回事?

名称如此相像的两个类是有什么区别和联系?

  • 1.所属的包不同。URI位置在java.net.URI,显然是Java提供的一个类。而Uri位置在android.net.Uri,是由Android提供的一个类。所以初步可以判断,Uri是URI的“扩展”以适应Android系统的需要。
  • 2.作用的不同。URI类代表了一个URI(这个URI不是类,而是其本来的意义:通用资源标志符——Uniform Resource Identifier)实例。Uri类是一个不可改变的URI引用,包括一个URI和一些碎片,URI跟在“#”后面。建立并且转换URI引用。而且Uri类对无效的行为不敏感,对于无效的输入没有定义相应的行为,如果没有另外制定,它将返回垃圾而不是抛出一个异常。

看不懂?没关系,知道这个就可以了:Uri是Android开发的,扩展了JAVA中URI的一些功能来特定的适用于Android开发,所以大家在开发时,只使用Android 提供的Uri即可;

二、Uri结构

(1)、基本形式:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. [scheme:]scheme-specific-part[#fragment]  
这里分为三部分:
scheme、scheme-specific-part、fragment

(2)、进一步划分:

如果进一步划分的话是这样子的

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. [scheme:][//authority][path][?query][#fragment]  
其中有下面几个规则:
  • path可以有多个,每个用/连接,比如
    scheme://authority/path1/path2/path3?query#fragment
  • query参数可以带有对应的值,也可以不带,如果带对应的值用=表示,如:
    scheme://authority/path1/path2/path3?id = 1#fragment,这里有一个参数id,它的值是1
  • query参数可以有多个,每个用&连接
    scheme://authority/path1/path2/path3?id = 1&name = mingming&old#fragment
    这里有三个参数:
    参数1:id,其值是:1
    参数2:name,其值是:mingming
    参数3:old,没有对它赋值,所以它的值是null
  • 在android中,除了scheme、authority是必须要有的,其它的几个path、query、fragment,它们每一个可以选择性的要或不要,但顺序不能变,比如:
    其中"path"可不要:scheme://authority?query#fragment
    其中"path"和"query"可都不要:scheme://authority#fragment
    其中"query"和"fragment"可都不要:scheme://authority/path
    "path","query","fragment"都不要:scheme://authority
    等等……

(3)、终极划分

其中authority,又可以分为host:port的形式,即再次划分后是这样的:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. [scheme:][//host:port][path][?query][#fragment]  
所以这是划分最细的形式,其中host:port用冒号分隔,冒号前的是host,冒号后的port;

三、示例

经过上面的讲解,想必大家的Uri的结构就有所了解了,下面我们就实例看看各部分的识别方式。

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. [scheme:]scheme-specific-part[#fragment]  
  2. [scheme:][//authority][path][?query][#fragment]  
  3. [scheme:][//host:port][path][?query][#fragment]  
先列出这三种Uri形式,好让大家对比;
针对下面一个Uri字符串来匹配一下各个部分:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4#harvic  
  • scheme:匹对上面的两个Uri标准形式,很容易看出在:前的部分是scheme,所以这个Uri字符串的sheme是:http
  • scheme-specific-part:很容易看出scheme-specific-part是包含在scheme和fragment之间的部分,也就是包括第二部分的[//authority][path][?query]这几个小部分,所在这个Uri字符串的scheme-specific-part是://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4 ,注意要带上//,因为除了[scheme:]和[#fragment]部分全部都是scheme-specific-part,当然包括最前面的//;
  • fragment:这个是更容易看出的,因为在最后用#分隔的部分就是fragment,所以这个Uri的fragment是:harvic
    下面就是对scheme-specific-part进行拆分了;
    在scheme-specific-part中,最前端的部分就是authority,?后面的部分是query,中间的部分就是path
  • authority:很容易看出scheme-specific-part最新端的部分是:www.java2s.com:8080
  • query:在scheme-specific-part中,?后的部分为:stove=10&path=32&id=4
  • path:在**query:**在scheme-specific-part中,除了authority和query其余都是path的部分:/yourpath/fileName.htm
    又由于authority又一步可以划分为host:port形式,其中host:port用冒号分隔,冒号前的是host,冒号后的是port,所以:
  • host:www.java2s.com
  • port:8080

四、代码提取

上面我们通过实例讲解了肉眼识别Uri更部分的方式,但在代码中又要怎样提取呢。下面就看看Uri中提取各部分的接口,依然以上面的Uri字符串为例:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4#harvic  
  • getScheme() :获取Uri中的scheme字符串部分,在这里即,http
  • getSchemeSpecificPart():获取Uri中的scheme-specific-part:部分,这里是://www.java2s.com:8080/yourpath/fileName.htm?
  • getFragment():获取Uri中的Fragment部分,即harvic
  • getAuthority():获取Uri中Authority部分,即www.java2s.com:8080
  • getPath():获取Uri中path部分,即/yourpath/fileName.htm
  • getQuery():获取Uri中的query部分,即stove=10&path=32&id=4
  • getHost():获取Authority中的Host字符串,即www.java2s.com
  • getPost():获取Authority中的Port字符串,即8080
另外还有两个常用的:getPathSegments()、getQueryParameter(String key)

  • List< String> getPathSegments():上面我们的getPath()是把path部分整个获取下来:/yourpath/fileName.htm,getPathSegments()的作用就是依次提取出Path的各个部分的字符串,以字符串数组的形式输出。以上面的Uri为例:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. String mUriStr = "http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4#harvic";  
  2. Uri mUri = Uri.parse(mUriStr);  
  3. List<String> pathSegList = mUri.getPathSegments();  
  4. for (String pathItem:pathSegList){  
  5.     Log.d("qijian","pathSegItem:"+pathItem);  
  6. }  
打出来的列表为:

  • getQueryParameter(String key):在上面我们通过getQuery()获取整个query字段:stove=10&path=32&id=4,getQueryParameter(String key)作用就是通过传进去path中某个Key的字符串,返回他对应的值。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. String mUriStr = "http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id#harvic";  
  2. mUri = Uri.parse(mUriStr);  
  3. Log.d(tag,"getQueryParameter(\"stove\"):"+mUri.getQueryParameter("stove"));  
  4. Log.d(tag,"getQueryParameter(\"id\"):"+mUri.getQueryParameter("id"));  
注意注意,我稍微更改了下字符串,把query中id的值去掉了!!!!!然后看看通过getQueryParameter("id")获取它的值会得到什么!
结果如下:

可以看到,在path中,即使针对某一个KEY不对它赋值是允许的,但在利用getQueryParameter()获取该KEY对应的值时,获取到的是null;

五、扩展

1、 绝对URI和相对URI

绝对URI:以scheme组件起始的完整格式,如http://fsjohnhuang.cnblogs.com。表示以对标识出现的环境无依赖的方式引用资源。 
相对URI:不以scheme组件起始的非完整格式,如fsjohnhuang.cnblogs.com。表示以对依赖标识出现的环境有依赖的方式引用资源。 

2、不透明URI和分层URI

不透明URI: scheme-specific-part组件不是以正斜杠(/)起始的,如mailto:fsjohnhuang@xxx.com。由于不透明URI无需进行分解操作,因此不会对scheme-specific-part组件进行有效性验证。 
分层URI: scheme-specific-part组件是以正斜杠(/)起始的,如http://fsjohnhuang.com。



 

Uri详解之二——通过自定义Uri外部启动APP与Notification启动

分类: 5、andriod开发   961人阅读  评论(2)  收藏  举报

目录(?)[+]

前言:马上快要毕业一年了,还有三个月,要在毕业一年的时候把android基础看完,把android pro4认真的过一遍,在下一年中仔细看看JAVA基础、高级应用及内核的东西。预算中最后的一年,努力吧。


一、自定义Uri与外部启动

1、概述

上篇我们讲了Uri的结构,在这篇中,我们将看看如何利用自定义的URI来启动我的的应用。 有时,我们要通过外部Uri链接来启动我们的应用,主要是通过Uri隐式Intent匹配的方式:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Uri uri = Uri.parse("qijian://test.uri.activity?action=1");  
  2. Intent intent = new Intent("android.qijian.schemeurl.activity");  
  3. intent.setData(uri);  
  4. startActivity(intent);  
这里通过隐式Intent匹配来启动应用,在这里我们自定义了一个Uri结构:qijian://test.uri.activity?action=1
我们的应用在隐式匹配Intent时,使用的语法为:
[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <activity  
  2.     android:name=".SecondActivity"  
  3.     android:label="@string/title_activity_second">  
  4.     <intent-filter>  
  5.         <action android:name="android.qijian.schemeurl.activity" />  
  6.         <category android:name="android.intent.category.DEFAULT" />  
  7.         <data  
  8.             android:scheme="qijian"  
  9.             android:host="test.uri.activity" />  
  10.     </intent-filter>  
  11. </activity>  
我们这里在匹配Intent时,使用指定scheme和host来精确匹配过来的Uri,以防止同名scheme就能启动我们的activity,即本来可能要启人家应用,确我们也横插一脚,用户体验很不好,一定要做到精确匹配,以防大家URI一样出现多个应用让用户选择的情况。
这样,第三方就能通过这个Uri来匿名启动我们的Activity了。

2、实例

(1)、新建用于外部启动的Activity
首先,我们先建一个应用,命名为:SchemeURL,在这个应用中我们新建一个Activity命名为:secondActivity,其XML代码如下:
(这个Activity是为了在外部启动,为了标识这个Activity是这个应用的,把背景色改成了黄色,文字改上了“SchemeURL 的Activity”)

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:background="#ffff00"  
  6.     tools:context="com.harvic.com.schemeurl.SecondActivity">  
  7.   
  8.     <TextView  
  9.         android:text="SchemeURL 的Activity"  
  10.         android:layout_width="wrap_content"  
  11.         android:layout_height="wrap_content" />  
  12. </RelativeLayout>  
(2)、在AndroidManifest.xml中添加Intent-filter过滤代码:
在SecondAcitivity中添加上Intent-filter用于隐式启动Intent,由于我们定义的Uri格式为:qijian://test.uri.activity?action=1,所以我们固定schemeurl和host,通过query来传递参数即可;
除了Uri匹配,我这里还添加上了Action:“android.qijian.schemeurl.activity”,所以我们在第三方隐式匹配时要同时通过Uri和action来同时匹配才能通过这里的Intent-filter
[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <activity  
  2.     android:name=".SecondActivity"  
  3.     android:label="@string/title_activity_second">  
  4.     <intent-filter>  
  5.         <action android:name="android.qijian.schemeurl.activity" />  
  6.         <category android:name="android.intent.category.DEFAULT" />  
  7.         <data  
  8.             android:scheme="qijian"  
  9.             android:host="test.uri.activity" />  
  10.     </intent-filter>  
  11. </activity>  
(3)新建应用:UseSchemeURL,通过自定义的Uri来从外部调起SecondActivity
这个应用的外观是这个样子的:当点击按钮时,调起SchemeURL的SecondActivity:

代码为:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Button btn = (Button) findViewById(R.id.btn_try);  
  2. btn.setOnClickListener(new View.OnClickListener() {  
  3.     @Override  
  4.     public void onClick(View v) {  
  5.         Uri uri = Uri.parse("qijian://test.uri.activity?action=1");  
  6.         Intent intent = new Intent("android.qijian.schemeurl.activity");  
  7.         intent.setData(uri);  
  8.         startActivity(intent);  
  9.     }  
  10. });  
(4)、进阶:通过Uri来传递参数,并处理
在上面,我们已经能够通过Uri来进入我们的应用,我们上面只是固定了Uri的scheme部分和host部分,对于其它部分并没有固定,所以我们可以通过其它部分来传递参数,进而完成指定的功能:比较进入指定的页面或做出指定的操作,等
比如,我们在SchemeURL中,对Uri进行接收,并将结果显示出来:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class SecondActivity extends Activity {  
  2.   
  3.     @Override  
  4.     protected void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(R.layout.activity_second);  
  7.         Intent intent = getIntent();  
  8.         if (null != intent) {  
  9.             Uri uri = intent.getData();  
  10.             if (uri == null) {  
  11.                 return;  
  12.             }  
  13.             String acionData = uri.getQueryParameter("action");  
  14.   
  15.             TextView tv = (TextView)findViewById(R.id.qijian_test_tv);  
  16.             tv.append("\n传过来的action值为:" + acionData);  
  17.         }  
  18.     }  
  19. }  
结果截图如下:

源码在文章底部给出;

二、特殊应用:Notification与应用启动

有关通过Uri启动APP的经典应用,应当数通过推送消息启动我们应用的指定页面或做出特定的操作了。这部分,我们就看看如何通过推送的通知栏消息来进入我们的应用。

效果如下:


  • 首先:SchemeURL工程代码都不变,我们依然通过隐式匹配Intent来启动SecondActivity.
  • 然后:在UseSchemeURL工程中新加一个按钮,当点击时,发送Notification通知,点击跳转到SchemeURL工程的SecondActivity 
其中发送Notification代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private void pushNotify() {  
  2.     NotificationManager notifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
  3.     NotificationCompat.Builder builder;  
  4.     builder = new NotificationCompat.Builder(this);  
  5.     builder.setSmallIcon(R.drawable.ic_launcher)  
  6.             .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher))  
  7.             .setContentTitle("harvic")  
  8.             .setContentText("test schemeURL")  
  9.             .setTicker("有新消息")  
  10.             .setOngoing(false)  
  11.             .setWhen(System.currentTimeMillis())  
  12.             .setPriority(Notification.PRIORITY_DEFAULT)  
  13.             .setAutoCancel(true);  
  14.   
  15.     Uri uri = Uri.parse("qijian://test.uri.activity?action=1");  
  16.     Intent intent = new Intent("android.qijian.schemeurl.activity");  
  17.     intent.setData(uri);  
  18.     PendingIntent pendingIntent = PendingIntent.getActivity(this0, intent, PendingIntent.FLAG_UPDATE_CURRENT);  
  19.     builder.setContentIntent(pendingIntent);  
  20.     Notification notification = builder.build();  
  21.     notifyManager.notify(1111, notification);  
  22. }  
有关Notification的知识,我就不再讲了,最重要的是PendingIntent的封装!
即如下代码:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Uri uri = Uri.parse("qijian://test.uri.activity?action=1");  
  2. Intent intent = new Intent("android.qijian.schemeurl.activity");  
  3. intent.setData(uri);  
  4. PendingIntent pendingIntent = PendingIntent.getActivity(this0, intent, PendingIntent.FLAG_UPDATE_CURRENT);  
在这里大家也可以看到,这是利用隐式Intent匹配的方式来启动我们的Activity的!所有的APP在通知栏进入到自己的应用,都是通过这个方式来的!
源码在文章底部给出

三、有关path、pathPrefix、pathPattern 之间的区别

细心的同学可能在AndroidManifest.xml中已经发现,Intent-filter的data域除了scheme、host、port这些已知的还有三个参数我们没用过——path、pathPrefix、pathPattern;它们也是用来隐式匹配Intent的,即:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <activity  
  2.     android:name=".SecondActivity"  
  3.     android:label="@string/title_activity_second">  
  4.     <intent-filter>  
  5.         <action android:name="android.qijian.schemeurl.activity" />  
  6.         <category android:name="android.intent.category.DEFAULT" />  
  7.         <data  
  8.             android:scheme="qijian"  
  9.             android:host="test.uri.activity"  
  10.             android:path=""  
  11.             android:pathPrefix=""  
  12.             android:pathPattern=""/>  
  13.     </intent-filter>  
  14. </activity>  
这里主要说的区别是 path、pathPrefix、pathPattern 之间的区别
  • path: 用来匹配完整的路径,如:http://example.com/blog/abc.html,这里将 path 设置为 /blog/abc.html 才能够进行匹配;
  • pathPrefix: 用来匹配路径的开头部分,拿上面的 Uri 来说,这里将 pathPrefix 设置为 /blog 就能进行匹配了;
  • pathPattern: 用表达式来匹配整个路径,这里需要说下匹配符号与转义。 
匹配符号: 
1、“” 用来匹配0次或更多,如:“a” 可以匹配“a”、“aa”、“aaa”… 
2、“.” 用来匹配任意字符,如:“.” 可以匹配“a”、“b”,“c”… 
3、因此 “.*” 就是用来匹配任意字符0次或更多,如:“.*html” 可以匹配 “abchtml”、“chtml”,“html”,“sdf.html”… 
转义: 
因为当读取 Xml 的时候,“\” 是被当作转义字符的(当它被用作 pathPattern 转义之前),因此这里需要两次转义,读取 Xml 是一次,在 pathPattern 中使用又是一次。如:“” 这个字符就应该写成 “\”,“\” 这个字符就应该写成 “\\”。

样例:匹配 http 以 “.pdf” 结尾的路径

如果我们想要匹配 http 以 “.pdf” 结尾的路径,使得别的程序想要打开网络 pdf 时,用户能够可以选择我们的程序进行下载查看。

我们可以将 scheme 设置为 “http”,pathPattern 设置为 “.*\.pdf”,整个 intent-filter 设置为:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <intent-filter>  
  2.      <action android:name="android.intent.action.VIEW"></action>  
  3.      <category android:name="android.intent.category.DEFAULT"></category>  
  4.      <data android:scheme="http" android:pathPattern=".*\\.pdf"></data>  
  5. </intent-filter>  
如果你只想处理某个站点的 pdf,那么在 data 标签里增加 android:host="yoursite.com" 则只会匹配 http://yoursite.com/xxx/xxx.pdf,但这不会匹配 www.yoursite.com,如果你也想匹配这个站点的话,你就需要再添加一个 data 标签,除了 android:host 改为 “www.yoursite.com” 其他都一样。

四、特殊:如何从网页中通过Uri启动我们的应用

如果想要从网页中点击一个链接跳转到我们的应用,那除了Intent-filter中的各种匹配工作,还应该加上一个属性:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <category android:name="android.intent.category.BROWSABLE"/>  
即,以我们的SecondActivity为例,它完整的AndroidManifest.xml的配置方式为:
[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <activity  
  2.     android:name=".SecondActivity"  
  3.     android:label="@string/title_activity_second">  
  4.     <intent-filter>  
  5.         <action android:name="android.qijian.schemeurl.activity" />  
  6.         <category android:name="android.intent.category.DEFAULT" />  
  7.         <category android:name="android.intent.category.BROWSABLE"/>  
  8.         <data  
  9.             android:scheme="qijian"  
  10.             android:host="test.uri.activity"/>  
  11.     </intent-filter>  
  12. </activity>  

参考文章:《intent-filter 之 data 「scheme, host, port, mimeType, path, pathPrefix, pathPattern」》







如何通过Html网页调用本地安卓app?

一、通过html页面打开Android本地的app


1、首先在编写一个简单的html页面

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">    
        <title>Insert title here</title>
    </head>
    <body>
        <a href="m://my.com/">打开app</a><br/>
    </body>
</html>


2、在Android本地app的配置

在AndroidManifest的清单文件里的intent-filte中加入如下元素:
 <intent-filter>
<action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data
                    android:host="my.com" 
                    android:scheme="m" />
</intent-filter>

然后使用“手机浏览器”或者“webview”的方式打开这个本地的html网页,点击“打开APP”即可成功开启本地的指定的app


二、如何通过这个方法获取网页带过来的数据

只能打开就没什么意思了,最重要的是,我们要传递数据,那么怎么去传递数据呢?

我们可以使用上述的方法,把一些数据传给本地app,那么首先我们更改一下网页,代码修改后:

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Insert title here</title>
    </head>
    <body>
        <a href="m://my.com/?arg0=0&arg1=1">打开app</a><br/>
    </body>
</html>

(1).假如你是通过浏览器打开这个网页的,那么获取数据的方式为:

Uri uri = getIntent().getData();  String test1= uri.getQueryParameter("arg0");  String test2= uri.getQueryParameter("arg1");
(2)如果使用webview访问该网页,获取数据的操作为:

webView.setWebViewClient(new WebViewClient(){
  @Override
  public boolean shouldOverrideUrlLoading(WebView view, String url) {
      Uri uri=Uri.parse(url);
          if(uri.getScheme().equals("m")&&uri.getHost().equals("my.com")){
              String arg0=uri.getQueryParameter("arg0");
              String arg1=uri.getQueryParameter("arg1");
             
          }else{
              view.loadUrl(url);
          }
      return true;
  }
});

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值