編輯:關於Android編程
內容提供器(Content Provider)主要用於在不同的應用程序之間共享數據,雖然Android提供的文件存儲和SharePreferences都可以設置全局讀寫模式共享數據,但由於安全性問題,已經在Android4.2中被廢棄。內容提供器將提供一種安全的數據共享方式。當一個程序通過內容提供器提供了外部訪問接口,其他任何程序都可以通過該接口來對這部分數據進行訪問,例如:聯系人數據,短信數據。
一、訪問其他應用程序中的數據
1 . 獲得ContentResolver類的實例
對於每一個應用程序,如果想要訪問內容提供器中的數據,就必須要借助於ContentResolver類,可以通過Context中的getContentResolver()放法獲得該類的實例。
ContentResolver類中提供了類似於SQLite中類似的insert()、delete()、update()、query()等方法實現對數據的增刪改查,但是參數與SQLite中的參數略有不同。
注:ContentResolver中的增刪改查方法都是不接受表名參數的,而是使用Uri參數代替,這個參數被稱為內容URI。
2 . 獲得內容URI
內容URI給內容提供器中的參數建立了唯一標識符,它主要由權限和路徑兩部分組成,權限主要是為了區分不同的應用程序,一般使用程序包名。比如:com.example.app.provider。路徑則是對同一應用程序中不同的表進行區分,以/+表名的方式接在權限的後面。最後我餓還需要加上協議聲明才組成了完整的內容URI。
內容URI標准格式
content://com.example.app.provider/table1
content://com.example.app.provider/table2
3 . 將URI字符串解析為Uri對象
Uri uri = Uri.parse("content://com.example.app.provider/table1");
4 . 對數據進行增刪改查
//插入數據
ContentValues values1 = new ContentValues();
values1.put("column1", "text1");
values1.put("column2", "text2");
getContentResolver().insert(uri, values1);
//刪除數據
getContentResolver().delete(uri, "cloumn2=?", new String[]{"1"});
//修改數據
ContentValues values2 = new ContentValues();
values2.put("column1", "t");
getContentResolver().update(uri, values2, "column1 = ? and column2=?", new String[]{"text", "1"});
//查詢數據
Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);
if (cursor != null){
while (cursor.moveToNext()){
String column1 = cursor.getString(cursor.getColumnIndex("column1"));
int column2 = cursor.getInt(cursor.getColumnIndex("column2"));
}
cursor.close();
}
上面的操作和SQLite的操作十分類似,只是傳入的參數不再是表名,而是解析出來的Uri對象。
下面重點介紹query()中各參數的意義
下面放上一個獲取聯系人信息的小例子
MainActivity.java中的代碼
public class MainActivity extends AppCompatActivity {
private ListView contactsView;
private ArrayAdapter adapter;
private List contactsList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
contactsView = (ListView) findViewById(R.id.contacts_view);
adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, contactsList);
contactsView.setAdapter(adapter);
readContacts();
}
private void readContacts() {
Cursor cursor = null;
try{
//查詢聯系人數據
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
while(cursor.moveToNext()){
//獲取聯系人姓名
String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
//獲取聯系人手機號
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
contactsList.add(displayName + "\n" + number);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (cursor != null){
cursor.close();
}
}
}
}
activity_main.xml文件
上面的代碼中的Uri對象並不是通過parse()方法解析,是因為官方向我們直接提供了解析好的Uri對象。我們獲取到手機聯系人姓名和電話號碼後簡單地顯示在了ListView中。
二、創建自己的內容提供器
上面我們使用別人提供的內容提供器來獲取其他程序共享的數據,下面我們將創建自己的內容提供器來共享自己應用程序中的數據。下面是基本的步驟
1 . 創建一個類去繼承ContentProvider,重寫其中的6個抽象方法。
下面簡單介紹這6個方法(與SQLite中的方法很類似)
1 . onCreate() ——- 初始化內容提供器的時候調用。通常在這裡完成數據庫的額創建或升級等操作。返回true表示內容提供器初始化成功,返回false表示失敗。
注:只有當有ContentResolver嘗試訪問我們程序中的數據時,內容提供器才會被初始化。
2 . query() —–從內容提供器中來查詢數據,query方法的參數已經在上面的表格中做了詳細說明。
3 . insert() —– 向內容提供器中添加一條數據,使用方法咋在上面的代碼中已經有介紹。
4 . update() —– 更新內容提供器中已有的數據。
5 . delete() —– 從內容提供器中刪除數據
6 . getType() —– 根據傳入的URI來返回響應的MIME類型。
2 . 分析內容URI。
標准的內容URI(以路徑結尾,表示期望訪問表中的所有數據):
content://com.example.app.provider/table
含有id的內容URI(以id結尾,表示訪問表中擁有相應id的數據):
content://com.example.app.provider/table/1
為了下一步准確解析這兩種內容URI,我們還必須使用通配符來匹配上面兩種模式。
1 . * ——- 表示匹配任意長度的任意字符
2 . # ——- 表示匹配任意長度的數字
//匹配上面第一行內容URI(所有數據)
content://com.example.app.provider/table/*
//匹配上面第二種URI(相應id的數據)
content://com.example.app.provider/table/#
3 . 借助於UriMatcher類實現匹配內容URI。
上面我們已經分析了內容URI,接下來我們借助於UriMatcher類提供的addURI()方法,分別依次傳入三個參數(權限、路徑,自定義代碼(標識))。最後我們再調用UriMatcher的match()方法,傳入一個Uri對象,就會返回我們剛剛傳入的自定義代碼(標識),我們以此來判斷調用方想訪問數據的意圖。
public class MyProvider extends ContentProvider {
//自定義代碼
public static final int TABLE1_DIR = 0;
public static final int TABLE1_ITEM = 1;
private static UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//期望查詢所有數據
uriMatcher.addURI("com.example.app.provider", "table1", TABLE1_DIR);
//期望查詢相應id的數據
uriMatcher.addURI("com.example.app.provider", "table1/#", TABLE1_ITEM);
}
@Nullable
@Override
public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) {
switch (uriMatcher.match(uri)){
case TABLE1_DIR:
//查詢所有數據
break;
case TABLE1_ITEM:
//查詢單條數據
break;
default:
break;
}
return null;
}
}
上面的代碼只是簡單演示了在query()方法中的重寫,對於insert()、update()、delete()中的重寫都是類似的,都是從Uri對象中獲得自定義代碼,得到訪問數據者的意圖後寫相應的邏輯。
4 . 重寫getType()方法。
getType()方法是所有內容提供器都必須提供的一個方法,用於獲取Uri對象所對應的MIME類型,一個內容URI所對應的MIME類型字符串有三部分組成。Android做了如下規定:
1 . 必須以vnd開頭
2 . 如果內容URI以路徑結尾,則後面接android.cursor.dir/,如果內容URI以id結尾,則後接android.cursor.item/
3 . 最後接vnd.<權限>.<路徑>
//內容URI以路徑結尾
vnd.android.cursor.dir/vnd.com.example.app.provider.table1
//內容URI以id結尾
vnd.android.cursor.item/vnd.com.example.app.provider.table1
@Nullable
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)){
case TABLE1_DIR:
return "vnd.android.cursor.dir/vnd.com.example.app.provider.table1";
case TABLE1_ITEM:
return "vnd.android.cursor.item/vnd.com.example.app.provider.table1";
}
return null;
}
從上面的內容我們也會發現,內容提供器之所以可以保證數據的安全性,是因為要想對數據進行增刪改查,我們都首先需要匹配到內容URI格式才可以,只要我們不把隱私數據添加進UriMatcher中,我們的隱私數據就不會被訪問到。
感覺android中的toast效果挺不錯的,就試著自己用2dx做了一下,挺簡單的,效果也不錯。 XYToast.h #pragma once #include co
Android作為目前主流的移動操作系統,完全符合SQLite占用資源少的優勢,故在Android平台上,集成了一個嵌入式關系型數據庫—SQLite。如果想要開發 And
Android Emulator 給用戶提供 GPU on 選項,意思是利用 Host ( 就是運行 Emulator 的PC機) 的 GPU. 當然PC機必須把 Op
1. 默認為debug mode,使用的簽名文件在: $HOME/.android/debug.keystore 2. Release Mode 簽