36.Android 自定义ContentProvider

36.Android 自定义ContentProviderContentProvider 介绍

有一种情景:假如A应用存储的数据,B也用到。那么,要怎么共享数据呢?

其实有很多种解决办法,比如存在SD卡上、网络等等。

其实Android上的相册、联系人也都是Google给Android系统写的App。也提供了对应的一套API给我们调用到其相应的数据,这就是ContentProvider。

ContentProvider是获取数据和存储都用的是统一的封装接口,涉及到Uri的概念。

当然了,如果用到Uri了,我们可以使用Google提供的工具类 UriMatcher 和 ContentUris ,以下会讲到这些。

ContentProvider 优点

可以获取系统原生一些App的数据。

不同App之间可以共享数据。

对数据进行封装,存储和获取提供统一的API。

Android 自带的ContentProvider

如果想获取一些系统自带App的数据,可以参考: android.provider 包下的ContentProvider。

ContentProvider Uri 结构

content://com.camnter.content.provider/message/6

content:// :Scheme

com.camnter.content.provider :Authority(主机名),这个ContentProvider的唯一标识。

message :Table(表名)

6 :Id

几个例子: content://com.camnter.content.provider/message:表示操作message表的所有记录。

content://com.camnter.content.provider/message/6:表示操作message表的Id = 6的记录。

content://com.camnter.content.provider/message/6/content:表示操作message表的Id = 6的记录的content字段。

Google Uri 工具类

UriMatcher :

public void addURI(String authority, String path, int code):添加Uri,Uri会被添加到一个ArrayList里,提供match(Uri uri)去匹配。

public int match(Uri uri):根据Uri匹配改Uri是否被添加。

ContentUris:

public static long parseId(Uri contentUri):解析Uri取得Id。

public static Uri.Builder appendId(Uri.Builder builder, long id):添加Id。

public static Uri withAppendedId(Uri contentUri, long id):添加Id。

UriMatcher 解析

ContentUris的源码特别简单,整个类就调用了Uri类的两个方法 T T# 。

所以就看看UriMatcher源码吧。

由于对其他类的依赖不多,我就自定义了一份UriMatcher。

