内容提供者 这个东西主要是用来提供外部访问自身数据库的,也就是相对于给我们一个出口,将我们的数据对外提供。 这个东西一般是和数据库进行配合使用。 所以首先我们先构造一个数据库:
1 2 MySQLiteOpenHelper mso = new MySQLiteOpenHelper(getBaseContext()); mso.getReadableDatabase();
先写一个自己的数据库,然后实例化创建我们的数据库,数据库代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package com.example.android_study13.database;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteDatabase.CursorFactory;import android.database.sqlite.SQLiteOpenHelper;public class MySQLiteOpenHelper extends SQLiteOpenHelper { public MySQLiteOpenHelper (Context context) { super (context, "DATA.db" , null , 1 ); } @Override public void onCreate (SQLiteDatabase db) { db.execSQL("create table student(id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,age INTEGER)" ); db.execSQL("create table teacher(id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,kemu TEXT)" ); } @Override public void onUpgrade (SQLiteDatabase db, int oldVersion, int newVersion) { } }
就是在创建的时候我们创建我们的数据库。 一个学生表和老师表。 下面是关键,我们需要写一个继承于ContentProvider
的类,这个类是用来重写那些方法的,而且这个类也是我们需要配置的:
1 2 3 4 5 6 7 8 9 10 11 12 @Override public boolean onCreate () { Log.d("wker" , "Oncreate" ); try { SQLiteOpenHelper open = new MySQLiteOpenHelper(getContext()); database = open.getWritableDatabase(); return true ; } catch (Exception e) { e.printStackTrace(); return false ; } }
首先我们在这个方法中重写,主要使用来获取数据库操作对象的。 下面写插入数据:
1 2 3 4 5 6 7 @Override public Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Log.d("wker" , "query" ); ContentResolver resolver = getContext().getContentResolver(); resolver.notifyChange(uri, null ); return null ; }
返回一个数据库的迭代器,意思就是将我们数据库查询的对象返回回去,我这里没写查询,但是要看下面的两句代码,这个就是通过上下文环境获取内容解析者,获取到解析者之后通知内容监听者,我们有新的信息了。 添加方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Override public Uri insert (Uri uri, ContentValues values) { Log.d("wker" , "insert" ); long result=-1 ; switch (matcher.match(uri)) { case STUDENT: result = database.insert("student" , null , values); break ; case TEACHER: result = database.insert("teacher" , null , values); break ; } return Uri.parse("result://io.wker666/" +result); }
这个就是数据库的插入,传进来一个Uri的对象,这个对象中有我们要进行操作的数据,我们可以通过UriMatcher的匹配方法判断是不是满足某个条件的Uri。 所以我们先要去创建一个UriMatcher的对象:
1 2 3 4 5 6 7 8 9 10 private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);private static final int STUDENT = 1 ;private static final int TEACHER = 2 ;static { matcher.addURI("io.wker666" , "student" , STUDENT); matcher.addURI("io.wker666" , "teacher" , TEACHER); }
UriMatcher对象是专门用来进行匹配Uri的就有点像正则匹配器,在初始化的时候传进去一个int值,这个值代表的是我们没有匹配到结果的时候我们返回的结果,addURI
这个方法是用来添加Uri匹配的,第一个参数是Uri的域名,第二个数路径,第三个参数是我们的返回值,这里我们返回一个常量,上面定义了的。 所以我们在插入数据的时候,我们首先匹配这个Uri对象,然后根据返回值来给特定的表段进行增删改查。 最后插入完毕之后我们就将我们的结果返回回去。 比较特别的是一个getType()
方法,这个方法主要是用来判断Uri对象所对应的类型的:
1 2 3 4 public String getType (Uri uri) { Log.d("wker" , "getType" ); return null ; }
这里我没改,返回的一般是一个MIME的字符串。 写完之后,我们就要将我们的这个类配置我们XML文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <application android:allowBackup ="true" android:icon ="@drawable/ic_launcher" android:label ="@string/app_name" android:theme ="@style/AppTheme" > <activity android:name =".MainActivity" android:label ="@string/app_name" > <intent-filter > <action android:name ="android.intent.action.MAIN" /> <category android:name ="android.intent.category.LAUNCHER" /> </intent-filter > </activity > <provider android:name ="com.example.android_study13.provider.MyContentProvider" android:authorities ="io.wker666" android:exported ="true" /> </application >
最关键的就是那个provider
这个节点,name
属性使我们需要对外提供的全类名,如果不想写全类名,那么就要将我们的包写在配置文件根节点上,authorities
这个属性使用来表示我们的根Uri的,exported
这个属性必须要要,否则会抛出异常,true代表是对外可以访问。
内容解析者 用来获取内容提供给我们的数据的:
1 2 3 4 5 6 public void onQuery (View view) { ContentResolver resolver = getContentResolver(); Uri uri = Uri.parse("content://io.wker666" ); resolver.query(uri, null , null , null , null ); }
比较简单,收我们先要获取内容解析者,这个东西应该是个单例对象,获取之后我们就能调用相对应的内容提供者中的方法了,但是之前我们先要配一下我们的Uri对象,配置的时候,我们不能忘记丢掉我们的协议名content://,也就是我们内容提供者中所提供的类名,然后进行查询就好了,也就会调用我们在内容提供者中编写的方法。
1 2 3 4 5 6 7 8 9 10 11 public void onInsert (View view) { ContentResolver resolver = getContentResolver(); Uri uri = Uri.parse("content://io.wker666/" +"teacher" ); ContentValues values = new ContentValues(); values.put("name" , "wker" ); values.put("kemu" , "c" ); Uri reu= resolver.insert(uri, values ); Log.d("wker" , reu.toString()); }
这个和上面类似,也就是配置我们的Uri,配置好之后,我们要加入的数据,通过ContentValues
这个键值对的对象,然后将返回给我们的Uri接受一下,也就是得到我们加入了第几行。
内容监听者 这个东西也是比较简单,主要是重写父类的方法,新建一个类,继承ContentObserver
这个类,然后重写我们的onChange
方法,也就是在内容提供者有对应操作的时候会给我们提供数据:public void onChange(boolean selfChange, Uri uri)
,可以看到传进来一个Uri,也就是我们要的数据。 我们在使用这个东西之前我们先要注册这个内容监听者:
1 2 3 4 5 6 7 8 private MyObserver mco;mco = new MyObserver(new Handler()); Uri uri = Uri.parse("content://sms" ); getContentResolver().registerContentObserver(uri, true , mco);
注册也比较简单,就是通过内容解析者来注册这个内容监听者,第一个参数是我们要监听的Uri,第二个参数是我们是否想要进行模糊匹配,第三个参数就是我们的实例对象。 之后我们有数据传输的时候我们就会调用onChange
方法了。 我们如果想要注销的话呢:getContentResolver().unregisterContentObserver(mco);
这个样子就可以进行注销内容监听者了。 但是有一点要注意,我们一定要在数据传输的时候要使用内容解析者的notify方法通知内容监听者:
1 2 ContentResolver resolver = getContext().getContentResolver(); resolver.notifyChange(uri, null );
也就是这个东西,否则我们是接收不到的。