Android 第九天重置版_Contentprovider_注意事項


為什么需要內容提供者:


第六點就是為什么需要內容提供者


SQLiteDatabase.openDatabase(path, factory, flags)

可以通過這個方法打開一個數據庫的文件。但是這個數據庫文件必須是其他用戶可以使用的權限  -rwx(當前用戶權限) rwx(當前用戶組權限) rwx其他用戶權限) 


我們可以使用cursor.getColumnIndex("列名")來返回你指定列名的 索引.

這樣的好處就是當我們 不知道索引的情況下 也可以查找出內容。


我們為了實現訪問另外一個應用程序中的數據庫的內容。可以使用上面的方式。

但是這種方式不是 Android 推薦的方式。


所以我們要使用內容提供者。

————————————————————————————————

內容提供者原理:



————————————————————————————————

實現內容提供者的步驟:


<span style="font-size:18px;">public class AccountProvider extends ContentProvider {



//[1]定一個一個uri路徑匹配器
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private static final int QUERYSUCESS = 0; //ctrl+shift+X 變大寫 小寫加y
private static final int INSERTSUCESS = 1;
private static final int UPDATESUCESS = 2;
private static final int DELETESUCESS = 3;
private MyOpenHelper myOpenHelper;
//[2]創建一個靜態代碼塊 在這個里面添加 uri
static{

/**
* http://www.baidu.com
* authority 注意: 和清單文件里面定義的一樣 com.itheima.provider/query
*
*/
sURIMatcher.addURI("com.itheima.provider", "query", QUERYSUCESS);
sURIMatcher.addURI("com.itheima.provider", "insert", INSERTSUCESS);
sURIMatcher.addURI("com.itheima.provider", "update", UPDATESUCESS);
sURIMatcher.addURI("com.itheima.provider", "delete", DELETESUCESS);
}


//當內容提供者初始化 會執行此方法
@Override
public boolean onCreate() {

//[3]初始化 myopenHelpler 對象 就可以獲取到sqlitedatabases對象 我們就可以操作數據庫

myOpenHelper = new MyOpenHelper(getContext());

return false;
}

//這個方法對外暴露的
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
int code = sURIMatcher.match(uri);
if (code ==QUERYSUCESS ) {
//說明路徑匹配成功
SQLiteDatabase db = myOpenHelper.getReadableDatabase();
//調用query方法
Cursor cursor = db.query("info", projection, selection, selectionArgs, null, null, sortOrder);

//發送一條消息 說明說明數據庫被操作了
getContext().getContentResolver().notifyChange(uri, null);


//db.close();
//小細節 ☆ 這個cursor不能關
return cursor;

}else{
//說明路徑不匹配
//return null;
throw new IllegalArgumentException("哥們 :uri路徑不匹配 請檢測路徑");

}


}

@Override
public String getType(Uri uri) {
return null;
}

@Override
public Uri insert(Uri uri, ContentValues values) {

int code = sURIMatcher.match(uri);
if (code == INSERTSUCESS) {
//說明路徑匹配成功
SQLiteDatabase db = myOpenHelper.getReadableDatabase();

long insert = db.insert("info", null, values);
Uri uri2 = Uri.parse("com.hahaheheheihei/"+insert);

if (insert>0) {
//發送一條消息 說明說明數據庫被操作了
getContext().getContentResolver().notifyChange(uri, null);
}


db.close();//關閉數據庫
return uri2;

}else {
throw new IllegalArgumentException("姐們 :uri路徑不匹配 請檢測路徑");
}


}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {

int code = sURIMatcher.match(uri);
if (code == DELETESUCESS) {
//匹配成功
SQLiteDatabase db = myOpenHelper.getReadableDatabase();


//代表影響的行數
int delete = db.delete("info", selection, selectionArgs);

if (delete>0) {
//發送一條消息 說明說明數據庫被操作了
getContext().getContentResolver().notifyChange(uri, null);

}

return delete;

}

return 0;
}

@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int code = sURIMatcher.match(uri);

if (code == UPDATESUCESS) {
//路徑匹配成功
SQLiteDatabase db = myOpenHelper.getWritableDatabase();

//代表影響的行數
int update = db.update("info", values, selection, selectionArgs);
if(update>0){
//發送一條消息 說明說明數據庫被操作了
getContext().getContentResolver().notifyChange(uri, null);

}



return update;


}else{
throw new IllegalArgumentException("大爺:uri路徑不匹配 請檢測路徑");

}


}

}
</span>