import android.net.Uri;import java.util.ArrayList;import java.util.List;/**Utility class to aid in matching URIs in content providers.<p>To use this class, build up a tree of <code>UriMatcher</code> objects.For example:<pre>private static final int PEOPLE = 1;private static final int PEOPLE_ID = 2;private static final int PEOPLE_PHONES = 3;private static final int PEOPLE_PHONES_ID = 4;private static final int PEOPLE_CONTACTMETHODS = 7;private static final int PEOPLE_CONTACTMETHODS_ID = 8;private static final int DELETED_PEOPLE = 20;private static final int PHONES = 9;private static final int PHONES_ID = 10;private static final int PHONES_FILTER = 14;private static final int CONTACTMETHODS = 18;private static final int CONTACTMETHODS_ID = 19;private static final int CALLS = 11;private static final int CALLS_ID = 12;private static final int CALLS_FILTER = 15;private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);static{sURIMatcher.addURI(“contacts”, “people”, PEOPLE);sURIMatcher.addURI(“contacts”, “people/#”, PEOPLE_ID);sURIMatcher.addURI(“contacts”, “people/#/phones”, PEOPLE_PHONES);sURIMatcher.addURI(“contacts”, “people/#/phones/#”, PEOPLE_PHONES_ID);sURIMatcher.addURI(“contacts”, “people/#/contact_methods”, PEOPLE_CONTACTMETHODS);sURIMatcher.addURI(“contacts”, “people/#/contact_methods/#”, PEOPLE_CONTACTMETHODS_ID);sURIMatcher.addURI(“contacts”, “deleted_people”, DELETED_PEOPLE);sURIMatcher.addURI(“contacts”, “phones”, PHONES);sURIMatcher.addURI(“contacts”, “phones/filter/*”, PHONES_FILTER);sURIMatcher.addURI(“contacts”, “phones/#”, PHONES_ID);sURIMatcher.addURI(“contacts”, “contact_methods”, CONTACTMETHODS);sURIMatcher.addURI(“contacts”, “contact_methods/#”, CONTACTMETHODS_ID);sURIMatcher.addURI(“call_log”, “calls”, CALLS);sURIMatcher.addURI(“call_log”, “calls/filter/*”, CALLS_FILTER);sURIMatcher.addURI(“call_log”, “calls/#”, CALLS_ID);}</pre><p>Starting from API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, paths can start with a leading slash. For example:<pre>sURIMatcher.addURI(“contacts”, “/people”, PEOPLE);</pre><p>Then when you need to match against a URI, call {@link #match}, providingthe URL that you have been given. You can use the result to build a query,return a type, insert or delete a row, or whatever you need, without duplicatingall of the if-else logic that you would otherwise need. For example:<pre>public String getType(Uri url){int match = sURIMatcher.match(url);switch (match){case PEOPLE:return “vnd.android.cursor.dir/person”;case PEOPLE_ID:return “vnd.android.cursor.item/person”;… snip …return “vnd.android.cursor.dir/snail-mail”;case PEOPLE_ADDRESS_ID:return “vnd.android.cursor.item/snail-mail”;default:return null;}}</pre>instead of:<pre>public String getType(Uri url){List<String> pathSegments = url.getPathSegments();if (pathSegments.size() >= 2) {if (“people”.equals(pathSegments.get(1))) {if (pathSegments.size() == 2) {return “vnd.android.cursor.dir/person”;} else if (pathSegments.size() == 3) {return “vnd.android.cursor.item/person”;… snip …return “vnd.android.cursor.dir/snail-mail”;} else if (pathSegments.size() == 3) {return “vnd.android.cursor.item/snail-mail”;}}}return null;}</pre>*/public class UriMatcher{public static final int NO_MATCH = -1;/*** Creates the root node of the URI tree.* 创建Uri树的根节点** @param code the code to match for the root URI*/public UriMatcher(int code){mCode = code;mWhich = -1;mChildren = new ArrayList<UriMatcher>();mText = null;}private UriMatcher(){mCode = NO_MATCH;mWhich = -1;mChildren = new ArrayList<UriMatcher>();mText = null;}/*** Add a URI to match, and the code to return when this URI is* matched. URI nodes may be exact match string, the token “*”* that matches any text, or the token “#” that matches only* numbers.* 添加一个URI匹配,并且这里添加code值会在这个URI匹配成功的时候返回。URI节点可能精确匹配字符串,* token为“*”的时候会匹配为text,token为“#”的时候只会匹配为数字* <p>* Starting from API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},* this method will accept a leading slash in the path.** @param authority the authority to match*ContentProvider的authority** @param path the path to match. * may be used as a wild card for* any text, and # may be used as a wild card for numbers.*匹配路径,*可能是作为一个通配符用于任何文本,和#可能用作通配符数字。** @param code the code that is returned when a URI is matched* against the given components. Must be positive.*该URI匹配成功时返回的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 = newPath.split(“/”);}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 itchild = 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;}/*** Try to match against the path in a url.* 尝试匹配一个url的路径。** @param uriThe url whose path we will match against.*将匹配的url路径。** @return The code for the matched node (added using addURI),* or -1 if there is no matched node.*匹配节点设置的code(在使用addURI时,给对应URI设置code),*或者没有匹配节点,则反悔-1。*/public int match(Uri uri){final List<String> pathSegments = uri.getPathSegments();final int li = pathSegments.size();UriMatcher node = this;if (li == 0 && uri.getAuthority() == null) {return this.mCode;}for (int i=-1; i<li; i++) {String u = i < 0 ? uri.getAuthority() : pathSegments.get(i);ArrayList<UriMatcher> list = node.mChildren;if (list == null) {break;}node = null;int lj = list.size();for (int j=0; j<lj; j++) {UriMatcher n = list.get(j);which_switch:switch (n.mWhich) {case EXACT:if (n.mText.equals(u)) {node = n;}break;case NUMBER:int lk = u.length();for (int k=0; k<lk; k++) {char c = u.charAt(k);if (c < ‘0’ || c > ‘9’) {break which_switch;}}node = n;break;case TEXT:node = n;break;}if (node != null) {break;}}if (node == null) {return NO_MATCH;}}return node.mCode;}private static final int EXACT = 0;private static final int NUMBER = 1;private static final int TEXT = 2;private int mCode;private int mWhich;private String mText;private ArrayList<UriMatcher> mChildren;}

以上注释还有使用,Google告诉我们怎么使用UriMatcher的范例代码。

自定义 ContentProvider

代码都重复看过,都写上了注释。

没有了爱的语言,所有的文字都是乏味的

36.Android 自定义ContentProvider

相关文章:

你感兴趣的文章:

标签云: