Android 中的 Uri 如何使用呢 ?

问题

Android 中常用的 uri 如何使用呢 ?(此篇分析基础为Android 7.1.1系统源码),参看Android官方说明:https://developer.android.com/reference/android/net/Uri,代码可在此查看:https://github.com/LineageOS/android_frameworks_base/blob/lineage-20.0/core/java/android/net/Uri.java

1 概述

通用资源标志符 URI (Universal Resource Identifier),URI 在 java.net.URI 中定义,显然是 Java 提供的一个类。而 Uri 位置在 android.net.Uri 中定义(Android 源码内位置:frameworks/base/core/java/android/net/Uri.java),是特有针对 Android 系统定义的类。Uri 代表要操作的数据,Android 上可用的每种资源(图像、视频片段、网页等)都可以用 Uri 来表示。

Uri 的组成部分:

  • 访问资源的命名机制(scheme)
  • 存放资源的主机名(authority)
  • 资源自身的名称,由路径表示(path)

Uri 的结构:

# 基本形式
[scheme:]scheme-specific-part[#fragment]
# 第二形式
[scheme:][//authority][path][?query][#fragment]
# 第三形式
[scheme:][//host:port][path][?query][#fragment]

特别针对scheme说明下,Uri中有这么几种常用标识:

  • content : 主要操作的是ContentProvider,它代表的是数据库中的某个资源
  • http : 某网站资源
  • file : 本地机器上的资源
  • git : git仓库中的资源
  • ftp : ftp服务器上的资源

2 Uri 的结构

2.1 基本形式

# 基本形式
[scheme:]scheme-specific-part[#fragment]

2.2 第二形式

# 第二形式
[scheme:][//authority][path][?query][#fragment]

注意其中规则:

  1. path 可以有多个,每个用 / 连接,比如:```
    scheme://authority/path1/path2/path3?query#fragment

  2. query 参数可以带有对应的值,也可以不带,如果带对应的值用 = 表示,如:```
    //这里有一个参数id,它的值是1
    scheme://authority/path1/path2/path3?id=1#fragment

  3. query 参数可以有多个,每个用 & 连接,如:```
    /*
    这里有3个参数:
    参数1:id,其值是:1
    参数2:name,其值是:pedro
    参数3:old,没有对它赋值,所以它的值是null
    */
    scheme://authority/path1/path2/path3?id = 1&name=pedro&old#fragment

在android中,除了scheme、authority是必须要有的,其它的几个path、query、fragment,它们每一个可以选择性的要或不要,但顺序不能变

2.3 第三形式

第二形式中 authority 又可以分为 host:port 的形式,这是划分最细的形式:

# 第三形式
[scheme:][//host:port][path][?query][#fragment]

2.4 例子

可以通过这个例子检测下学习效果:

http://www.pedro11.com:8080/yourpath/fileName.html?stove=10&path=32&id=4#harvic

3 Uri 的UML类图

我把 Android 源码中 frameworks/base/core/java/android/net/Uri.java (也可在此查看:https://github.com/LineageOS/android_frameworks_base/blob/lineage-20.0/core/java/android/net/Uri.java)导入到 IDEA 工程中,通过 IDEA 的 Diagram 工具生成了它的 UML 类图(注意其中紫色方法为抽象方法),更方便分析这个有意思的类(在Uri.java中可以看出它有很多内部类,而且内部类又继承了Uri类本身)。\

类图中各个小图标的含义可查看这里:https://jetbrains.design/intellij/resources/icons_list/

4 从 Uri 中提取 String

  • getScheme() : 获取Uri中的scheme字符串部分,即 http
  • getSchemeSpecificPart() : 获取Uri中的scheme-specific-part:部分,即 //www.pedro11.com:8080/yourpath/fileName.html
  • getFragment() : 获取Uri中的Fragment部分,即 harvic
  • getAuthority() : 获取Uri中Authority部分,即 www.pedro11.com:8080
  • getPath() : 获取Uri中path部分,即 /yourpath/fileName.html
  • getQuery() : 获取Uri中的query部分,即 stove=10&path=32&id=4
  • getHost() : 获取Authority中的Host字符串,即 www.pedro11.com
  • getPost() : 获取Authority中的Port字符串,即 8080
  • getPathSegments() : 依次提取出Path的各个部分的字符串,存入List< String>
  • getQueryParameter(String key) : 通过传进去query中某个Key的字符串,返回它对应的值
String mUriStr = "http://www.pedro11.com:8080/yourpath/fileName.html?stove=10&path=32&id=4#harvic";
Uri mUri = Uri.parse(mUriStr);
List<String> pathSegList = mUri.getPathSegments();
for (String pathItem:pathSegList){
    Log.d("qijian","pathSegItem:"+pathItem);
}

Log.d(tag,"getQueryParameter(\"stove\"):"+mUri.getQueryParameter("stove"));
Log.d(tag,"getQueryParameter(\"id\"):"+mUri.getQueryParameter("id"));

6 Uri操作工具类

6.1 ContentUris 处理 Uri

ContentUris 有两个作用:

  • 为路径加上ID
  • 从Uri路径中获取ID
  1. 为Uri路径加上ID: withAppendedId(uri, id)```
    //比如有这样一个Uri
    Uri uri = Uri.parse("content://com.example.yy/book");

    //通过ContentUris的withAppendedId()方法,为该Uri加上ID
    Uri resultUri = ContentUris.withAppendedId(uri, 10);

    //最后resultUri为:
    //content://com.example.yy/book/10

  2. 从Uri路径中获取ID—parseId(uri)```
    Uri uri = Uri.parse("content://com.example.yy/book/10")
    long bookId= ContentUris.parseId(uri);

6.2 UriMatcher 处理 Uri

待添加

6.3 uri与file、path相互转化

  1. uri 转 file```
    file = new File(new URI(uri.toString()));

  2. file 转 uri```
    URI uri = file.toURI();

  3. uri 转 path```
    private String getPath(Context context, Uri uri) {
    String path = null;
    Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
    if (cursor == null) {
    return null;
    }
    if (cursor.moveToFirst()) {
    try {
    path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    cursor.close();
    return path;
    }

  4. path 转 uri```
    Uri uri = Uri.parse(path);

  5. file 转 path```
    String path = file.getPath();

  6. path 转 file```
    File file = new File(path);

8 常用Uri

//显示网页: 
    Uri uri = Uri.parse("http://www.google.com"); 
    Intent it = new Intent(Intent.ACTION_VIEW,uri); 
    startActivity(it); 
 
//显示地图: 
    Uri uri = Uri.parse("geo:38.899533,-77.036476"); 
    Intent it = new Intent(Intent.Action_VIEW,uri); 
    startActivity(it); 
 
//路径规划: 
    Uri uri = Uri.parse("http://maps.google.com/maps?f=d&saddr=startLat%20startLng&daddr=endLat%20endLng&hl=en"); 
    Intent it = new Intent(Intent.ACTION_VIEW,URI); 
    startActivity(it); 
 
//调用拨号程序,要使用这个必须在配置文件中加入<uses-permission id="Android.permission.CALL_PHONE" /> 
    Uri uri = Uri.parse("tel:xxxxxx"); 
    Intent it = new Intent(Intent.ACTION_DIAL, uri);   
    startActivity(it);

    Uri uri = Uri.parse("tel.xxxxxx"); 
    Intent it =new Intent(Intent.ACTION_CALL,uri); 
 
//调用发送短信的程序 
    Intent it = new Intent(Intent.ACTION_VIEW); 
    it.putExtra("sms_body", "The SMS text"); 
    it.setType("vnd.android-dir/mms-sms"); 
    startActivity(it);

//发送短信 
    Uri uri = Uri.parse("smsto:0800000123"); 
    Intent it = new Intent(Intent.ACTION_SENDTO, uri); 
    it.putExtra("sms_body", "The SMS text"); 
    startActivity(it);   

//发送彩信 
    Uri uri = Uri.parse("content://media/external/images/media/23"); 
    Intent it = new Intent(Intent.ACTION_SEND); 
    it.putExtra("sms_body", "some text"); 
    it.putExtra(Intent.EXTRA_STREAM, uri); 
    it.setType("image/png"); 
    startActivity(it); 
 
//发送Email 
    Uri uri = Uri.parse("mailto:xxx@abc.com"); 
    Intent it = new Intent(Intent.ACTION_SENDTO, uri); 
    startActivity(it); 
  
    Intent it = new Intent(Intent.ACTION_SEND); 
    it.putExtra(Intent.EXTRA_EMAIL, "me@abc.com"); 
    it.putExtra(Intent.EXTRA_TEXT, "The email body text"); 
    it.setType("text/plain"); 
    startActivity(Intent.createChooser(it, "Choose Email Client"));
  
    Intent it=new Intent(Intent.ACTION_SEND);   
    String[] tos={"me@abc.com"};   
    String[] ccs={"you@abc.com"};   
    it.putExtra(Intent.EXTRA_EMAIL, tos);   
    it.putExtra(Intent.EXTRA_CC, ccs);   
    it.putExtra(Intent.EXTRA_TEXT, "The email body text");   
    it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");   
    it.setType("message/rfc822");   
    startActivity(Intent.createChooser(it, "Choose Email Client")); 
 
//添加附件 
    Intent it = new Intent(Intent.ACTION_SEND);
    it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
    it.putExtra(Intent.EXTRA_STREAM, "[url=]file:///sdcard/mysong.mp3[/url]");
    sendIntent.setType("audio/mp3");
    startActivity(Intent.createChooser(it, "Choose Email Client"));
 
//播放多媒体 
    Intent it = new Intent(Intent.ACTION_VIEW); 
    Uri uri = Uri.parse("[url=]file:///sdcard/song.mp3[/url]"); 
    it.setDataAndType(uri, "audio/mp3"); 
    startActivity(it); 
  
    Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1"); 
    Intent it = new Intent(Intent.ACTION_VIEW, uri); 
    startActivity(it);   
 
//Uninstall APP
    Uri uri = Uri.fromParts("package", strPackageName, null); 
    Intent it = new Intent(Intent.ACTION_DELETE, uri); 
    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); 
 
//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);   
 
//进入联系人页面 
    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); 

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容