android之Uri

一.URI简介

概念:统一资源标识符(Uniform Resource Identifier)

组成部分:
    1.访问资源的命名机制(scheme)
    2.存放资源的主机名(authority)

    3.资源自身的名称,由路径表示(path)

格式:scheme:// authority//path,其中authority中又包括了host和port两部分。

例如:
content://com.example.project:200/folder/subfolder/etc
 ———/ —————————-/ —-/ ————————/
 Scheme          host             port              path
            ————————————/

                            Authority


用处:uri主要用来表示一个资源。这个资源有很多种类,包括图片,视频,文件等。

针对资源的种类,uri用以下几种scheme标识:

      1.Content:主要操作的是ContentProvider,所以它代表的是数据库中的某个资源
      2.http:一个网站资源
      3.file:本地机器上的某个资源
      4.git:git仓库中某个资源
      5.ftp:服务器上的某个资源
      6.ed2k:(电驴协议)
      7.等等……….
以上的资源例子如下:

  1. http://write.blog.csdn.net/postedit/7313543,    
  2. file:///c:/WINDOWS/clock.avi  
  3. git://github.com/user/project-name.git  
  4. ftp://user1:1234@地址  
  5. ed2k://|file|%5BMAC%E7%89%88%E6%9E%81%E5%93%81%E9%A3%9E%E8%BD%A69%EF%BC%9A%E6%9C%80%E9%AB%98%E9%80%9A%E7%BC%89%5D.%5BMACGAME%5DNeed.For.Speed.Most.Wanted.dmg|4096933888|2c55f0ad2cb7f6b296db94090b63e88e|h=ltcxuvnp24ufx25h2x7ugfaxfchjkwxa|/  
http://write.blog.csdn.net/postedit/7313543, 
file:///c:/WINDOWS/clock.avi
git://github.com/user/project-name.git
ftp://user1:1234@地址
ed2k://|file|%5BMAC%E7%89%88%E6%9E%81%E5%93%81%E9%A3%9E%E8%BD%A69%EF%BC%9A%E6%9C%80%E9%AB%98%E9%80%9A%E7%BC%89%5D.%5BMACGAME%5DNeed.For.Speed.Most.Wanted.dmg|4096933888|2c55f0ad2cb7f6b296db94090b63e88e|h=ltcxuvnp24ufx25h2x7ugfaxfchjkwxa|/

在Android中,由于很多资源(音频、视频、图片、以及个人通信录信息)都存入了数据库,所以Android中对资源的使用一般是通过ContentProivder访问数据库,见得比较多的就是Content这种类型的uri。所以我们这里也只是着重讲Content类型的uri。


二.uri详解

1.Authority部分:
在看Authority之前,让我们先了解一下ContentProvider。
ContentProvider在android中的作用是对外共享数据, 也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对你应用中的数据进行添删改查。那么其他的应用该怎么找到这个ContentProvider?答案在AndroidManifest.xml中配置:

  1. package=“com.android.providers.telephony”  
  2.         <provider android:name=“TelephonyProvider”  
  3.                   android:authorities=“telephony”  
  4.                   android:exported=“true”  
  5.                   android:singleUser=“true”  
  6.                   android:multiprocess=“false” />  
package="com.android.providers.telephony" 
<provider android:name="TelephonyProvider"
android:authorities="telephony"
android:exported="true"
android:singleUser="true"
android:multiprocess="false" />
在这里,规定了这个TelephonyProvider内容提供者对外提供的主机(authorities)为telephony。
   好了,让我们回去看看content://com.example.project:200/folder/subfolder/etc这个例子。host主要是用com.example.project来表示,这根本就是一个包名啊。但是通过AndroidManifest.xml配置后,就看到了最常见的uri:

所有SIM卡信息的Uri: content:// telephony/siminfo
某张SIM卡的Uri: content:// telephony/siminfo/2
所有图片Uri: content://media/external
某个图片的Uri:content://media/external/images/media/4

