我的全部文章整理在此篇,將陸續更新收錄:知無涯,行者之路莫言終(個人編程之路)java
[1]經過短信認識ContentProvider的查詢功能
[2]經過圖片查詢瞭解ContentProvider插入、修改、更新、查找等操做
[3]查詢聯繫人看一下兩個表之間該怎麼辦
[4]簡單看一下Android系統如何實現短信的ContentProvider
[5]如何自定義一個ContentProvider,來給別的應用使用
複製代碼
權限自理:
<uses-permission android:name="android.permission.READ_SMS"/>
android
/**
* 做者:張風捷特烈
* 時間:2018/4/12:16:46
* 郵箱:1981462002@qq.com
* 說明:短信實體類
*/
class SMSBean {
var address: String? = null//短信發送方
var name: String? = null//號碼在通信錄中的姓名:無爲null
var date: String? = null//短信時間
var body: String? = null//短信內容
var type: Int = 0//1 接收短信 2 發送短信
var thread_id: Int = 0//同一個手機號互發的短信,其序號是相同的
}
複製代碼
/**
* 獲取短信:SMSBean:address發信人 date時間 body信息內容
*
* @param ctx 上下文
* @return 短信bean集合 注意添加讀取短信權限
*/
public static List<SMSBean> getSMS(Context ctx) {
List<SMSBean> smsBeans = new ArrayList<>();
//[1.]得到ContentResolver對象
ContentResolver resolver = ctx.getContentResolver();
//[2.1]獲得Uri :訪問raw_contacts的url
Uri uri = Uri.parse("content://sms");
//[3]查詢表,得到sms表遊標結果集
String[] projection = {"address", "date", "body", "type", "person", "thread_id"};//訪問表的字段
Cursor cursor = resolver.query(
uri, projection, null, null, null);
while (cursor.moveToNext()) {//遍歷遊標,獲取數據,儲存在bean中
SMSBean smsBean = new SMSBean();
smsBean.setAddress(cursor.getString(cursor.getColumnIndex("address")));
smsBean.setDate(cursor.getString(cursor.getColumnIndex("date")));
smsBean.setBody(cursor.getString(cursor.getColumnIndex("body")));
smsBean.setType(cursor.getInt(cursor.getColumnIndex("type")));
smsBean.setName(cursor.getString(cursor.getColumnIndex("person")));
smsBean.setThread_id(cursor.getInt(cursor.getColumnIndex("thread_id")));
smsBeans.add(smsBean);
}
//[4] 關閉cursor
cursor.close();
return smsBeans;
}
複製代碼
sql的基礎知識git
* @param uri 資源地址
The URI, using the content:// scheme, for the content to retrieve.
* @param projection 想要查詢的列, null查詢全部列,最低效
A list of which columns to return. Passing null will return all columns, which is inefficient.
* @param selection 查詢過濾語句(不用加where)
A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself).
Passing null will return all rows for the given URI.
* @param selectionArgs 查詢過濾語句中的參數
You may include ?s in selection, which will be replaced by the values from selectionArgs,
in the order that they appear in the selection. The values will be bound as Strings.
* @param sortOrder 排序
How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself).
Passing null will use the default sort order, which may be unordered.
複製代碼
下面親測可用,就補貼圖了github
|-- 查詢10086發來的信息
Cursor cursor = resolver.query(
uri, projection, "address=10086", null, null);
|-- 查詢指定號碼發來的信息
public static List<SMSBean> getSMSByPhone(Context ctx, String phone) {
...
Cursor cursor = resolver.query(
uri, projection, "address=?", new String[]{phone}, null);
...
}
|-- 按時間倒序排序
Cursor cursor = resolver.query(
uri, projection, "address=?", new String[]{phone}, "date desc");
|-- 按時間倒序排序 + 取前八條數據
Cursor cursor = resolver.query(
uri, projection, "address=?", new String[]{phone}, "date desc limit 0,8");
複製代碼
media做爲手機的三鼎之一,天然是少不了內容提供者來向外界暴漏信息
主要儲存在external.db(外部)
和internal.db(內部)
兩個數據庫中
數據庫中圖片的主要字段有:sql
_id:id標識 _data: 圖片絕對路徑 _size: 圖片大小 mime_type: 類型
data_added:添加的時間 data_modifide:最後修改時間 _display_name:顯示名稱 description:描述
width:寬 height:高
複製代碼
private void insertImg() {
//1.建立ContentValues對象,記錄插入照片信息
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, "張風捷特烈");
values.put(MediaStore.Images.Media.DESCRIPTION, "天下無雙");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
//2.獲取內容提供者,插入(外部圖片存儲Uri,values),返回插入圖片的Uri
Uri imgFileUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
L.d(imgFileUri + L.l());//content://media/external/images/media/1064830
//3.經過打開圖片的意圖添加額外信息將imgFileUri發送給系統相機
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imgFileUri);
startActivity(intent);
}
複製代碼
private void readImg() {
try {
//1.獲取內容提供者,經過剛纔的Uri打開輸入流
Uri imgUri = Uri.parse("content://media/external/images/media/1064830");
InputStream is = getContentResolver().openInputStream(imgUri);
//2.將圖片解碼展現
Bitmap bitmap = BitmapFactory.decodeStream(is);
mImageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
複製代碼
private void updateImg() {
ContentValues values = new ContentValues(2);
values.put(MediaStore.Images.Media.DISPLAY_NAME, "Toly");
values.put(MediaStore.Images.Media.DESCRIPTION, "Only Me");
//1.獲取內容提供者,經過剛纔的Uri打開輸入流
Uri imgUri = Uri.parse("content://media/external/images/media/1064830");
getContentResolver().update(imgUri, values, null, null);
}
複製代碼
既然是內容提供者,玩個表再所不免,驗證上面的修改方法是否成功數據庫
private void queryImg() {
//1.查詢得到遊標
Cursor cursor = getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, "_id=1064830",
null, null, null);
//2.讓遊標移動,到尾爲止
while (cursor.moveToNext()) {
String filePath = cursor.getString(cursor.getColumnIndex("_data"));
String name = cursor.getString(cursor.getColumnIndex("_display_name"));
String description = cursor.getString(cursor.getColumnIndex("description"));
L.d(filePath + L.l());//storage/emulated/0/DCIM/Camera/1539834068417.jpg
L.d(name + L.l());//Toly
L.d(description + L.l());//Only Me
}
複製代碼
private void deleteImg() {
Uri imgUri = Uri.parse("content://media/external/images/media/1064830");
int delete = getContentResolver().delete(imgUri, "_id=1064830", null);
L.d(delete + L.l());//1 表示刪除了1行
}
複製代碼
一共12540張圖片,方法耗時:1.289秒,屬於耗時操做應該放在子線程
能夠獲取數據庫中的字段,封裝一個圖片的實體類,以便使用編程
private ArrayList<String> queryAllImg() {
ArrayList<String> imgPaths = new ArrayList<>();
//1.查詢得到遊標
Cursor cursor = getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, "",
null, null, null);
//2.讓遊標移動,到尾爲止
while (cursor.moveToNext()) {
String filePath = cursor.getString(cursor.getColumnIndex("_data"));
imgPaths.add(filePath);
}
return imgPaths;
}
複製代碼
爲了簡便,使用Picasso來加載圖片--詳情可見:開源框架之[-Picasso-]應用篇bash
排序條件:
"date_added desc"
表示根據date_added字段倒序查詢
將數據盛放在List中,並根據列表元素個數來決定跳出while循環app
private ArrayList<String> queryPic100() {
ArrayList<String> imgPaths = new ArrayList<>();
//1.查詢得到遊標
String queryCol = MediaStore.Images.Media.DATE_ADDED;
Cursor cursor = getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, "",
null, "date_added desc", null);
//2.讓遊標移動,到尾爲止
while (cursor.moveToNext()) {
if (imgPaths.size() >= 100) {
break;
}
String filePath = cursor.getString(cursor.getColumnIndex("_data"));
imgPaths.add(filePath);
}
return imgPaths;
}
複製代碼
1).建立適配器類和ViewHolder
2).設置RecyclerView樣式框架
/**
* 適配器
*/
class PicRVAdapter extends RecyclerView.Adapter<PicViewHolder> {
@NonNull
@Override
public PicViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(Pic100Activity.this).inflate(R.layout.item_img, null);
return new PicViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull PicViewHolder holder, int position) {
//使用Picasso加載文件圖片
Picasso.get().setIndicatorsEnabled(true);
Picasso.get()
.load(new File(mList.get(position)))//文件
.resize(200,200)//重設尺寸
.into(holder.mIv_icon);
}
@Override
public int getItemCount() {
return mList.size();
}
}
/**
* ViewHolder
*/
public class PicViewHolder extends RecyclerView.ViewHolder {
public final ImageView mIv_icon;
/**
* itemView爲MyViewHolder中onCreateViewHolder加載的佈局
*
* @param itemView 條目
*/
public PicViewHolder(View itemView) {
super(itemView);
mIv_icon = itemView.findViewById(R.id.id_iv_item);
}
}
複製代碼
//1.設置適配器
mIdRvPic100.setAdapter(new PicRVAdapter());
//2.!!建立佈局管理器
mGLM = new GridLayoutManager(this, 4, GridLayoutManager.VERTICAL, false);
//3.!!!設置佈局管理器
mIdRvPic100.setLayoutManager(mGLM);
複製代碼
MediaStore是一個爲例方便操做媒體ContentProvider而給出的類,
圖片、音頻、視頻三大頂樑柱都涉及了,因此圖片會操做,那兩個也不在話下
權限自理:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
raw_contacts表
中查到contact_id字段
,在每一個contact_id
下,根據contact_id
查詢data表
字段,
而後判斷mimetype的值,新建實體類,將數據設置到實體中,將實體放入實體集合,查完返回集合。
聯繫人數據庫
raw_contacts表
關注字段contact_id
data表
和mimetype表
:關注字段:mimetype_id 、raw_contact_id 、data1
/**
* 做者:張風捷特烈<br></br>
* 時間:2019/2/27/027:19:48<br></br>
* 郵箱:1981462002@qq.com<br></br>
* 說明:聯繫人
*/
class ContactBean {
var name: String? = null//聯繫人姓名
var address: String? = null//聯繫人地址
var email: String? = null//聯繫人郵箱
var phone: String? = null//聯繫人電話
var photo: Bitmap? = null//聯繫人頭像
}
複製代碼
/**
* 獲取聯繫人:ContactBean字段:name姓名 address地址 email郵箱 phone手機號
*
* @param ctx 上下文
* @return ContactBean集合
*/
public static List<ContactBean> getContact(Context ctx) {
//建立一個容器放結果
List<ContactBean> contactBeans = new ArrayList<>();
//[1.]得到ContentResolver對象
ContentResolver resolver = ctx.getContentResolver();
//[2.1]獲得Uri :訪問raw_contacts的url
Uri raw_contactsUri = Uri.parse("content://com.android.contacts/raw_contacts");
//[2.2]獲得Uri ://訪問data的url
Uri dataUri = Uri.parse("content://com.android.contacts/data");
//[3]查詢表,得到raw_contact表遊標結果集
Cursor raw_contactsCursor = resolver.query(
raw_contactsUri, new String[]{"contact_id"}, null, null, null);
//[4]遍歷遊標,獲取數據,儲存在bean中
while (raw_contactsCursor.moveToNext()) {
//[4.1]查詢到contact_id
String contact_id = raw_contactsCursor.getString(0);
if (contact_id != null) {
//[4.2]查詢表,得到data表遊標結果集
Cursor dataCursor = resolver.query(dataUri,
new String[]{"data1", "mimetype"},//注意不是mimetype_id
"raw_contact_id=?",
new String[]{contact_id}, null);
ContactBean contactBean = new ContactBean();
while (dataCursor.moveToNext()) {
String result = dataCursor.getString(0);
//[4.4]根據實體類判斷數據,放入實體類中
String mimetype = dataCursor.getString(1);
if (mimetype != null) {
//[4.3]新建實體類
switch (mimetype) {
case "vnd.android.cursor.item/phone_v2"://手機號
contactBean.setPhone(result);
break;
case "vnd.android.cursor.item/email_v2"://email
contactBean.setEmail(result);
break;
case "vnd.android.cursor.item/name"://姓名
contactBean.setName(result);
break;
case "vnd.android.cursor.item/postal-address_v2"://地址
contactBean.setAddress(result);
break;
}
}
}
if (contactBean.getPhone() != null) {
contactBeans.add(contactBean);//加入集合
}
//[5.1]關閉data表Cursor
dataCursor.close();
}
}
//[5.2]關閉raw_contacts表Cursor
raw_contactsCursor.close();
return contactBeans;
}
複製代碼
/**
* 根據號碼得到聯繫人頭像
*
* @param ctx 上下文
* @param number 號碼
* @return 圖片
*/
public static Bitmap getContactPhoto(Context ctx, String number) {
Bitmap bmpHead = null;
ContentResolver resolver = ctx.getContentResolver();//得到ContentResolver對象
// 得到Uri
Uri uriNumber2Contacts = Uri.parse("content://com.android.contacts/"
+ "data/phones/filter/" + number);
// 查詢Uri,返回數據集
Cursor cursorCantacts = resolver.query(uriNumber2Contacts, null, null, null, null);
// 若是該聯繫人存在
if (cursorCantacts.getCount() > 0) {
// 移動到第一條數據
cursorCantacts.moveToFirst();
// 得到該聯繫人的contact_id
Long contactID = cursorCantacts.getLong(cursorCantacts.getColumnIndex("contact_id"));
// 得到contact_id的Uri
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactID);
// 打開頭像圖片的InputStream
InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(resolver, uri);
// 從InputStream得到bitmap
bmpHead = BitmapFactory.decodeStream(input);
}
return bmpHead;
複製代碼
下面是之前作的小項目,用到的聯繫人獲取
相信到這裏,你應道知道ContentProvider有什麼用了吧。
接下來看一下短信的ContentProvider在Android系統中是怎樣實現的。
看了一下,就這個還hold住,其餘幾個都要命的長。若是你下載了Android源碼,可見:
源碼目錄\packages\providers\TelephonyProvider\src\com\android\providers\telephony\SmsProvider.java
一共不到900行
從這裏能夠看到uri和數據庫表的相關字段
public class SmsProvider extends ContentProvider {
private static final Uri NOTIFICATION_URI = Uri.parse("content://sms");
private static final Uri ICC_URI = Uri.parse("content://sms/icc");
static final String TABLE_SMS = "sms";
static final String TABLE_RAW = "raw";
private static final String TABLE_SR_PENDING = "sr_pending";
private static final String TABLE_WORDS = "words";
static final String VIEW_SMS_RESTRICTED = "sms_restricted";
private static final Integer ONE = Integer.valueOf(1);
private static final String[] CONTACT_QUERY_PROJECTION =
new String[] { Contacts.Phones.PERSON_ID };
private static final int PERSON_ID_COLUMN = 0;
/**
* These are the columns that are available when reading SMS
* messages from the ICC. Columns whose names begin with "is_"
* have either "true" or "false" as their values.
這些列在從ICC讀取SMS消息時可用。名稱以「is_」開頭的列的值要麼爲「true」,要麼爲「false」。
*/
private final static String[] ICC_COLUMNS = new String[] {
// N.B.: 這些列的出現順序必須與要添加的調用在convertIccToSms中出現的順序相同。
"service_center_address", // getServiceCenterAddress
"address", // getDisplayOriginatingAddress
"message_class", // getMessageClass
"body", // getDisplayMessageBody
"date", // getTimestampMillis
"status", // getStatusOnIcc
"index_on_icc", // getIndexOnIcc
"is_status_report", // isStatusReportMessage
"transport_type", // Always "sms".
"type", // Always MESSAGE_TYPE_ALL.
"locked", // Always 0 (false).
"error_code", // Always 0
"_id"
};
--->private SQLiteOpenHelper mOpenHelper;//數據庫操做類
private final static String TAG = "SmsProvider";
private final static String VND_ANDROID_SMS = "vnd.android.cursor.item/sms";
private final static String VND_ANDROID_SMSCHAT =
"vnd.android.cursor.item/sms-chat";
private final static String VND_ANDROID_DIR_SMS =
"vnd.android.cursor.dir/sms";
private static final String[] sIDProjection = new String[] { "_id" };
---->操做標識符--------------------------------------------
private static final int SMS_ALL = 0;
private static final int SMS_ALL_ID = 1;
private static final int SMS_INBOX = 2;
private static final int SMS_INBOX_ID = 3;
private static final int SMS_SENT = 4;
private static final int SMS_SENT_ID = 5;
private static final int SMS_DRAFT = 6;
private static final int SMS_DRAFT_ID = 7;
private static final int SMS_OUTBOX = 8;
private static final int SMS_OUTBOX_ID = 9;
private static final int SMS_CONVERSATIONS = 10;
private static final int SMS_CONVERSATIONS_ID = 11;
private static final int SMS_RAW_MESSAGE = 15;
private static final int SMS_ATTACHMENT = 16;
private static final int SMS_ATTACHMENT_ID = 17;
private static final int SMS_NEW_THREAD_ID = 18;
private static final int SMS_QUERY_THREAD_ID = 19;
private static final int SMS_STATUS_ID = 20;
private static final int SMS_STATUS_PENDING = 21;
private static final int SMS_ALL_ICC = 22;
private static final int SMS_ICC = 23;
private static final int SMS_FAILED = 24;
private static final int SMS_FAILED_ID = 25;
private static final int SMS_QUEUED = 26;
private static final int SMS_UNDELIVERED = 27;
--------------------------------------------------------
private static final UriMatcher sURLMatcher =
new UriMatcher(UriMatcher.NO_MATCH);
--->static {//靜態代碼塊定義可操做項
---> sURLMatcher.addURI("sms", null, SMS_ALL);//null是,表示所有
sURLMatcher.addURI("sms", "#", SMS_ALL_ID);
sURLMatcher.addURI("sms", "inbox", SMS_INBOX);
sURLMatcher.addURI("sms", "inbox/#", SMS_INBOX_ID);
sURLMatcher.addURI("sms", "sent", SMS_SENT);
sURLMatcher.addURI("sms", "sent/#", SMS_SENT_ID);
sURLMatcher.addURI("sms", "draft", SMS_DRAFT);
sURLMatcher.addURI("sms", "draft/#", SMS_DRAFT_ID);
sURLMatcher.addURI("sms", "outbox", SMS_OUTBOX);
sURLMatcher.addURI("sms", "outbox/#", SMS_OUTBOX_ID);
sURLMatcher.addURI("sms", "undelivered", SMS_UNDELIVERED);
sURLMatcher.addURI("sms", "failed", SMS_FAILED);
sURLMatcher.addURI("sms", "failed/#", SMS_FAILED_ID);
sURLMatcher.addURI("sms", "queued", SMS_QUEUED);
sURLMatcher.addURI("sms", "conversations", SMS_CONVERSATIONS);
sURLMatcher.addURI("sms", "conversations/*", SMS_CONVERSATIONS_ID);
sURLMatcher.addURI("sms", "raw", SMS_RAW_MESSAGE);
sURLMatcher.addURI("sms", "attachments", SMS_ATTACHMENT);
sURLMatcher.addURI("sms", "attachments/#", SMS_ATTACHMENT_ID);
sURLMatcher.addURI("sms", "threadID", SMS_NEW_THREAD_ID);
sURLMatcher.addURI("sms", "threadID/*", SMS_QUERY_THREAD_ID);
sURLMatcher.addURI("sms", "status/#", SMS_STATUS_ID);
sURLMatcher.addURI("sms", "sr_pending", SMS_STATUS_PENDING);
sURLMatcher.addURI("sms", "icc", SMS_ALL_ICC);
sURLMatcher.addURI("sms", "icc/#", SMS_ICC);
//we keep these for not breaking old applications
sURLMatcher.addURI("sms", "sim", SMS_ALL_ICC);
sURLMatcher.addURI("sms", "sim/#", SMS_ICC);
}
複製代碼
onCreate()
方法這裏獲取了一個
MmsSmsDatabaseHelper
的數據庫操做類
@Override
public boolean onCreate() {
setAppOps(AppOpsManager.OP_READ_SMS, AppOpsManager.OP_WRITE_SMS);
mOpenHelper = MmsSmsDatabaseHelper.getInstance(getContext());
return true;
}
複製代碼
@Override
public Cursor query(Uri url, String[] projectionIn, String selection,
String[] selectionArgs, String sort) {
final boolean accessRestricted = ProviderUtil.isAccessRestricted(
getContext(), getCallingPackage(), Binder.getCallingUid());
final String smsTable = getSmsTable(accessRestricted);
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
// Generate the body of the query.---生成查詢的主體。
int match = sURLMatcher.match(url);//獲取操做標識符
switch (match) {//下面根據狀況進行查詢
case SMS_ALL:
constructQueryForBox(qb, Sms.MESSAGE_TYPE_ALL, smsTable);
break;
case SMS_UNDELIVERED:
constructQueryForUndelivered(qb, smsTable);
break;
case SMS_FAILED:
constructQueryForBox(qb, Sms.MESSAGE_TYPE_FAILED, smsTable);
break;
case SMS_QUEUED:
constructQueryForBox(qb, Sms.MESSAGE_TYPE_QUEUED, smsTable);
break;
case SMS_INBOX:
constructQueryForBox(qb, Sms.MESSAGE_TYPE_INBOX, smsTable);
break;
case SMS_SENT:
constructQueryForBox(qb, Sms.MESSAGE_TYPE_SENT, smsTable);
break;
...略
}
String orderBy = null;
if (!TextUtils.isEmpty(sort)) {//若是排序非空
orderBy = sort;//賦值
} else if (qb.getTables().equals(smsTable)) {
orderBy = Sms.DEFAULT_SORT_ORDER;//使用默認的排序
}
---> SQLiteDatabase db = mOpenHelper.getReadableDatabase();//得到SQLiteDatabase
---> Cursor ret = qb.query(db, projectionIn, selection, selectionArgs,
null, null, orderBy);//數據庫的查詢操做
ret.setNotificationUri(getContext().getContentResolver(),
NOTIFICATION_URI);
return ret;//將查詢到的Cursor返回出去
}
private void constructQueryForBox(SQLiteQueryBuilder qb, int type, String smsTable) {
qb.setTables(smsTable);
if (type != Sms.MESSAGE_TYPE_ALL) {//若是不是All,就根據傳入的類型查詢
qb.appendWhere("type=" + type);
}
}
複製代碼
@Override
public int delete(Uri url, String where, String[] whereArgs) {
int count;
int match = sURLMatcher.match(url);
---> SQLiteDatabase db = mOpenHelper.getWritableDatabase();//獲取SQLiteDatabase
switch (match) {//根據分支處理
case SMS_ALL:
count = db.delete(TABLE_SMS, where, whereArgs);//執行刪除語句
if (count != 0) {
// Don't update threads unless something changed. MmsSmsDatabaseHelper.updateAllThreads(db, where, whereArgs); } break; case SMS_ALL_ID: ... break; case SMS_CONVERSATIONS_ID: ... break; case SMS_RAW_MESSAGE: count = db.delete("raw", where, whereArgs);//執行刪除語句 break; case SMS_STATUS_PENDING: count = db.delete("sr_pending", where, whereArgs);//執行刪除語句 break; case SMS_ICC: String messageIndexString = url.getPathSegments().get(1); return deleteMessageFromIcc(messageIndexString); default: throw new IllegalArgumentException("Unknown URL"); } if (count > 0) { notifyChange(url); } return count; } 複製代碼
就分析這兩個吧,可見,就是根據Uri對應不一樣的操做, 核心仍是SQLiteDatabase的數據庫的操做,ContentProvider只是封裝一下,並暴露給全部人
5.最最重要的一點不要忘記要配置一下
SwordProvider
這個應該不多用,不是系統級的應用提供的數據你敢用?這裏稍做了解
下面進入Sqlite數據庫相關,非戰鬥人員火速備瓜...仍是拿《萬界神兵錄》的表來看吧
|--- 表分析:
數據庫名: weapon
表名: sworld
字段:
id id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
名稱 name VARCHAR(32) NOT NULL
攻擊力 atk SMALLINT UNSIGNED DEFAULT 1000
持有人 user VARCHAR(32) NOT NULL
|--- 建表語句
CREATE TABLE sword (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name VARCHAR(32) NOT NULL,
atk SMALLINT UNSIGNED NOT NULL DEFAULT 1000,
user VARCHAR(32) NOT NULL,
);
複製代碼
ContentProvider是一個抽象類,須要實現下面幾個方法
/**
* 做者:張風捷特烈<br/>
* 時間:2019/2/28/028:11:42<br/>
* 郵箱:1981462002@qq.com<br/>
* 說明:萬界神兵錄
*/
public class SwordProvider extends ContentProvider {
@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) {
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
}
複製代碼
我是根據
MmsSmsDatabaseHelper
源碼來寫的,畢竟是大佬寫的,參考一下書寫風格
public class SwordDatabaseHelper extends SQLiteOpenHelper {
private static String DATABASE_NAME = "weapon.db";//數據庫名
private static int DATABASE_VERSION = 1;//數據庫版本
private static SwordDatabaseHelper sInstance;
//雙檢鎖單例
public static synchronized SwordDatabaseHelper getInstance(Context context) {
if (sInstance == null) {
synchronized (SwordDatabaseHelper.class) {
if (sInstance == null) {
sInstance = new SwordDatabaseHelper(context);
}
}
}
return sInstance;
}
public SwordDatabaseHelper(@Nullable Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
createSwordTable(db);
}
/**
* 建立sword表
*
* @param db SQLiteDatabase
*/
private void createSwordTable(SQLiteDatabase db) {
db.execSQL("CREATE TABLE sword (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
"name VARCHAR(32) NOT NULL," +
"atk INTEGER DEFAULT 1000," +
"user VARCHAR(32) NOT NULL" +
"); ");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
複製代碼
也就是sql的基礎語法
SwordDatabaseHelper helper = new SwordDatabaseHelper(this);
SQLiteDatabase db = helper.getWritableDatabase();
|-- 插入測試
db.execSQL("INSERT INTO sword(name,atk,user) VALUES" +
"('絕世好劍',7000,'步驚雲')");
|-- 修改測試
db.execSQL("UPDATE sword SET atk=3500 WHERE id=1");
|-- 查詢測試
Cursor cursor = db.rawQuery("SELECT * FROM sword", null);
while (cursor.moveToNext()) {
String id = cursor.getString(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String atk = cursor.getString(cursor.getColumnIndex("atk"));
String user = cursor.getString(cursor.getColumnIndex("user"));
Log.e(TAG, "rawQuery: "+id + "---" + name + "---" + atk + "---" + user );
//rawQuery: 1---絕世好劍---3500---步驚雲
}
cursor.close();//關閉遊標
|-- 刪除測試
db.execSQL("DELETE FROM sword WHERE id=1");
複製代碼
既然測試ok,那就去實現一下ContentProvider的幾個方法,uri就設定爲增刪改查四個...
規則能夠本身設定,在方法裏均可以根據sUriMatcher.match(uri)
獲取對應碼來區別處理
/**
* 做者:張風捷特烈<br/>
* 時間:2019/2/28/028:11:42<br/>
* 郵箱:1981462002@qq.com<br/>
* 說明:萬界神兵錄
*/
public class SwordProvider extends ContentProvider {
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private static final int SWORD_QUERY = 0;
private static final int SWORD_INSERT = 1;
private static final int SWORD_UPDATE = 2;
private static final int SWORD_DELETE = 3;
private static final String TABLE_NAME = "sword";
static {
//給當前sUriMatcher添加匹配規則
sUriMatcher.addURI("toly1994.com.sword", "query", SWORD_QUERY);
sUriMatcher.addURI("toly1994.com.sword", "insert", SWORD_INSERT);
sUriMatcher.addURI("toly1994.com.sword", "update", SWORD_UPDATE);
sUriMatcher.addURI("toly1994.com.sword", "delete", SWORD_DELETE);
}
private SQLiteOpenHelper mOpenHelper;
@Override
public boolean onCreate() {
mOpenHelper = SwordDatabaseHelper.getInstance(getContext());
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
//進行uri匹配
int result = sUriMatcher.match(uri);
if (result == SWORD_QUERY) {
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
return db.query(TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
} else {
throw new IllegalStateException(" query Uri 錯誤");
}
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
//進行uri匹配
int result = sUriMatcher.match(uri);
if (result == SWORD_INSERT) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Long insert = db.insert(TABLE_NAME, null, values);
//uri:數據發送變化,經過uri判斷調用哪一個內容觀察者
//第二個參數:內容觀察者對象 若是傳null 則註冊了整個uri的內容觀察者皆能夠收到通知
getContext().getContentResolver().notifyChange(uri, null);
db.close();
return Uri.parse(String.valueOf(insert));
} else {
throw new IllegalStateException("insert Uri 錯誤");
}
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
//進行uri匹配
int result = sUriMatcher.match(uri);
if (result == SWORD_DELETE) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int delete = db.delete(TABLE_NAME, selection, selectionArgs);
db.close();
return delete;
} else {
throw new IllegalStateException("delete Uri 錯誤");
}
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
//進行uri匹配
int result = sUriMatcher.match(uri);
if (result == SWORD_UPDATE) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int update = db.update(TABLE_NAME, values, selection, selectionArgs);
db.close();
return update;
} else {
throw new IllegalStateException("update Uri 錯誤");
}
}
}
複製代碼
<provider
android:name=".provider.swordProvider.SwordProvider"
android:authorities="toly1994.com.sword"
android:exported="true"/>
複製代碼
你應該清楚,上面就至關於系統的SmsProvider,用於提供一個可供全局操做的數據庫
經測試,是可用的,也就是
另外一個app
能夠操做剛纔應用中的數據庫
/**
* 做者:張風捷特烈<br/>
* 時間:2019/2/27/027:19:52<br/>
* 郵箱:1981462002@qq.com<br/>
* 說明:另外一個app測試SwordProvider
*/
public class SwordProviderActivity extends AppCompatActivity {
private static final String TAG = "SwordProviderActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ContentResolver resolver = getContentResolver();
// insert(resolver); //插入測試
// query(resolver);//查詢測試
update(resolver);//更新測試
query(resolver);
delete(resolver);//刪除測試
query(resolver);
}
/**
* 刪除測試
*
* @param resolver
*/
private void delete(ContentResolver resolver) {
Uri uri = Uri.parse("content://toly1994.com.sword/delete");
resolver.delete(uri, "name=?", new String[]{"屠龍刀"});
}
/**
* 插入測試
*
* @param resolver
*/
private void insert(ContentResolver resolver) {
Uri uri = Uri.parse("content://toly1994.com.sword/insert");
ContentValues values = new ContentValues();
values.put("name", "屠龍刀");
values.put("atk", "3000");
values.put("user", "張無忌");
resolver.insert(uri, values);
}
/**
* 更新測試
*
* @param resolver
*/
private void update(ContentResolver resolver) {
Uri uri = Uri.parse("content://toly1994.com.sword/update");
ContentValues values = new ContentValues();
values.put("name", "屠龍刀");
values.put("atk", "3500");
values.put("user", "張無忌");
resolver.update(uri, values, "name=?", new String[]{"屠龍刀"});
}
/**
* 查詢測試
*
* @param resolver
*/
private void query(ContentResolver resolver) {
Uri uri = Uri.parse("content://toly1994.com.sword/query");
Cursor cursor = resolver.query(uri, null, null, null, null);
while (cursor.moveToNext()) {//遍歷遊標,獲取數據,儲存在bean中
int id = cursor.getInt(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
int atk = cursor.getInt(cursor.getColumnIndex("atk"));
String user = cursor.getString(cursor.getColumnIndex("user"));
Log.e(TAG, "query: " + id + "---" + name + "---" + atk + "---" + user);
//query: 2---屠龍刀---3000---張無忌
}
}
}
複製代碼
至於ContentProvider的內部實現原理暫時尚未興趣,未提上日程
好了,到此爲止,安卓的四大組件就從新總結了一遍,這是第二次終結
四大組件的幾篇文章都用一個工程測試的,Github地址:歡迎star