先上文档contentProvider
啥都不说,我们先到文档中查看
文档大致是这么说的:
ContentProvider是android应用程序的构建基础之一,它们封装数据并通过单一的ContentResolver接口提供给应用程序,如果你想要在多个应用程序之间共享数据,ContentProvider是必须需要的,例如,联系人数据由多个应用程序使用,必须存储在内容提供者中。如果不需要在多个应用程序之间共享数据,那么可以通过SQLiteDatabase直接使用数据库
当请求通过ContentResolver完成时,系统将检查给定URI的权限,并将请求传递给在权限内注册的内容提供者。内容提供程序可以解释它想要的其他URI。UriMatcher类有助于解析uri。
在使用ContentProvider时,我们需要继承一下几个方法
1. onCreate()
2.query(Uri, String[], String, String[], String)
3.insert(Uri, ContentValues)
4update(Uri, ContentValues, String, String[])
5.delete(Uri, String, String[])
6.getType(Uri)
ps:数据访问方法(如insert(Uri,ContentValues)和 update(Uri,ContentValues,String,String[]))可以同时从多个线程调用,而且必须是线程安全的
oncreate()方法必须在主线程中被调用
下面我们一个一个搞他们
1.oncreate()
在这里我们对ContentProvider进行初始化,在这里我们不能执行耗时操作,如果我们使用数据库,通常在这里我们使用DatabaseHelper来创建数据库的帮助类,成功返回true
2.query()
在这我们去处理客户端发送的请求命令。
3.insert()
处理插入请求,在调用之后,需要调用notifyChange()通知数据更改
4.update()
处理更新请求,通过selection和selectArgs参数约束更新行,需要调用notifyChange()通知数据更改
5.delete()
处理删除请求,通过selection和selectArgs参数约束更新行,需要调用notifyChange()通知数据更改
6.getType()
用于获取Uri对象所对应的MIME类型,一个内容Uri所对应的MIME字符串有以下三部分组成
1.必须以vnd开头
2如果内容Uri以路径结尾,最后接android.curosr.dir/,如果以id结尾,
最后接android.cursor.item/
3之后接上vnd.< authority>.< path>
所以,对于contnent://com.example.myapplication/table1
这个Uri就可以写成 vnd.android.curosr.dir/vnd.com.example.myapplication.table1
对于contnent://com.example.myapplication/table1/1就可以写成
vnd.android.cursor.item/vnd.com.example.myapplicaion.table1
现在我们来具体实现一下
创建数据库帮助类
package com.example.myapplication;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* Created by fang on 2017/11/13.
*/
public class MyDatabaseHelper extends SQLiteOpenHelper {
String create="create table book(id integer primary key autoincrement,name text,price real,author text)";
public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(create);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
创建ContentProvider
package com.example.myapplication;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
/**
* Created by fang on 2017/11/13.
*/
public class MyContentProvider extends ContentProvider {
String TAG = "TAG";
MyDatabaseHelper helper;
public static UriMatcher uriMatcher;
public static final int BOOK_DIR = 0;
public static final int BOOK_ITEM = 1;
public static final String AUTHORITY = "com.example.myapplication";
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
}
@Override
public boolean onCreate() {
helper = new MyDatabaseHelper(getContext(), "bookStore.db", null, 1);
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
SQLiteDatabase database = helper.getReadableDatabase();
Cursor cursor = null;
switch (uriMatcher.match(uri)) {
case BOOK_DIR: {
cursor = database.query("book", projection, selection, selectionArgs, null, null, sortOrder);
break;
}
case BOOK_ITEM: {
String id = uri.getPathSegments().get(1);
//getPathSegments()返回的是将Path部分的内容按照"/"分割并转成List集合,get(1)返回ID
Log.d(TAG, "id=" + id + " path=" + uri.getPathSegments().get(0));
cursor = database.query("book", projection, "id=?", new String[]{id}, null, null, sortOrder);
break;
}
}
return cursor;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
switch (uriMatcher.match(uri)) {
case BOOK_DIR: {
return "vnd.android.cursor.dir/vnd.com.example.myapplication.book";
}
case BOOK_ITEM: {
return "vnd.android.cursor.item/vnd.com.example.myapplication.book";
}
}
return null;
}
/**
* c插入数据,并不需要ID,同一张表,一次插入就行
*
* @param uri
* @param values
* @return
*/
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
SQLiteDatabase database = helper.getWritableDatabase();
Uri uriId = null;
switch (uriMatcher.match(uri)) {
case BOOK_DIR:
case BOOK_ITEM:
long newbookId = database.insert("book", null, values);
uriId = Uri.parse("content://" + AUTHORITY + "/book/" + newbookId);
break;
}
return uriId;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
SQLiteDatabase database = helper.getWritableDatabase();
int row = 0;
switch (uriMatcher.match(uri)) {
case BOOK_DIR: {
row = database.delete("book", selection, selectionArgs);
break;
}
case BOOK_ITEM: {
String bookid = uri.getPathSegments().get(1);
row = database.delete("book", "id=?", new String[]{bookid});
break;
}
}
return row;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
SQLiteDatabase database = helper.getWritableDatabase();
int row = 0;
switch (uriMatcher.match(uri)) {
case BOOK_DIR: {
database.update("book", values, selection, selectionArgs);
break;
}
case BOOK_ITEM: {
String id = uri.getPathSegments().get(1);
database.update("book", values, "id=?", new String[]{id});
break;
}
}
return row;
}
}
Avtivity
package com.example.myapplication;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button delete;
Button query;
Button insert;
Button update;
String path = "content://com.example.myapplication";
String TAG = "TAG";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
delete = (Button) findViewById(R.id.delete);
query = (Button) findViewById(R.id.query);
insert = (Button) findViewById(R.id.insert);
update = (Button) findViewById(R.id.update);
delete.setOnClickListener(this);
query.setOnClickListener(this);
insert.setOnClickListener(this);
update.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v == delete) {
int newId = 0;
getContentResolver().delete(Uri.parse(path+"/book/"+newId),null,null);
}
if (v == query) {
Cursor cursor = getContentResolver().query(Uri.parse(path + "/book"), null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int price = cursor.getInt(cursor.getColumnIndex("price"));
Log.d(TAG, "name=" + name);
Log.d(TAG, "author" + author);
Log.d(TAG, "price" + price);
Log.d(TAG, "=======================");
}
}
}
if (v == insert) {
//create table book(id integer primary key autoincrement,name text,price real,author text
ContentValues contentValues = new ContentValues();
contentValues.put("name", "第一行代码");
contentValues.put("price", 50);
contentValues.put("author", "郭霖");
getContentResolver().insert(Uri.parse(path + "/book"), contentValues);
ContentValues contentValues1 = new ContentValues();
contentValues1.put("name", "Effective java");
contentValues1.put("price", 40);
contentValues1.put("author", "Joshua Bloch");
getContentResolver().insert(Uri.parse(path + "/book"), contentValues1);
}
if (v == update) {
int newID = 2;
ContentValues contentValues1 = new ContentValues();
contentValues1.put("name", "JAVA编程思想");
contentValues1.put("price", 89);
contentValues1.put("author", "Bruce Eckel");
getContentResolver().update(Uri.parse(path + "/book/" + newID), contentValues1, null, null);
}
}
}
主布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.myapplication.MainActivity">
<Button
android:id="@+id/delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="delete" />
<Button
android:id="@+id/query"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="query" />
<Button
android:id="@+id/insert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="insert" />
<Button
android:id="@+id/update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="update" />
</LinearLayout>
现在我们就创建了一个自己的内容提供者
一般来说我们不会将数据暴露出去,相反我们却需要系统提供给我们提供数据,这时候我们就需要知道系统常见的查询条件
在下面我们列出一些
电话联系人:
Uri: ContactsContract.Contacts.CONTENT_URI
String[] columns={“_id”,”display_name”,”has_phone_number”};
不知道固列的。可以使用Contact点出来,就是一堆常量
Uri:ContactsContract.CommonDataKinds.Phone.CONTENT_URI
String[] phone_cols={ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID
};
使用CommonDataKinds点出来
图片:
Uri:MediaStore.Images.Media.EXTERNAL_CONTENT_URI
String str[] = { MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATA};
音频:
Uri:MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
String str[] = { MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.SIZE};
视频:
Uri:MediaStore.Video.Media.EXTERNAL_CONTENT_URI
String str[] = { MediaStore.Video.Media._ID,
MediaStore.Video.Media.DISPLAY_NAME,
MediaStore.Video.Media.DATA};
短信:
Uri:(Uri.parse(“content://sms/”)
String[] cols={“address”,”type”,”body”,”date”};
通话记录:
Uri:CallLog.Calls.CONTENT_URI
String[] cols={
CallLog.Calls.NUMBER,//电话号码
CallLog.Calls.CACHED_NAME,//联系人名
CallLog.Calls.TYPE,//通话类型:1:已接,2:已拨,3:未接
CallLog.Calls.DATE,//通话日期时间
CallLog.Calls.DURATION//通话时长
};
常用的系统权限
<uses-permission android:name="android.permission.INTERNET"/>
访问网络
<uses-permission android:name="android.permission.CALL_PHONE"/>
拨打电话
<uses-permission android:name="android.permission.SEND_SMS"/>
发送信息
<uses-permission android:name="android.permission.READ_CONTACTS"/>
读取联系人
<uses-permission android:name="android.permission.READ_SMS"/>
读取信息
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
录制声音
<uses-permission
android:name="android.permission.READ_PHONE_STATE"/>
读取手机状态
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
对外存进行读写
下面我们进行演示部分上面的操作
package com.example.fang.myapplication;
import android.database.Cursor;
import android.provider.ContactsContract;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button button;
String TAG = "TAG";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.select);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
String[] column = {"_id", "display_name", "has_phone_number"};//查询联系人
Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, column, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
Log.d(TAG, "id-----------------------" + cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts._ID)));
Log.d(TAG, "display_name-------------" + cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)));
Log.d(TAG, "has_phone_number---------" + cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)));//代表有没有号码1代表有0代表无
}
}
}
}
其他的查询也一样,就不演示了,上面是一些基本的常量,直接用就是了