android 中的Uri

文章出处:http://blog.csdn.net/shift_wwx/article/details/47663373

请转载的朋友标明出处~~

前言:关于Uri网上相关的例子还是很多的,但是结合source code来讲解的很少,个人还是习惯性根据source code 总结一下。

总结版本基于4.4

一、source code(frameworks/base/core/java/android/net/Uri.java)

public abstract class Uri implements Parcelable, Comparable<Uri> {

    private Uri() {}

    public abstract boolean isHierarchical();

    public boolean isOpaque() {
        return !isHierarchical();
    }

    public abstract boolean isRelative();

    public boolean isAbsolute() {
        return !isRelative();
    }

    public abstract String getScheme();

    public abstract String getSchemeSpecificPart();

    public abstract String getEncodedSchemeSpecificPart();

    public abstract String getAuthority();

    public abstract String getEncodedAuthority();

    public abstract String getUserInfo();

    public abstract String getEncodedUserInfo();

    public abstract String getHost();

    public abstract int getPort();

    public abstract String getPath();

    public abstract String getEncodedPath();

    public abstract String getQuery();

    public abstract String getEncodedQuery();

    public abstract String getFragment();

    public abstract String getEncodedFragment();

    public abstract List<String> getPathSegments();

    public abstract String getLastPathSegment();

    public boolean equals(Object o) {
        if (!(o instanceof Uri)) {
            return false;
        }

        Uri other = (Uri) o;

        return toString().equals(other.toString());
    }

    public int hashCode() {
        return toString().hashCode();
    }

    public int compareTo(Uri other) {
        return toString().compareTo(other.toString());
    }

    public abstract String toString();

    public String toSafeString() {
        String scheme = getScheme();
        String ssp = getSchemeSpecificPart();
        if (scheme != null) {
            if (scheme.equalsIgnoreCase("tel") || scheme.equalsIgnoreCase("sip")
                    || scheme.equalsIgnoreCase("sms") || scheme.equalsIgnoreCase("smsto")
                    || scheme.equalsIgnoreCase("mailto")) {
                StringBuilder builder = new StringBuilder(64);
                builder.append(scheme);
                builder.append(':');
                if (ssp != null) {
                    for (int i=0; i<ssp.length(); i++) {
                        char c = ssp.charAt(i);
                        if (c == '-' || c == '@' || c == '.') {
                            builder.append(c);
                        } else {
                            builder.append('x');
                        }
                    }
                }
                return builder.toString();
            }
        }
        // Not a sensitive scheme, but let's still be conservative about
        // the data we include -- only the ssp, not the query params or
        // fragment, because those can often have sensitive info.
        StringBuilder builder = new StringBuilder(64);
        if (scheme != null) {
            builder.append(scheme);
            builder.append(':');
        }
        if (ssp != null) {
            builder.append(ssp);
        }
        return builder.toString();
    }

    public abstract Builder buildUpon();

    /** Index of a component which was not found. */
    private final static int NOT_FOUND = -1;

    /** Placeholder value for an index which hasn't been calculated yet. */
    private final static int NOT_CALCULATED = -2;

    private static final String NOT_HIERARCHICAL
            = "This isn't a hierarchical URI.";

    /** Default encoding. */
    private static final String DEFAULT_ENCODING = "UTF-8";

    /**
     * Creates a Uri which parses the given encoded URI string.
     *
     * @param uriString an RFC 2396-compliant, encoded URI
     * @throws NullPointerException if uriString is null
     * @return Uri for this given uri string
     */
    public static Uri parse(String uriString) {
        return new StringUri(uriString);
    }

    /**
     * Creates a Uri from a file. The URI has the form
     * "file://<absolute path>". Encodes path characters with the exception of
     * '/'.
     *
     * <p>Example: "file:///tmp/android.txt"
     *
     * @throws NullPointerException if file is null
     * @return a Uri for the given file
     */
    public static Uri fromFile(File file) {
        if (file == null) {
            throw new NullPointerException("file");
        }

        PathPart path = PathPart.fromDecoded(file.getAbsolutePath());
        return new HierarchicalUri(
                "file", Part.EMPTY, path, Part.NULL, Part.NULL);
    }
    
    ......
    
}

1、什么是Uri

Uri就是Android系统为了特殊需要,而制定的一种拥有特殊格式的一种数据模式。

从注释看:

The "four main components" of a hierarchical URI consist of
    <scheme>://<authority><path>?<query>

就是说hierarchical 格式的Uri分为四部分:

1)scheme:访问资源的命名机制,通过这个可以获悉Uri 的具体资源存在形式,如http、content、file、market等

2)authority:存放资源的主机名,例如Provider 里面会对资源进行操作、存放,这个时候Provider就需要指出authority。

