Android——内容提供者

Android 基础中最重要的就四大组件,四大组件是Android学习的开始。
activity ——算作Android界面
service——服务
Broadcast Receiver——广播
Content Provider——内容提供者
这四大组件开始对我来说内容提供者是最难理解的,但是慢慢接触之后感觉也不是很难。相对于基础来说吧。
这两天我又看了这一章的内容,就在这做个笔记吧

内容提供者。就按字面意思来理解 Android手机的内容,提供出来的工具
在做黑马教程(手机卫士)的时候就要提取出联系人,短信等数据的时候就要到了内容提供者
它是不同应用程序直接进行数据交换的标准API,当一个应用程序需要把自己的数据暴露出来给其他应用使用的时候,该应用程序
就可以通过提供contentProvider来实现:其他应用程序就可以通过ContentResolver来操作ContentProvider暴露出来的数据(抄的疯狂Android)

这里就可以知道,Android的内容提供者是有两部分组成的,这样想。内容当做事一个苹果树,A是苹果树的拥有者,如果B想要就需要拿钱去买。
但是A想卖,B才能买。买卖交换就要有市场。
Android——内容提供者
简单点说就是其他应用拿数据,需要一个桥梁这就出现了内容提供者
Uri就是这个桥梁
想利用好内容提供者就要知道Uri。
假设你想去百度获取信息,该怎么办。首先得去百度网站才能吧。那也就是去到百度的界面,去百度的网站 
同理,B应用要拿到A应用的网站就要去A的网站。只是在这里应该是打引号的网站,先这样理解吧

从其他地方扒了一点过来
Uri代表了要操作的数据,Uri主要包含了两部分信息
①需要操作的ContentProvider
②对ContentProvider中的什么数据进行操作
组成部分
①scheme:ContentProvider的scheme已经由Android所规定为content://
②主机名(Authority):用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。建议为公司域名,保持唯一性
③路径(path):可以用来表示我们要操作的数据,路径的构建应根据业务而定:
Android——内容提供者
要操作person表中id为10的记录,可以构建这样的路径:/person/10
要操作person表中id为10的记录的name字段, person/10/name
要操作person表中的所有记录,可以构建这样的路径:/person
要操作xxx表中的记录,可以构建这样的路径:/xxx
当然要操作的数据不一定来自数据库,也可以是文件等他存储方式,如下:  
要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:
Uri uri = Uri.parse("content://com.jbridge.provider.personprovider/person")

下面就直接写代码把。方法直接就在代码直接说

清单文件
1
           <provider
2
            android:authorities="org.crazyit.providers.firstprovider"  <!--这么一长串的东西只是一个标识-->
3
            android:name=".content.FirstProvider"
4
            ></provider>
这个程序我就用了四个button,就没有添代码了
然后我点击了 插入 出现了 
参数是name=Yaca

大致就是这么一个节奏

1
    //实现插入的方法,该方法应该返回新插入的纪录的Uri
2
    @Nullable
3
    @Override
4
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
5
        Log.w(Tag , "insert: 调用");
6
        Log.w(Tag , "values: 参数是"+values);
7
        return null;
8
    }

把这两个代码放在一起看,就懂了。 数据的操作无法就是增删改查。contentProvider定义增删改查的方法。contentResolver提供参数

创建ContentProvider的说明
通过上面的介绍可以看出,ContentProvide不像Activity存在复杂的生命周期,ContentProvider只有一个onCreate()生命周期方法——当其他应用通过ContentResolver第一次方法该ContentProvider时
onCreate()方法将会被调用,onCreate只会被调用一次:ContentProvider提供的query(),insert(),update(),delete()方法则由其他应用用过ContentResolve调用这些方法时传入
前面介绍的示例由于并未真正对数据进行操作,因此ContentProvider实际能处理的Uri,以及确定每个方法中Uri参数所操作的额数据,Android系统提供了UriMatcher工具类