<span style="font-size:18px;">public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


}


//點擊按鈕 往數據庫里面插入一條數據
public void click1(View v){
//因為第一個應用里面的私有的數據庫 已經通過內容提供者暴露出來了 所以通過內容解析者去獲取數據
Uri uri = Uri.parse("content://com.itheima.provider/insert");
ContentValues values = new ContentValues(); //實際是map
//key: 代表列名 value 對應的值
values.put("name", "zhaoliu");
values.put("money", 1000);
//插入一條數據
Uri uri2 = getContentResolver().insert(uri, values);

System.out.println("uri2:"+uri2);



}

//點擊按鈕刪除 趙六刪掉
public void click2(View v){
//[1]獲取內容的解析者
Uri uri = Uri.parse("content://com.itheima.provider/delete");
//[2]代表影響的函數
int delete = getContentResolver().delete(uri, "name=?", new String[]{"zhaoliu"});
Toast.makeText(getApplicationContext(), "刪除了"+delete+"行", 1).show();

}

//給趙六多點錢 1000元
public void click3(View v){
//[1] 創建uri
Uri uri = Uri.parse("content://com.itheima.provider/update");
//[2]獲取內容的解析者
ContentValues values = new ContentValues();
values.put("money", "10000000");
int update = getContentResolver().update(uri, values, "name=?",new String[]{"zhaoliu"});
Toast.makeText(getApplicationContext(), "更新了"+update+"行", 1).show();

}


//點擊按鈕 查詢第一個應用里面數據庫的信息
public void click4(View v){
// 第二種 查詢方式 因為第一個應用里面的私有的數據庫 已經通過內容提供者暴露出來了 所以通過內容解析者去獲取數據
Uri uri = Uri.parse("content://com.itheima.provider/query");
//通過內容解析者獲取數據
Cursor cursor = getContentResolver().query(uri, new String[]{"name","money"}, null, null, null);
if (cursor!=null) {

while(cursor.moveToNext()){
String name = cursor.getString(0);
String money = cursor.getString(1);

System.out.println("第二個應用:"+name+"---"+money);

}
}

}



}</span>


————————————————————————————————

備份短信案例:


當我們看見包名有providers 時候,我們就應該知道  這些內容已經通過內容提供者暴露出來了。我們只要使用內容解析者接收 就可以了。


//點擊按鈕查詢短信內容 然后把短信內容進行備份
public void click(View v) {

try {
//[1]獲取XmlSerializer的實例
XmlSerializer serializer = Xml.newSerializer();
//[2]設置序列化器參數
File file = new File(Environment.getExternalStorageDirectory().getPath(),"smsbackup.xml");
FileOutputStream fos = new FileOutputStream(file);
serializer.setOutput(fos, "utf-8");
//[3]寫xml文檔開頭
serializer.startDocument("utf-8", true);

//[4]寫xml的根節點
serializer.startTag(null, "smss");
//[5]構造uri
Uri uri = Uri.parse("content://sms/");

//[6]由於短信的數據庫已經通過內容提供者暴露出來 所以我們直接通過內容解析者查詢
Cursor cursor = getContentResolver().query(uri, new String[]{"address","date","body"}, null, null, null);
while(cursor.moveToNext()){
String address = cursor.getString(0);
String date = cursor.getString(1);
String body = cursor.getString(2);

//[7]寫sms節點
serializer.startTag(null, "sms");
//[8]寫address節點
serializer.startTag(null, "address");
serializer.text(address);
serializer.endTag(null, "address");

//[9]寫date節點
serializer.startTag(null, "date");
serializer.text(date);
serializer.endTag(null, "date");
//[10]寫body節點
serializer.startTag(null, "body");
serializer.text(body);
serializer.endTag(null, "body");

serializer.endTag(null, "sms");

}

serializer.endTag(null, "smss");
serializer.endDocument();
fos.close();

} catch (Exception e) {
e.printStackTrace();
}





}



這里的Uri.parse("content://")前面是默認的寫法。后面就是在 內容提供者里面定義的。

記住要加權限:android.permission.READ_SMS

                        android.permission.WRITE_SMS

————————————————————————————————

利用內容提供者插入短信:


————————————————————————————————

讀取聯系人案例:

記住要加權限:android.permission.READ_CONTACTS

                        android.permission.WRITE_CONTACTS

注意一點,谷歌工程師設計的聯系人刪除的時候,只是把raw_contact表 中的raw_contact_id 設置為空。但是 實際的數據並沒有刪除。

所以我們在查詢contact_id的時候要判斷是否為空.


//查詢聯系人的工具類
public class QueryContactsUtils {


public static List<Contact> queryContacts(Context context){
//[0]創建一個集合

List<Contact> contactLists = new ArrayList<Contact>();
//[1]先查詢row_contacts表 的contact_id列 我們就知道一共有幾條聯系人
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri dataUri = Uri.parse("content://com.android.contacts/data");
Cursor cursor = context.getContentResolver().query(uri,new String[]{"contact_id"} , null, null, null);
while(cursor.moveToNext()){
String contact_id = cursor.getString(0);


if (contact_id!=null) {
//創建javabean對象
Contact contact = new Contact();

contact.setId(contact_id);

System.out.println("contact_id:"+contact_id);
//[2]根據contact_id去查詢data表 查詢data1列和mimetype_id

//☆ ☆ ☆ ☆ 當我們在查詢data表的時候 其實查詢的是view_data的視圖

Cursor dataCursor = context.getContentResolver().query(dataUri, new String[]{"data1","mimetype"}, "raw_contact_id=?", new String[]{contact_id}, null);
while(dataCursor.moveToNext()){
String data1 = dataCursor.getString(0);
String mimetype = dataCursor.getString(1);
//[3]根據mimetype 區分data1列的數據類型
if ("vnd.android.cursor.item/name".equals(mimetype)) {
contact.setName(data1);
}else if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) {
contact.setPhone(data1);
}else if ("vnd.android.cursor.item/email_v2".equals(mimetype)) {
contact.setEmail(data1);
}


}

//把javabean對象加入到集合中
contactLists.add(contact);
}

}

return contactLists;

}

}
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);List<Contact> queryContacts = QueryContactsUtils.queryContacts(getApplicationContext());for (Contact contact : queryContacts) {System.out.println("contat:"+contact);}}}

public void click(View v) {
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri dataUri = Uri.parse("content://com.android.contacts/data");

//[2]獲取name phone email Textutils
String name = et_name.getText().toString().trim();
String phone = et_phone.getText().toString().trim();
String email = et_email.getText().toString().trim();

//[2.1]在插入聯系人id的時候 先查詢一下 row_contact 一共有幾條數據 加+1就是聯系人的id
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
int count = cursor.getCount();
int contact_id = count +1;

//[3] 先往row_contact表 插入聯系人的id (contact_id)
ContentValues values = new ContentValues();
values.put("contact_id", contact_id);
getContentResolver().insert(uri,values);

//[4]在把name phone email 插入到data表
ContentValues nameValues = new ContentValues();
nameValues.put("data1", name);
//☆ ☆ ☆ ☆ ☆ 插入的數據要告訴數據庫 屬於第幾條聯系人 和 數據類型
nameValues.put("raw_contact_id", contact_id);
nameValues.put("mimetype", "vnd.android.cursor.item/name");
getContentResolver().insert(dataUri, nameValues);

//[5]把phone號碼 插入到data表
ContentValues phoneValues = new ContentValues();
phoneValues.put("data1", phone);
phoneValues.put("mimetype", "vnd.android.cursor.item/phone_v2");
phoneValues.put("raw_contact_id", contact_id);
getContentResolver().insert(dataUri, phoneValues);


//[5]把phone號碼 插入到data表
ContentValues emailValues = new ContentValues();
emailValues.put("data1", email);
emailValues.put("mimetype", "vnd.android.cursor.item/email_v2");
emailValues.put("raw_contact_id", contact_id);
getContentResolver().insert(dataUri, emailValues);

}


注意一點:

我們查詢的data表,其實是查詢view_data表,所以當你去查詢mimetype_id的時候

你會發現報錯,因為view-data表沒有這個數據。 所以我們應該查詢mimetype的數據。


還有data表中的raw-contacts_id 就是就是raw-contacts表中的 contacts-id的數據.

————————————————————————————————

內容觀察者原理:


注意:內容觀察者不是四大組件之一,不需要再清單文件中配置。




————————————————————————————————

內容觀察者引用場景:

短信監聽




注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com