一.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.等等……….
以上的资源例子如下:
- 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|/
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中配置:
- package=“com.android.providers.telephony”
- <provider android:name=“TelephonyProvider”
- android:authorities=“telephony”
- android:exported=“true”
- android:singleUser=“true”
- 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的主要方法:
- public static Uri withAppendedPath(Uri baseUri, String pathSegment)
- public boolean isPathPrefixMatch(Uri prefix)
- 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和ContentUris2.UriMatcher.java
构造方法:
- private ArrayList<UriMatcher> mChildren;
- public UriMatcher(int code)
- {
- mCode = code;
- mWhich = -1;
- mChildren = new ArrayList<UriMatcher>();
- mText = null;
- }
private ArrayList<UriMatcher> mChildren;
public UriMatcher(int code)
{
mCode = code;
mWhich = -1;
mChildren = new ArrayList<UriMatcher>();
mText = null;
}
UriMatcher维护了一个ArrayList用于保存所有加进来的UriMatcher对象。执行添加操作的方法如下:
- 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() > 0 && 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 < numTokens; i++) {
- String token = i < 0 ? authority : tokens[i];
- ArrayList<UriMatcher> children = node.mChildren;
- int numChildren = children.size();
- UriMatcher child;
- int j;
- for (j = 0; j < 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;
- }
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() > 0 && 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 < numTokens; i++) {
String token = i < 0 ? authority : tokens[i];
ArrayList<UriMatcher> children = node.mChildren;
int numChildren = children.size();
UriMatcher child;
int j;
for (j = 0; j < 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()方法时能返回。
一个匹配的方法:
- public int match(Uri uri){…}
public int match(Uri uri){…}
我们来分析一下在源码TelephonyProvider中它的使用:首先,TelephonyProvider创建了一个静态块,用于添加UriMatcher:
- 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);
- }
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();
- 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;
- }
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中,如下:
- 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();
- }
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);