对于Provider 具体可以看一下:《Android基础总结之八:ContentProvider详解

authority 应该是scheme:// 之后到第一次出现 ‘/’ 或‘?’ 或‘#’之间的string

3)path:authority之后第一个 ‘/’ 开始到 ‘?’ 或 ‘#’ 之前的string(包含’/’)

4)query:’?’ 号之后 ‘#’ 号之前的string

经常看到的Uri形式有:

#打开一个网页
http://blog.3gstdy.com/
#打开地图并定位到一个点
geo:52.76,-79.0342
#拨打电话
tel:10086
#播放音频文件
file:///sdcard/download/everything.mp3
#打开发邮件界面
mailto:admin@3gstdy.com
#寻找某个应用
market://search?q=pname:pkg_name
#路径规划
http://maps.google .com/maps?f=d&saddr=startLat%20startLng&daddr=endLat%20endLng&hl=en

2、getScheme、getSchemeSpecificPart、getEncodedSchemeSpecificPart

1)getScheme:返回scheme,如果Uri是相对路径,那么就返回null

2)getSchemeSpecificPart :这里出现了ssp 概念,从这里可以将Uri 重新格式化为:

[scheme:]schemeSpecificPart[#fragment]  ([...]表示可选) 

如果是个相对路径的话,就返回整个。

3)getEncodedSchemeSpecificPart:如果ssp里面有出现非A~Z、a~z、0~9、‘_’、‘-’、‘叹号’、‘点号’、‘~’、‘单引号’、‘(’、‘)’、‘星号’,都需要encode一把,有时候会看到%连接的一串,那都是encode。

详细的可以看一下source code:

for (int i = 0; i < bytesLength; i++) {
    encoded.append('%');
    encoded.append(HEX_DIGITS[(bytes[i] & 0xf0) >> 4]);
    encoded.append(HEX_DIGITS[bytes[i] & 0xf]);
}

后面相关encode都是这样的,具体实现情况看函数:

String encode(String s, String allow)

3、isRelative、isAbsolute

isRelative:就是没有明确的scheme

isAbsolute:非isRelative

    public boolean isAbsolute() {
        return !isRelative();
    }

4、分层、不透明

   /**
     * Returns true if this URI is hierarchical like "http://google.com".
     * Absolute URIs are hierarchical if the scheme-specific part starts with
     * a '/'. Relative URIs are always hierarchical.
     */
    public abstract boolean isHierarchical();

    /**
     * Returns true if this URI is opaque like "mailto:nobody@google.com". The
     * scheme-specific part of an opaque URI cannot start with a '/'.
     */
    public boolean isOpaque() {
        return !isHierarchical();
    }

不透明也就是不分层。

通过注释可以大概理解两api 的意义:

如果ssp开头是 ‘/’,那么就是hierarchical,如果不是就是opaque。

当然,通过source code也能够确定的:

public boolean isHierarchical() {
    int ssi = findSchemeSeparator();

    if (ssi == NOT_FOUND) {
        // All relative URIs are hierarchical.
        return true;
    }

    if (uriString.length() == ssi + 1) {
        // No ssp.
        return false;
    }

    // If the ssp starts with a '/', this is hierarchical.
    return uriString.charAt(ssi + 1) == '/';
}

5、getHost()、getPort()

1)getHost:authority 中 ‘@’ 之后到 ‘:’ 之前的string

2)getPort:authority 中 ‘:’ 之后的 integer

6、Uri是个abstract类,好多函数是abstract的,肯定是有地方实现的。

那么Uri是abstract类,并不能实例化,应用的时候是怎么使用这些method,提供了两种方法:

    public static Uri parse(String uriString) {
        return new StringUri(uriString);
    }
    public static Uri fromFile(File file) {
        if (file == null) {
            throw new NullPointerException("file");
        }

        PathPart path = PathPart.fromDecoded(file.getAbsolutePath());
        return new HierarchicalUri(
                "file", Part.EMPTY, path, Part.NULL, Part.NULL);
    }

显然是在这里new 出来了,返回的类型都是Uri,可以确定StringUri 和 HierarchicalUri都是Uri的子类了。

总结:

根据之前的解释可以清楚知道Uri 的格式:

scheme:ssp#fragment

1)scheme 就是第一个 ‘:’ 之前的部分,没有的就返回null

2)ssp:authority + path + query

当然其中的部分可能不存在,反正ssp就是这三部分的统称

ssp 语法:[//aurhority][path][?query]

authority 也可能包含了userinfo + host  + port

authority语法:[userinfo@]host[:port]

3)fragment:第一次出现 ‘#’ 之后的string

    原文作者:私房菜
    原文地址: https://blog.csdn.net/shift_wwx/article/details/47663373
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