四大组件
· ContentProvider
按照谷歌API给的说法,ContentProvider其实就是一个数据共享的一个东西,它是为多个应用提供数据共享的唯一一种方式。比如电话本,电话本数据可以为多个应用提供数据,它就是ContentProvider实现的。如果你的应用不想为其他应用提供数据共享,那么你就可以用手机SQLiteDataBase实现。
当进行数据共享时,一个请求通过ContentResolver系统检查特定URI认证,并将请求内容提供者注册的认证。内容提供者可以解释它想要的URI。我们用UriMatcher类来管理URL。
在运用ContentProvider时,我们要实现以下几个方法:
- onCreate() : ContentProvider初始化调用
- query(Uri, String[], String, String[], String) : 将结果返回给调用者
- insert(Uri, ContentValues) : 向ContentProvider插入一条数据
- update(Uri, ContentValues, String, String[]) : ContentProvider更新一条数据
- delete(Uri, String, String[]) : ContentProvider删除一条数据
- getType(Uri) : 给ContentProvider返回一个MIME数据类型
注意 :
ContentProvider中的query 和 update方法在同一时间有几个线程调用时,那么必须是线程安全的。其他的方法也必须值UI线程中调用,否则会报错。
好了,我们结合一个简单的程序实例来具体说下。
1、首先我们自定义我们自己的ContentProvider,直接继承自ContentProvider即可。
public class TestContentProvider extends ContentProvider {
private TestMyDatabase myDatabase;
private SQLiteDatabase dbHelper;
static UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI("zhulinxianzi.com", "first", 1);
uriMatcher.addURI("zhulinxianzi.com", "first/#", 2);
uriMatcher.addURI("zhulinxianzi.com", "first/*", 3);
uriMatcher.addURI("zhulinxianzi.com", "second", 4);
uriMatcher.addURI("zhulinxianzi.com", "second/#", 5);
uriMatcher.addURI("zhulinxianzi.com", "second/*", 6);
}
@Override
public boolean onCreate() {
if (myDatabase == null) {
myDatabase = new TestMyDatabase(App.appContext);
}
return true;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
dbHelper = myDatabase.getWritableDatabase();
int code = uriMatcher.match(uri);
Cursor cursor;
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
switch (code) {
case 1:
builder.setTables(TestMyDatabase.TABLE_NAME);
break;
case 2:
builder.setTables(TestMyDatabase.TABLE_NAME2);
break;
}
cursor = builder.query(dbHelper, projection, selection, selectionArgs,null,"",sortOrder);
return cursor;
}
@Nullable
@Override
public String getType(Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
dbHelper = myDatabase.getWritableDatabase();
int code = uriMatcher.match(uri);
long id;
switch (code) {
case 1:
id = dbHelper.insert(TestMyDatabase.TABLE_NAME, null, values);
break;
case 4:
id = dbHelper.insert(TestMyDatabase.TABLE_NAME2, null, values);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
return ContentUris.withAppendedId(uri, id);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
}
我们在这里稍微说说这个UriMatcher。
UriMatcher我们在初始化的时候都是静态类里初始化。它管理的Uri都是由三部分构成,举个例子:
content://zhulinxianzi.com/first/123
content:我们称之为scheme。
zhulinxianzi.com:我们称之为:authority。他就是我们进行Uri匹配的重要部分。
first/123:我们称之为path。
first部分我们一般取的事数据库表名,在后面的123,我们根据后面的/#还是/*来区分是数字还是任何字符。我们可以更这个来做删除或者更新,其可作为参数使用,比如:
content://zhulinxianzi.com/first/123
long parmas = ContentUris.parseId(uri);
我们可以得到123这个参数。
content://zhulinxianzi.com/first/lisi
String table = uri.getPathSegments().get(0);
String name = uri.getPathSegments().get(1);
table 的值为:first,而name的值为:list 。
2、创建我们我数据库
public class TestMyDatabase extends SQLiteOpenHelper {
public static final String DB_NAME="test.db";
public static final String TABLE_NAME="test";
public static final String TABLE_NAME2="test2";
private static int DB_VERSION= 1;
private static final String CREATE_TABLE = "create table "+TABLE_NAME+" (_id integer primary key autoincrement ,name varchar(30));";
private static final String CREATE_TABLE2 = "create table "+TABLE_NAME2+" (_id integer primary key autoincrement ,name varchar(30));";
public TestMyDatabase(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
db.execSQL(CREATE_TABLE2);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if(newVersion > oldVersion){
db.execSQL("drop table if exists "+ TABLE_NAME);
db.execSQL("drop table if exists "+ TABLE_NAME2);
onCreate(db);
}
}
}
3、 manifest里进行配置
<provider
android:authorities="zhulinxianzi.com"
android:name=".control.TestContentProvider"
android:exported="true"/>
exported是第三方是否可以读取数据,值为false,则无法读取,汇报安全权限错误。
4、 接下我我们就可以在自己的应用里或者第三方(有权限)应用调用了。
插入数据:
private void insert() {
ContentResolver cp = getContentResolver();
ContentValues values = new ContentValues();
values.put("name", "liu");
Uri uri = cp.insert(
Uri.parse("content://zhulinxianzi.com/first"), values);
LogUtil.i("info",uri.toString());
}
如果插入成功:则日志打印:content://zhulinxianzi.com/first/1。
1是代表插入成功后数据库返回的当前数据库数据的id号。
查询数据:
private void getCount(){
ContentResolver cp= getContentResolver();
Cursor cursor = cp.query(
Uri.parse("content://zhulinxizi.com/first"),
null,null,null,null);
if (cursor!= null) {
Log.i("info","cursor.size :" + cursor.getCount());
}
····
}
查询成功后,会打印数据的条数,显示数据等操作。
至于其他的我们删除、更新都是同样的做法,不在赘述。
我们在这里的方法getType是返回的null。这个一般用的少,但是从谷歌官方解释说,它是返回uri里对应的MIME值。如果是一条数据,那么它返回的应该是vnd.android.cursor.item
开头,如果是数据集多条数据的话,应该是以vnd.android.cursor.dir/
开头,/后面的我们可以随便写了。另外,这也可以用在第三方获取数据的读写权限和隐式调用中。
在manifest配置provider时,我们看到还可以配置其他的具体权限问题:
<provider
android:authorities="wanduoduo.com"
android:name=".control.TestContentProvider"
android:exported="true"
android:permission=""
android:readPermission=""
android:writePermission=""
/>
具体的权限问题和getType的问题,大家可以上网自行学习下。
好了,Android四大组件我们介绍完了。接下来,我们进入View的重头戏吧。
祝大家2017年生活幸福,快乐每一天。