博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android进程间通信之ContentProvider
阅读量:4180 次
发布时间:2019-05-26

本文共 9201 字,大约阅读时间需要 30 分钟。

        UriMatcher:

        当我们在使用ContentProvide进行进程间通信时,那我们就必然会用到UriMatcher这个类,这个类的功能可以这样去理解,就是一段字符串与一个数值对应起来,只不过这段字符串是分段存储的,比如"path/csdn",那么在存的时候会先“/”对这个字符串进行分割然后在存起来,先来一段代码:

private static final String AUTHORITY = "com.zzq.uri";matcher = new UriMatcher(UriMatcher.NO_MATCH);matcher.addURI(AUTHORITY,"path1/zzq1",1);matcher.addURI(AUTHORITY,"path1/zzq2",2);matcher.addURI(AUTHORITY,"path2/zzq3/*",3);matcher.addURI(AUTHORITY,"path2/zzq4/#",4);matcher.match(Uri.parse("content://com.zzq.uri/path1/zzq2"));

它的存储图形:

                                                 

我们先来说它是如何匹配的,如果是我们自己定义的字符串匹配,那么这个协议头content://是可以随意取的,实际在这个匹配过程中,这个协议头实际是没有用到的,接下来就是看“com.zzq.uri/path1/zzq2”,内部匹配的时候实际也是讲这个字符串分成了三段,com.zzq.uri、path1、zzq2,分成三段后,先是第一段com.zzq.uri去匹配,匹配到的就只有一个,接下来在这个路径去匹配第二段,匹配到path1,再在path1路径下去匹配第三段,匹配到的结果就是zzq2,zzq2里面有记录添加时对应的数字,到这返回就是2了,对于添加时含有符号是#或*,那么在匹配时,#号对应的位置只要是数字就都可以匹配,而*号对应的位置只要是字符串就都可以匹配。这个类的作用有点像map集合,键是字符串,值是数字。如果还是不太清楚的可以去看源码。

UriMatcher的源码比较短。这里就直接贴出来了:

public class UriMatcher{    public static final int NO_MATCH = -1;    /**     * Creates the root node of the URI tree.     *     * @param code the code to match for the root URI     */    public UriMatcher(int code)    {        mCode = code;        mWhich = -1;        mChildren = new ArrayList
(); mText = null; } private UriMatcher() { mCode = NO_MATCH; mWhich = -1; mChildren = new ArrayList
(); 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. *

* 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 * @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. */ 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
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; } /** * Try to match against the path in a url. * * @param uri The url whose path we will match against. * * @return The code for the matched node (added using addURI), * or -1 if there is no matched node. */ public int match(Uri uri) { final List
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
< 0 ? uri.getAuthority() : pathSegments.get(i); ArrayList
list = node.mChildren; if (list == null) { break; } node = null; int lj = list.size(); for (int j=0; j
'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
mChildren;}

        ContentProvide:

        ContentProvide是四大组件之一,所以也是需要在清单文件中去注册的,比如下面注册:
对于注册的这个ContentProvide,别的应用如何找到呢?那这个就要看authorities这个属性了,我们访问ContentProvide都会用到getContentResolver()这个 方法,调用这个方法后返回的是ContentResolver对象,拿到这个对象后去访问ContentProvider需要我们传一个Uri进去,这里访问我们MyCOntentProvider的Uri是Content://com.example.zzq,这里用到的Uri就是authorities属性,到这里,虽说我们可以访问到ContentProvider,但是这个Uri并没指明他到ContentProvider去做什么,这个时候我们就可以在这个uri后面再添加路径,表明你这个uri是干嘛的,就好比https://baidu.com,这是百度的首页,如果我们要访问android百科,那么就是https://baike.baidu.com/item/Android/60243?fr=aladdin,在https://baidu.com后面加其他的路径,这样我们就可以访问到,ContentProvider用到的其实也是这个思路,只不过这后面的路径是需要我们自己去解析的,根据解析到的结果去做对应的处理,这里处理路径用到的就是UriMatcher。
        这里先上一段继承自ContentProvider的简单事例:
public class MyCOntentProvide extends ContentProvider {    private static final String TAG = "MyCOntentProvide";    private static final String authority = "com.example.zzq";    private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);    private static final String path1 = "path1";    private static final String path2 = "path2";    private static final String path3 = "path3";    private static final String path4 = "path4";    private static final String path5 = "path5";    private static final int code1 = 1;    private static final int code2 = 2;    private static final int code3 = 3;    private static final int code4 = 4;    private static final int code5 = 5;    static{        matcher.addURI(authority,path1,code1);        matcher.addURI(authority,path2,code2);        matcher.addURI(authority,path3,code3);        matcher.addURI(authority,path4,code4);        matcher.addURI(authority,path5,code5);    }    @Override    public boolean onCreate() {        return false;    }    @Nullable    @Override    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {        int match = matcher.match(uri);        switch (match){            case code1:                //你的处理                break;            case code2:                //你的处理                break;            case code3:                //你的处理                break;            case code4:                //你的处理                break;            case code5:                //你的处理                break;        }        MatrixCursor cursor = new MatrixCursor(new String[]{
"name","age"}); cursor.addRow(new String[]{
"zzq","12"}); return cursor; } @Nullable @Override public String getType(@NonNull Uri uri) { return "根据需要返回,也可以不做处理"; } @Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { int match = matcher.match(uri); switch (match){ case code1: //你的处理 break; case code2: //你的处理 break; case code3: //你的处理 break; case code4: //你的处理 break; case code5: //你的处理 break; } return uri; } @Override public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { return 1; } @Override public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { return 2; }}
当我们需要访问这个ContentProvider的时候,只需要调用getContentResolver()返回ContentResolver对象,然后调用ContentProvider的方法中对应的方就可以访问到,方法中需要我们传一个uri,比如上面这个事例,我们的uri中只要是content://com.example.zzq/...都是可以访问到这个ContentProvider的,那后面携带什么路径以及做什么对应的处理,那就是我们自己做定义了。比如我们访问的是一个uri = content://com.example.zzq/path2,
getContentResolver().query(uri,null,null,null,null);
后面需要什么参数就传什么参数,通过上面的调用就可以访问到这里注册的ContentProvide,那么在调用match.match(uri)后,返回的就是2,和上面我们在UriMatcher中添加path2的数字对应上,如果还需要别的参数,可以自己定义,只要两边协商好就可以了。
    这个时候我们可以看出UriMatcher其实就是一个工具类,如果不想用这个类,那也可以用Map来替代,我们做好对应的处理就ok了。在query()这个方法中需要我们返回的是一个Cursor,这时候我们可以自己构建一个MatrixCursor,然后往里面添加需要返回的数据就可以了。在这里做的操作不一定是访问数据库,任何操作都是你可以做的。耗时操作不要在这里处理,否者会报ANR。

        对于ContentProvider的使用,这里可以分为两个步骤,一是ContentProvider的注册,二是uri解析:

        1、对于ContentProvider的注册,其主要目的是对外提供访问这个ContentProvider的路径,也就是它的基路径,一般都是content://authorities的值,这个authorities就是注册这个ContentProvider的时候里面的一个属性。

        2、有了基路径content://authoritie后,后面可以在加一些其他的路径content://authorities/...,这样访问到的也是你定义的这个ContentProvider,后面加的参数是什么参数,要做什么处理,那就是你自己定义了,Android为我们提供了对这个路径的处理,那就是UriMatcher。        

你可能感兴趣的文章
SpringBoot | 配置logback-spring.xml
查看>>
SpringBoot | 第一章:构建第一个SpringBoot工程
查看>>
SpringBoot | 第二章:配置多环境以及上传文件
查看>>
Spring Data JPA |自定义非实体类的映射
查看>>
SpringBoot | 常用注解记录
查看>>
JavaBean对象转换EntityUtils工具类
查看>>
Maven常用命令
查看>>
SpringBoot | 运行报错,无法加载oracle连接驱动
查看>>
为什么阿里巴巴禁止在 foreach 循环里进行元素的 remove/add 操作
查看>>
AWS EC2如何从普通用户切换为root用户
查看>>
click方法不生效的
查看>>
mysql排行榜并列与不并列
查看>>
SpringBoot | Mybatis申明为Mapper文件
查看>>
JPA主键生成策略
查看>>
byte数组和InputStream的相互转换
查看>>
InputStream,InputStreamReader和Reader之间的区别与关系
查看>>
Java中System.arraycopy方法的使用
查看>>
tk.mybatis的使用记录
查看>>
遍历获取目录下的所有文件
查看>>
从指定服务器路径下载文件
查看>>