編輯:關於Android編程
ContentProvider(內容提供者)是Android的四大組件之一,管理android以結構化方式存放的數據,以相對安全的方式封裝數據(表)並且提供簡易的處理機制和統一的訪問接口供其他程序調用。
Android的數據存儲方式總共有五種,分別是:Shared Preferences、網絡存儲、文件存儲、外儲存儲、SQLite。但一般這些存儲都只是在單獨的一個應用程序之中達到一個數據的共享,有時候我們需要操作其他應用程序的一些數據,就會用到ContentProvider。而且Android為常見的一些數據提供了默認的ContentProvider(包括音頻、視頻、圖片和通訊錄等)。
但注意ContentProvider它也只是一個中間人,真正操作的數據源可能是數據庫,也可以是文件、xml或網絡等其他存儲方式。
URL(統一資源標識符)代表要操作的數據,可以用來標識每個ContentProvider,這樣你就可以通過指定的URI找到想要的ContentProvider,從中獲取或修改數據。
在Android中URI的格式如下圖所示:
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCqPBPGJyIC8+DQqhoTxiciAvPg0KoaGhoaGhc2NoZW1ho6zS0b6t08lBbmRyb2lky/m55raozqqjumNvbnRlbnQ6Ly+jrqGhPGJyIC8+DQqhoaGhoaENCjxwPqPCPC9wPg0KPHA+oaGhoaGh1ve7+sP7o6hBdXRob3JpdHmjqaOsysdVUkm1xMrayKiyv7fWo6zKx86o0rux6sq2t/ujrNPDwLS2qM67Q29udGVudFByb3ZpZGVyoaM8L3A+DQo8YmxvY2txdW90ZT4NCgk8cD6jw7K/t9a6zUSyv7fWo7rKx8O/uPZDb250ZW50UHJvdmlkZXLE2rK/tcTCt762sr+31jwvcD4NCjwvYmxvY2txdW90ZT4NCjxwPqPDPC9wPg0KPHA+oaGhoaGh1rjP8tK7uPa21M/zvK+6z6Os0ruw49PDse21xMP719ajrMjnufvDu9PQ1ri2qESyv7fWo6zU8re1u9jIq7K/vMfCvKGjPC9wPg0KPHA+o8Q8L3A+DQo8cD6hoaGhoaHWuM/yzNi2qLXEvMfCvKOs1eLA77Htyr6y2df3dXNlcrHtaWTOqje1xLzHwryho8jnufvSqrLZ1/d1c2Vyse3W0Glkzqo3tcS8x8K8tcRuYW1l19a2zqOsIESyv7fWseTOqiA8c3Ryb25nPi83L25hbWU8L3N0cm9uZz68tL/JoaM8L3A+DQo8YmxvY2txdW90ZT4NCgk8cD5VUknEo8q9xqXF5M2oxeS3+zwvcD4NCgk8cD4qo7rGpcXktcTIztLis6S2yLXEyM66ztPQ0KfX1rf7tcTX1rf7tK6hozwvcD4NCgk8cD6jo6O6xqXF5LXEyM7S4rOktsi1xMr919bX1rf7tcTX1rf7tK6hozwvcD4NCgk8cD7I56O6PC9wPg0KCTxwPmNvbnRlbnQ6Ly9jb20uZXhhbXBsZS5hcHAucHJvdmlkZXIvKjxiciAvPg0KCcalxeRwcm92aWRlcrXEyM66zsTayN11cmw8L3A+DQoJPHA+Y29udGVudDovL2NvbS5leGFtcGxlLmFwcC5wcm92aWRlci90YWJsZTMvIzxiciAvPg0KCcalxeR0YWJsZTO1xMv509DQ0DwvcD4NCjwvYmxvY2txdW90ZT4NCjxoMiBpZD0="21mime">2.1MIME
MIME是指定某個擴展名的文件用一種應用程序來打開,就像你用浏覽器查看PDF格式的文件,浏覽器會選擇合適的應用來打開一樣。Android中的工作方式跟HTTP類似,ContentProvider會根據URI來返回MIME類型,ContentProvider會返回一個包含兩部分的字符串。MIME類型一般包含兩部分,如:
text/html
text/css
text/xml
application/pdf
分為類型和子類型,Android遵循類似的約定來定義MIME類型,每個內容類型的Android MIME類型有兩種形式:多條記錄(集合)和單條記錄。
集合記錄:
vnd.android.cursor.dir/自定義
單條記錄:
vnd.android.cursor.item/自定義
vnd表示這些類型和子類型具有非標准的、供應商特定的形式。Android中類型已經固定好了,不能更改,只能區別是集合還是單條具體記錄,子類型可以按照格式自己填寫。
在使用Intent時,會用到MIME,根據Mimetype打開符合條件的活動。
下面分別介紹Android系統提供了兩個用於操作Uri的工具類:ContentUris和UriMatcher。
ContetnUris包含一個便利的函數withAppendedId()來向URI追加一個id。
Uri uri = Uri.parse("content://cn.scu.myprovider/user")
Uri resultUri = ContentUris.withAppendedId(uri, 7);
//生成後的Uri為:content://cn.scu.myprovider/user/7
同時提供parseId(uri)方法用於從URL中獲取ID:
Uri uri = Uri.parse("content://cn.scu.myprovider/user/7")
long personid = ContentUris.parseId(uri);
//獲取的結果為:7
UriMatcher本質上是一個文本過濾器,用在contentProvider中幫助我們過濾,分辨出查詢者想要查詢哪個數據表。
舉例說明:
第一步,初始化:
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
//常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼
第二步,注冊需要的Uri:
//USER 和 USER_ID是兩個int型數據
matcher.addURI("cn.scu.myprovider", "user", USER);
matcher.addURI("cn.scu.myprovider", "user/#",USER_ID);
//如果match()方法匹配content://cn.scu.myprovider/user路徑,返回匹配碼為USER
第三部,與已經注冊的Uri進行匹配:
/*
* 如果操作集合,則必須以vnd.android.cursor.dir開頭
* 如果操作非集合,則必須以vnd.android.cursor.item開頭
* */
@Override
public String getType(Uri uri) {
Uri uri = Uri.parse("content://" + "cn.scu.myprovider" + "/user");
switch(matcher.match(uri)){
case USER:
return "vnd.android.cursor.dir/user";
case USER_ID:
return "vnd.android.cursor.item/user";
}
}
public boolean onCreate()
ContentProvider創建後 或 打開系統後其它應用第一次訪問該ContentProvider時調用。
public Uri insert(Uri uri, ContentValues values)
外部應用向ContentProvider中添加數據。
public int delete(Uri uri, String selection, String[] selectionArgs)
外部應用從ContentProvider刪除數據。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):
外部應用更新ContentProvider中的數據。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
供外部應用從ContentProvider中獲取數據。
public String getType(Uri uri)
該方法用於返回當前Url所代表數據的MIME類型。
ContentResolver通過URI來查詢ContentProvider中提供的數據。除了URI以 外,還必須知道需要獲取的數據段的名稱,以及此數據段的數據類型。如果你需要獲取一個特定的記錄,你就必須知道當前記錄的ID,也就是URI中D部分。
ContentResolver 類提供了與ContentProvider類相同簽名的四個方法:
public Uri insert(Uri uri, ContentValues values) //添加
public int delete(Uri uri, String selection, String[] selectionArgs) //刪除
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) //更新
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)//獲取
實例代碼:
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://cn.scu.myprovider/user");
//添加一條記錄
ContentValues values = new ContentValues();
values.put("name", "fanrunqi");
values.put("age", 24);
resolver.insert(uri, values);
//獲取user表中所有記錄
Cursor cursor = resolver.query(uri, null, null, null, "userid desc");
while(cursor.moveToNext()){
//操作
}
//把id為1的記錄的name字段值更改新為finch
ContentValues updateValues = new ContentValues();
updateValues.put("name", "finch");
Uri updateIdUri = ContentUris.withAppendedId(uri, 1);
resolver.update(updateIdUri, updateValues, null, null);
//刪除id為2的記錄
Uri deleteIdUri = ContentUris.withAppendedId(uri, 2);
resolver.delete(deleteIdUri, null, null);
ContentObserver(內容觀察者),目的是觀察特定Uri引起的數據庫的變化,繼而做一些相應的處理,它類似於數據庫技術中的觸發器(Trigger),當ContentObserver所觀察的Uri發生變化時,便會觸發它.
下面是使用內容觀察者監聽短信的例子:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注冊觀察者Observser
this.getContentResolver().registerContentObserver(Uri.parse("content://sms"),true,new SMSObserver(new Handler()));
}
private final class SMSObserver extends ContentObserver {
public SMSObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
Cursor cursor = MainActivity.this.getContentResolver().query(
Uri.parse("content://sms/inbox"), null, null, null, null);
while (cursor.moveToNext()) {
StringBuilder sb = new StringBuilder();
sb.append("address=").append(
cursor.getString(cursor.getColumnIndex("address")));
sb.append(";subject=").append(
cursor.getString(cursor.getColumnIndex("subject")));
sb.append(";body=").append(
cursor.getString(cursor.getColumnIndex("body")));
sb.append(";time=").append(
cursor.getLong(cursor.getColumnIndex("date")));
System.out.println("--------has Receivered SMS::" + sb.toString());
}
}
}
}
同時可以在ContentProvider發生數據變化時調用
getContentResolver().notifyChange(uri, null)來通知注冊在此URI上的訪問者。
public class UserContentProvider extends ContentProvider {
public Uri insert(Uri uri, ContentValues values) {
db.insert("user", "userid", values);
getContext().getContentResolver().notifyChange(uri, null);
}
}
數據源是SQLite, 用ContentResolver操作ContentProvider。
Constant.java(儲存一些常量)
public class Constant {
public static final String TABLE_NAME = "user";
public static final String COLUMN_ID = "_id";
public static final String COLUMN_NAME = "name";
public static final String AUTOHORITY = "cn.scu.myprovider";
public static final int ITEM = 1;
public static final int ITEM_ID = 2;
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/user";
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/user";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTOHORITY + "/user");
}
DBHelper.java(操作數據庫)
public class DBHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "finch.db";
private static final int DATABASE_VERSION = 1;
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) throws SQLException {
//創建表格
db.execSQL("CREATE TABLE IF NOT EXISTS "+ Constant.TABLE_NAME + "("+ Constant.COLUMN_ID +" INTEGER PRIMARY KEY AUTOINCREMENT," + Constant.COLUMN_NAME +" VARCHAR NOT NULL);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) throws SQLException {
//刪除並創建表格
db.execSQL("DROP TABLE IF EXISTS "+ Constant.TABLE_NAME+";");
onCreate(db);
}
}
MyProvider.java(自定義的ContentProvider)
public class MyProvider extends ContentProvider {
DBHelper mDbHelper = null;
SQLiteDatabase db = null;
private static final UriMatcher mMatcher;
static{
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
mMatcher.addURI(Constant.AUTOHORITY,Constant.TABLE_NAME, Constant.ITEM);
mMatcher.addURI(Constant.AUTOHORITY, Constant.TABLE_NAME+"/#", Constant.ITEM_ID);
}
@Override
public String getType(Uri uri) {
switch (mMatcher.match(uri)) {
case Constant.ITEM:
return Constant.CONTENT_TYPE;
case Constant.ITEM_ID:
return Constant.CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException("Unknown URI"+uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
long rowId;
if(mMatcher.match(uri)!=Constant.ITEM){
throw new IllegalArgumentException("Unknown URI"+uri);
}
rowId = db.insert(Constant.TABLE_NAME,null,values);
if(rowId>0){
Uri noteUri=ContentUris.withAppendedId(Constant.CONTENT_URI, rowId);
getContext().getContentResolver().notifyChange(noteUri, null);
return noteUri;
}
throw new SQLException("Failed to insert row into " + uri);
}
@Override
public boolean onCreate() {
// TODO Auto-generated method stub
mDbHelper = new DBHelper(getContext());
db = mDbHelper.getReadableDatabase();
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
Cursor c = null;
switch (mMatcher.match(uri)) {
case Constant.ITEM:
c = db.query(Constant.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
break;
case Constant.ITEM_ID:
c = db.query(Constant.TABLE_NAME, projection,Constant.COLUMN_ID + "="+uri.getLastPathSegment(), selectionArgs, null, null, sortOrder);
break;
default:
throw new IllegalArgumentException("Unknown URI"+uri);
}
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
}
MainActivity.java(ContentResolver操作)
public class MainActivity extends Activity {
private ContentResolver mContentResolver = null;
private Cursor cursor = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.tv);
mContentResolver = getContentResolver();
tv.setText("添加初始數據 ");
for (int i = 0; i < 10; i++) {
ContentValues values = new ContentValues();
values.put(Constant.COLUMN_NAME, "fanrunqi"+i);
mContentResolver.insert(Constant.CONTENT_URI, values);
}
tv.setText("查詢數據 ");
cursor = mContentResolver.query(Constant.CONTENT_URI, new String[]{Constant.COLUMN_ID,Constant.COLUMN_NAME}, null, null, null);
if (cursor.moveToFirst()) {
String s = cursor.getString(cursor.getColumnIndex(Constant.COLUMN_NAME));
tv.setText("第一個數據: "+s);
}
}
}
最後在manifest申明
主要講解Android Studio中生成aar文件以及本地方式使用aar文件的方法。 在Android Studio中對一個自己庫進行生成操作時將會同時生成*.jar與
在Android的實際開發中,我們Android系統本身已經給我們提供了很豐富的UI以及各種實用的控件,例如TextView,Button,ImageView等。用這些
前面學習總結了平時開發中遇見的各種數據加密方式,最終都會對加密後的二進制數據進行Base64編碼,起到一種二次加密的效果,其實呢Base64從嚴格意義上來說的話不是一種加
一、初步集成Zxing項目二維碼的識別可是在生活中隨處可見的,現在基本上所有APP都有二維碼的相關操作,如果識別二維碼從頭開始開發做起來還是相當復雜和麻煩的,從零開始開發