2.path部分:
path部分就简单了,既然Authority指定了一个ContentProvider。那么如果我们需要某个具体的资源,就需要通过查询数据库表,在表中存储的位置等等信息了。所以content:// telephony/siminfo/2中siminfo代表的是数据库表名,2代表的是表中某个具体的数值。


三.Uri及它的工具类

1.Uri.java
Uri主要的结构如下:
Uri的内部类:
——- StringUri  子孙类,使用不明
——- OpaqueUri 子孙类,使用不明
——- HierarchicalUri子孙类,Builder构建Uri的实例对象主要是使用了这个类。
——- Builder 静态类,用于获取Uri实例对象。
——- ….
由于Uri的构造方法是私有的,所以它提供了Builder这个静态类用于获取Uri的实例对象。除了获取对象外,它还提供了很多实用的方法,比如:
Public Uri Build()——-获取Uri的实例对象
Public Builder encodedPath(String path)——–根据path构建Builder对象
public Builder authority(String authority)——-根据authority构建Builder对象
…….
Uri的主要方法:

  1. public static Uri withAppendedPath(Uri baseUri, String pathSegment)  
  2. public boolean isPathPrefixMatch(Uri prefix)   
  3. public static String encode(String s, String allow)  
public static Uri withAppendedPath(Uri baseUri, String pathSegment) 
public boolean isPathPrefixMatch(Uri prefix)
public static String encode(String s, String allow)
Uri的两个操作工具类:UriMatcher和ContentUris

2.UriMatcher.java
构造方法:
  1. private ArrayList<UriMatcher> mChildren;  
  2.     public UriMatcher(int code)  
  3.     {  
  4.         mCode = code;  
  5.         mWhich = -1;  
  6.         mChildren = new ArrayList<UriMatcher>();  
  7.         mText = null;  
  8. }  
private ArrayList<UriMatcher> mChildren; 
public UriMatcher(int code)
{
mCode = code;
mWhich = -1;
mChildren = new ArrayList<UriMatcher>();
mText = null;
}