void addURI(String authority,String path,int code):该方法用于向UriMatcher对象注册Uri,其中authorty和path组合成一个Uri,而code则代表Uri对应标识码
int match(Uri uri) : 根据前面注册的Uri来判断指定Uri对应的标识码,如果找不到匹配的标识码,该方法将会返回 -1

例如,我们先通过如下代码来创建UriMatcher对象
1
UriMatcher mather = new UriMathcer(UriMathcer.NO_MATCh);
2
mathcer.addURI("org.crazyit.providers.firstprovider","words",1);
3
mathcer.addURI("org.crazyit.providers.firstprovider","word/#",2);
上面创建的UriMatcher对象注册了两个Uri,其中org.crazyit.providers.firstprovider/words对应的识别码为1;
org.crazyit.providers.firstprovider/word#对应的标识码为2;#为通配符
这就意味着如下匹配结果:
至于到底需要为UriMatcher对象注册多少个uri,则取决于系统的业务逻辑
对于"content:// org.crazyit.providers.firstprovider/words "这个Uri,它的资源部分为words,这种资源通常代表了访问所以数据项;对应
"content:// org.crazyit.providers.firstprovider/word/2"这个Uri。它的资源部分通常代表访问数据项,其中最后一个数值往往代表了该数据的ID
除此之外,Android还提供了ContentUris工具类,它是一个操作Uri字符串的工具类
提供了如下两个工具方法

withAPPendedld(Uri,id)用于为路径加上ID部分
1
Uri uri = Uri.parse("content:// org.crazyit.providers.firstprovider/words ");
2
Uri resultUri = ContentUris.withAppendedId(Uri,2);
3
//生成后的Uri为:"content:// org.crazyit.providers.firstprovider/word/2"
Parseld(uri):用于从指定Uri种解析出所包含的ID值

接下来我就写一个例子:还是老路子,学生信息管理 
在A应用上创建一个数据库,然后在B应用上调用A应用的数据

开始创建A应用:代码如下
数据库类的代码
1
import android.content.Context;
2
import android.database.DatabaseErrorHandler;
3
import android.database.sqlite.SQLiteDatabase;
4
import android.database.sqlite.SQLiteOpenHelper;
5
import android.util.Log;
6
7
/**
8
 * Created by YacaToy on 2017/6/23.
9
 */
10
11
public class MySQLieOpenHeler extends SQLiteOpenHelper {
12
    private String Tag = "MySQLieOpenHeler";
13
    public MySQLieOpenHeler(Context context) {
14
        super(context, "student.db", null, 1);
15
    }
16
17
    @Override
18
    public void onCreate(SQLiteDatabase db) {
19
        Log.w(Tag,"创建了SQL");
20
        db.execSQL("create table student (_id integer  primary key autoincrement , " +
21
                "name varchar(50),phone varchar(20));");
22
    }
23
24
    @Override
25
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
26
27
    }
28
}
然后就是创建一下A应用的ContentProvider基础类

基本就是把,ContentResolver要调用的参数直接给数据操作。db了。这样也就相当于一个桥梁。直接把参数给它就成

一定要记得配置清单文件
1
       <provider
2
            android:authorities="com.yacatot.data.student"
3
            android:name=".MyContent"
4
            android:exported="true"
5
            ></provider>
最后一开始创建的时候就配置好,等下忘记了

好了。A应有提供功能就写完了。该是B应用了

布局文件我就写了四个按钮,没有做其他处理。有点儿懒
直接说吧。看代码
这里说一下。查询。在A应有中
1
//查询
2
    @Nullable
3
    @Override
4
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
5
        //这里一定要记得 new MySQLieOpenHeler(this.getContext()); 否则就是爆空指针异常
6
        if(dbOpenHelper == null){
7
            dbOpenHelper = new MySQLieOpenHeler(this.getContext());
8
        }
9
        SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
10
        return db.query("student",projection,selection,selectionArgs,null,null,sortOrder);
11
    }
12
//这里返回的是Cursor类型,记得。Content只是一个桥梁,他不做好人好事。
13
内容提供者的基础就介绍完了。有什么问题一起讨论。新手之间多多学习