UriMatcher维护了一个ArrayList用于保存所有加进来的UriMatcher对象。执行添加操作的方法如下:

  1. public void addURI(String authority, String path, int code)  
  2.     {  
  3.         if (code < 0) {  
  4.             throw new IllegalArgumentException(“code ” + code + “ is invalid: it must be positive”);  
  5.         }  
  6.   
  7.         String[] tokens = null;  
  8.         if (path != null) {  
  9.             String newPath = path;  
  10.             // Strip leading slash if present.  
  11.             if (path.length() > 0 && path.charAt(0) == ‘/’) {  
  12.                 newPath = path.substring(1);  
  13.             }  
  14.             tokens = PATH_SPLIT_PATTERN.split(newPath);  
  15.         }  
  16.   
  17.         int numTokens = tokens != null ? tokens.length : 0;  
  18.         UriMatcher node = this;  
  19.         for (int i = -1; i < numTokens; i++) {  
  20.             String token = i < 0 ? authority : tokens[i];  
  21.             ArrayList<UriMatcher> children = node.mChildren;  
  22.             int numChildren = children.size();  
  23.             UriMatcher child;  
  24.             int j;  
  25.             for (j = 0; j < numChildren; j++) {  
  26.                 child = children.get(j);  
  27.                 if (token.equals(child.mText)) {  
  28.                     node = child;  
  29.                     break;  
  30.                 }  
  31.             }  
  32.             if (j == numChildren) {  
  33.                 // Child not found, create it  
  34.                 child = new UriMatcher();  
  35.                 if (token.equals(“#”)) {  
  36.                     child.mWhich = NUMBER;  
  37.                 } else if (token.equals(“*”)) {  
  38.                     child.mWhich = TEXT;  
  39.                 } else {  
  40.                     child.mWhich = EXACT;  
  41.                 }  
  42.                 child.mText = token;  
  43.                 node.mChildren.add(child);  
  44.                 node = child;  
  45.             }  
  46.         }  
  47.         node.mCode = code;  
  48. }  
public void addURI(String authority, String path, int code) 
{
if (code < 0) {
throw new IllegalArgumentException(“code ” + code + ” is invalid: it must be positive”);
}

    String[] tokens = null;
    if (path != null) {
        String newPath = path;
        // Strip leading slash if present.
        if (path.length() &gt; 0 &amp;&amp; path.charAt(0) == '/') {
            newPath = path.substring(1);
        }
        tokens = PATH_SPLIT_PATTERN.split(newPath);
    }

    int numTokens = tokens != null ? tokens.length : 0;
    UriMatcher node = this;
    for (int i = -1; i &lt; numTokens; i++) {
        String token = i &lt; 0 ? authority : tokens[i];
        ArrayList&lt;UriMatcher&gt; children = node.mChildren;
        int numChildren = children.size();
        UriMatcher child;
        int j;
        for (j = 0; j &lt; numChildren; j++) {
            child = children.get(j);
            if (token.equals(child.mText)) {
                node = child;
                break;
            }
        }
        if (j == numChildren) {
            // Child not found, create it
            child = new UriMatcher();
            if (token.equals("#")) {
                child.mWhich = NUMBER;
            } else if (token.equals("*")) {
                child.mWhich = TEXT;
            } else {
                child.mWhich = EXACT;
            }
            child.mText = token;
            node.mChildren.add(child);
            node = child;
        }
    }
    node.mCode = code;

}
Code为匹配码,每个插入到ArrayList中的UriMatcher我们都可以设置一个匹配码,为之后执行match()方法时能返回。
一个匹配的方法:

  1. public int match(Uri uri){…}  
public int match(Uri uri){…}
我们来分析一下在源码TelephonyProvider中它的使用:
首先,TelephonyProvider创建了一个静态块,用于添加UriMatcher:
  1. private static final UriMatcher s_urlMatcher = new UriMatcher(UriMatcher.NO_MATCH);  
  2. static {  
  3.     s_urlMatcher.addURI(”telephony”“carriers”, URL_TELEPHONY);  
  4.     s_urlMatcher.addURI(”telephony”“carriers/current”, URL_CURRENT);  
  5.     s_urlMatcher.addURI(”telephony”“carriers/#”, URL_ID);  
  6.     s_urlMatcher.addURI(”telephony”“carriers/restore”, URL_RESTOREAPN);  
  7.     s_urlMatcher.addURI(”telephony”“carriers/preferapn”, URL_PREFERAPN);  
  8.     s_urlMatcher.addURI(”telephony”,“carriers/preferapn_no_update”, URL_PREFERAPN_NO_UPDATE);  
  9. s_urlMatcher.addURI(”telephony”“siminfo”, URL_SIMINFO);  
  10. s_urlMatcher.addURI(”telephony”,“carriers/subId/, URL_TELEPHONY_USING_SUBID);  
  11.     s_urlMatcher.addURI(”telephony”“carriers/current/subId/”, URL_CURRENT_USING_SUBID);  
  12.     s_urlMatcher.addURI(”telephony”“carriers/restore/subId/, URL_RESTOREAPN_USING_SUBID);  
  13.     s_urlMatcher.addURI(”telephony”“carriers/preferapn/subId/”, URL_PREFERAPN_USING_SUBID);  
  14.     s_urlMatcher.addURI(”telephony”“carriers/preferapn_no_update/subId/*”,  
  15.                 URL_PREFERAPN_NO_UPDATE_USING_SUBID);  
  16. }  
private static final UriMatcher s_urlMatcher = new UriMatcher(UriMatcher.NO_MATCH); 
static {
s_urlMatcher.addURI("telephony", "carriers", URL_TELEPHONY);
s_urlMatcher.addURI("telephony", "carriers/current", URL_CURRENT);
s_urlMatcher.addURI("telephony", "carriers/#", URL_ID);
s_urlMatcher.addURI("telephony", "carriers/restore", URL_RESTOREAPN);
s_urlMatcher.addURI("telephony", "carriers/preferapn", URL_PREFERAPN);
s_urlMatcher.addURI("telephony","carriers/preferapn_no_update", URL_PREFERAPN_NO_UPDATE);
s_urlMatcher.addURI("telephony", "siminfo", URL_SIMINFO);
s_urlMatcher.addURI("telephony","carriers/subId/*", URL_TELEPHONY_USING_SUBID);
s_urlMatcher.addURI("telephony", "carriers/current/subId/*", URL_CURRENT_USING_SUBID);
s_urlMatcher.addURI("telephony", "carriers/restore/subId/*", URL_RESTOREAPN_USING_SUBID);
s_urlMatcher.addURI("telephony", "carriers/preferapn/subId/*", URL_PREFERAPN_USING_SUBID);
s_urlMatcher.addURI("telephony", "carriers/preferapn_no_update/subId/*",
URL_PREFERAPN_NO_UPDATE_USING_SUBID);
}
这样,在对象s_urlMatcher内部维护了一个ArrayList, TelephonyProvider内容提供者中提供了增删改查的方法,我们来看看其中的一个方法update();
  1. public Cursor query(Uri url, String[] projectionIn, String selection,  
  2.             String[] selectionArgs, String sort) {  
  3. int match = s_urlMatcher.match(url);  
  4. switch (match) {  
  5.             case URL_TELEPHONY_USING_SUBID: {  
  6.                 subIdString = url.getLastPathSegment();  
  7.                 …  
  8.             case URL_TELEPHONY: {  
  9.                 break;  
  10.             }  
  11.   
  12.             case URL_CURRENT_USING_SUBID: {  
  13.                 subIdString = url.getLastPathSegment();  
  14. }  
  15. …  
  16. }  
  17.         SQLiteDatabase db = mOpenHelper.getReadableDatabase();  
  18.         Cursor ret = null;  
  19.         try {  
  20.             ret = qb.query(db, projectionIn, selection, selectionArgs, nullnull, sort);  
  21.         } catch (SQLException e) {  
  22.             loge(”got exception when querying: ” + e);  
  23.         }  
  24.         if (ret != null)  
  25.             ret.setNotificationUri(getContext().getContentResolver(), url);  
  26.         return ret;  
  27. }  
public Cursor query(Uri url, String[] projectionIn, String selection, 
String[] selectionArgs, String sort) {
int match = s_urlMatcher.match(url);
switch (match) {
case URL_TELEPHONY_USING_SUBID: {
subIdString = url.getLastPathSegment();

case URL_TELEPHONY: {
break;
}

        case URL_CURRENT_USING_SUBID: {
            subIdString = url.getLastPathSegment();

}

}
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor ret = null;
try {
ret = qb.query(db, projectionIn, selection, selectionArgs, null, null, sort);
} catch (SQLException e) {
loge(“got exception when querying: ” + e);
}
if (ret != null)
ret.setNotificationUri(getContext().getContentResolver(), url);
return ret;
}
可以看到,如果我们需要查询这个数据库中的数据时,传过来的uri需要跟s_urlMatcher内部的ArrayList进行匹配查找,如果存在此uri,则从数据库中查询并返回相应的数据,如果不存在此uri,那么将得不到任何数据。因此,当我们使用TelephonyProvider查询数据库时,并不是你提供什么uri,就给你返回什么数据。


3.ContentUris
ContentUris中的源码较少,它的主要实现都是在Uri.Builder中,如下:

  1. public static long parseId(Uri contentUri) {  
  2.         String last = contentUri.getLastPathSegment();  
  3.         return last == null ? -1 : Long.parseLong(last);  
  4.     }  
  5.     public static Uri.Builder appendId(Uri.Builder builder, long id) {  
  6.         return builder.appendEncodedPath(String.valueOf(id));  
  7.     }  
  8.     public static Uri withAppendedId(Uri contentUri, long id) {  
  9.         return appendId(contentUri.buildUpon(), id).build();  
  10. }    
public static long parseId(Uri contentUri) { 
String last = contentUri.getLastPathSegment();
return last == null ? -1 : Long.parseLong(last);
}
public static Uri.Builder appendId(Uri.Builder builder, long id) {
return builder.appendEncodedPath(String.valueOf(id));
}
public static Uri withAppendedId(Uri contentUri, long id) {
return appendId(contentUri.buildUpon(), id).build();
}
用法如下:
withAppendedId(uri, id)用于为路径加上ID部分:
Uri uri = Uri.parse(“content://com.xxx.provider.myprovider/person”);
Uri resultUri = ContentUris.withAppendedId(uri, 10);
//生成后的Uri为:content://com.xxx.provider.myprovider/person/10
parseId(uri)方法用于从路径中获取ID部分:
Uri uri = Uri.parse(“content://com.xxx.provider.myprovider/person/10”)
long personid = ContentUris.parseId(uri);//获取的结果为:10


=============================================分割线======================================================

Uri的总结也就这些,最后,记录一下常用的几个Uri:

显示网页:
  1. Uri uri = Uri.parse(“http://www.google.com”);
  2. Intent it = new Intent(Intent.ACTION_VIEW,uri);
  3. startActivity(it);

显示地图:
1. Uri uri = Uri.parse(“geo:38.899533,-77.036476”);
  2. Intent it = new Intent(Intent.Action_VIEW,uri);
  3. startActivity(it);

路径规划:
  1. Uri uri = Uri.parse(“http://maps.google.com/maps?f=d&saddr=startLat%20startLng&daddr=endLat%20endLng&hl=en”);
  2. Intent it = new Intent(Intent.ACTION_VIEW,URI);
  3. startActivity(it);

拨打电话:
调用拨号程序
  1. Uri uri = Uri.parse(“tel:xxxxxx”);
  2. Intent it = new Intent(Intent.ACTION_DIAL, uri);  
  3. startActivity(it);  
  1. Uri uri = Uri.parse(“tel.xxxxxx”);
  2. Intent it =new Intent(Intent.ACTION_CALL,uri);
  3. 要使用这个必须在配置文件中加入<uses-permission id=”Android.permission.CALL_PHONE” />

发送SMS/MMS
调用发送短信的程序
  1. Intent it = new Intent(Intent.ACTION_VIEW);
  2. it.putExtra(“sms_body”, “The SMS text”);
  3. it.setType(“vnd.android-dir/mms-sms”);
  4. startActivity(it);  
发送短信
  1. Uri uri = Uri.parse(“smsto:0800000123”);
  2. Intent it = new Intent(Intent.ACTION_SENDTO, uri);
  3. it.putExtra(“sms_body”, “The SMS text”);
  4. startActivity(it);  
发送彩信
  1. Uri uri = Uri.parse(“content://media/external/images/media/23”);
  2. Intent it = new Intent(Intent.ACTION_SEND);
  3. it.putExtra(“sms_body”, “some text”);
  4. it.putExtra(Intent.EXTRA_STREAM, uri);
  5. it.setType(“image/png”);
  6. startActivity(it);

发送Email
  1.
  2. Uri uri = Uri.parse(“mailto:xxx@abc.com”);
  3. Intent it = new Intent(Intent.ACTION_SENDTO, uri);
  4. startActivity(it);
  1. Intent it = new Intent(Intent.ACTION_SEND);
  2. it.putExtra(Intent.EXTRA_EMAIL, “me@abc.com”);
  3. it.putExtra(Intent.EXTRA_TEXT, “The email body text”);
  4. it.setType(“text/plain”);
  5. startActivity(Intent.createChooser(it, “Choose Email Client”));  
  1. Intent it=new Intent(Intent.ACTION_SEND);  
  2. String[] tos={“me@abc.com”};  
  3. String[] ccs={“you@abc.com”};  
  4. it.putExtra(Intent.EXTRA_EMAIL, tos);  
  5. it.putExtra(Intent.EXTRA_CC, ccs);  
  6. it.putExtra(Intent.EXTRA_TEXT, “The email body text”);  
  7. it.putExtra(Intent.EXTRA_SUBJECT, “The email subject text”);  
  8. it.setType(“message/rfc822”);  
  9. startActivity(Intent.createChooser(it, “Choose Email Client”));

添加附件
  1. Intent it = new Intent(Intent.ACTION_SEND);
  2. it.putExtra(Intent.EXTRA_SUBJECT, “The email subject text”);
  3. it.putExtra(Intent.EXTRA_STREAM, “[url=]file:///sdcard/mysong.mp3[/url]”);
  4. sendIntent.setType(“audio/mp3”);
  5. startActivity(Intent.createChooser(it, “Choose Email Client”));

播放多媒体
  1.  
  2. Intent it = new Intent(Intent.ACTION_VIEW);
  3. Uri uri = Uri.parse(“[url=]file:///sdcard/song.mp3[/url]”);
  4. it.setDataAndType(uri, “audio/mp3”);
  5. startActivity(it);
  1. Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, “1”);
  2. Intent it = new Intent(Intent.ACTION_VIEW, uri);
  3. startActivity(it);  

Uninstall 程序
  1. Uri uri = Uri.fromParts(“package”, strPackageName, null);
  2. Intent it = new Intent(Intent.ACTION_DELETE, uri);
  3. startActivity(it);

//调用相册
public static final String MIME_TYPE_IMAGE_JPEG = “image/*”;
public static final int ACTIVITY_GET_IMAGE = 0;
Intent getImage = new Intent(Intent.ACTION_GET_CONTENT);
getImage.addCategory(Intent.CATEGORY_OPENABLE);
getImage.setType(MIME_TYPE_IMAGE_JPEG);
startActivityForResult(getImage, ACTIVITY_GET_IMAGE);

//调用系统相机应用程序,并存储拍下来的照片
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
time = Calendar.getInstance().getTimeInMillis();
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment
.getExternalStorageDirectory().getAbsolutePath()+”/tucue”, time + “.jpg”)));
startActivityForResult(intent, ACTIVITY_GET_CAMERA_IMAGE);

uninstall apk
/**未测试
Uri uninstallUri = Uri.fromParts(“package”, “xxx”, null);
returnIt = new Intent(Intent.ACTION_DELETE, uninstallUri);
*/
Uri packageURI = Uri.parse(“package:”+wistatmap);  
Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);  
startActivity(uninstallIntent);

install apk
Uri installUri = Uri.fromParts(“package”, “xxx”, null);
returnIt = new Intent(Intent.ACTION_PACKAGE_ADDED, installUri);
play audio
Uri playUri = Uri.parse(“[url=]file:///sdcard/download/everything.mp3[/url]”);
returnIt = new Intent(Intent.ACTION_VIEW, playUri);

//发送附件
Intent it = new Intent(Intent.ACTION_SEND);  
it.putExtra(Intent.EXTRA_SUBJECT, “The email subject text”);  
it.putExtra(Intent.EXTRA_STREAM, “[url=]file:///sdcard/eoe.mp3[/url]”);  
sendIntent.setType(“audio/mp3”);  
startActivity(Intent.createChooser(it, “Choose Email Client”));

//搜索应用
Uri uri = Uri.parse(“market://search?q=pname:pkg_name”);  
Intent it = new Intent(Intent.ACTION_VIEW, uri);  
startActivity(it);  
//where pkg_name is the full package path for an application

//进入联系人页面
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(People.CONTENT_URI);
startActivity(intent);

//查看指定联系人
Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI, info.id);//info.id联系人ID
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(personUri);
startActivity(intent);


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值