和你一起終身學習,這里是程序員 Android
本篇文章主要介紹 Android
開發中的部分知識點,通過閱讀本篇文章,您將收獲以下內容:
一、ContentProvider 概述
二、ContentProvider的注冊
三、自定義ContentProvider 的實現
四、獲取聯系人ContactProvider實現的方法
五、獲取短信內容的實現方法
六、ContentResolver 內容解析者
七、ContentObserver 內容觀察者
八、ContentProvider ContentResolver ContentObserver 三者關系
一、ContentProvider 概述
在了解 ContentProvider
之前,我們首先了解一下ContentProvider
的繼承關系。
ContentProvider
繼承關系如下:
java.lang.Object
↳ android.content.ContentProvider
ContentProvider
是Android
四大組件之一,其本質上是一個標准化的數據管道,它屏蔽了底層的數據管理和服務等細節,以標准化的方式在Android
應用間共享數據。用戶可以靈活實現ContentProvider
所封裝的數據存儲以及增刪改查等,所有的ContentProvider
必須實現一個對外統一的接口(URI)
。
二、ContentProvider的注冊
ContentProvider
屬於四大組件之一,必須在Androidmainfest.xml
中注冊。
ContentProvider
注冊方法如下:
<provider
android:name="com.programandroid.CustomContentProviderMethod"
android:authorities="ProgramAndroid"
android:exported="true" />
注意 :
URI 中的元素是android:authorities="ProgramAndroid"
。
三、自定義ContentProvider 的實現
自定義ContentProvider
需要繼承 ContentProvider
,並實現增刪改查等方法。
1.自定義ContentProvider 類
public class CustomContentProviderMethod extends ContentProvider {
private SQLiteDatabase db;
private static final String MAUTHORITIESNAME = "ProgramAndroid";
private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
private static final int PERSON = 1;
private static final int PERSON_NUMBER = 2;
private static final int PERSON_TEXT = 3;
private static final String TABLE_NAME = "table_person";
// 構建URI
static {
// content://programandroid/person
matcher.addURI(MAUTHORITIESNAME, "person", PERSON);
// # 代表任意數字content://programandroid/person/4
matcher.addURI(MAUTHORITIESNAME, "person/#", PERSON_NUMBER);
// * 代表任意文本 content://programandroid/person/filter/ssstring
matcher.addURI(MAUTHORITIESNAME, "person/filter/*", PERSON_TEXT);
}
@Override
public boolean onCreate() {
DBHelper helper = new DBHelper(getContext());
// 創建數據庫
db = helper.getWritableDatabase();
return true;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// 過濾URI
int match = matcher.match(uri);
switch (match) {
case PERSON:
// content://autoname/person
return db.query(TABLE_NAME, projection, selection, selectionArgs,
null, null, sortOrder);
case PERSON_NUMBER:
break;
case PERSON_TEXT:
break;
default:
break;
}
return null;
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
// 過濾URI
int match = matcher.match(uri);
switch (match) {
case PERSON:
// content://autoname/person
long id = db.insert(TABLE_NAME, null, values);
// 將原有的uri跟id進行拼接從而獲取新的uri
return ContentUris.withAppendedId(uri, id);
case PERSON_NUMBER:
break;
case PERSON_TEXT:
break;
default:
break;
}
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
return 0;
}
@Nullable
@Override
public String getType(Uri uri) {
return null;
}
}
2. 提供對外提供操作的數據庫方法
public class DBHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "persons.db";
private static final int DB_VERSION = 1;
private static final String TABLE_NAME = "table_person";
private static final String ID = "_id";
private static final String NAME = "name";
public DBHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String sql = "CREATE TABLE " + TABLE_NAME + "(" + ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL" + "," + NAME
+ " CHAR(10) )";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
3.其他APK 訪問此ContentProvider 數據庫的方法
public class MainActivity extends Activity {
private String uri = "content://ProgramAndroid/person";
private EditText mEditText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mEditText = (EditText) findViewById(R.id.ed_name);
}
public void QureyData(View view) {
String name = null;
Cursor cursor = getContentResolver().query(Uri.parse(uri), null, null, null, null);
while (cursor.moveToNext()) {
name = cursor.getString(cursor.getColumnIndex("name"));
}
mEditText.setText(name);
}
public void InsertData(View view) {
String editName = mEditText.getText().toString();
ContentValues values = new ContentValues();
values.put("name, editName);
Uri result = getContentResolver().insert(Uri.parse(uri), values);
// 注意 : 此條添加上才ContentObserver可以監聽數據庫改變
getContentResolver().notifyChange(Uri.parse(uri),null);
long parseid = ContentUris.parseId(result);
if (parseid > 0) {
Toast.makeText(MainActivity.this, "保存成功", Toast.LENGTH_LONG).show();
mEditText.setText("");
}
}
}
注意 :
// 此條添加上才ContentObserver可以監聽數據庫改變
getContentResolver().notifyChange(Uri.parse(uri),null);
至此,自定義ContentProvider
的使用方法已經實現。
四、獲取聯系人ContactProvider實現的方法
Android
系統自帶一些ContentProvider
,比如 聯系人的ContactProvider
例如: 源碼 packages\providers
下的內容
1. 獲取聯系人實現方法
public class ContactListActivity extends Activity {
private static final String tag = "ContactListActivity";
private ListView lv_contact_list;
private List<HashMap<String, String>> mContactList = new ArrayList<HashMap<String, String>>();
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
// 給數據適配器設置數據
MyAdapter myAdapter = new MyAdapter();
TextView emptyView = new TextView(getApplicationContext());
emptyView.setLayoutParams(new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
emptyView.setText(getResources().getString(
R.string.please_add_contanct));
emptyView.setVisibility(View.GONE);
emptyView.setTextColor(Color.BLACK);
emptyView.setTextSize(20);
emptyView.setGravity(Gravity.CENTER);
((ViewGroup) lv_contact_list.getParent()).addView(emptyView);
lv_contact_list.setEmptyView(emptyView);
lv_contact_list.setAdapter(myAdapter);
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contact_list);
initUI();
initData();
}
/**
* 從系統數據庫中獲取聯系人數據,權限,讀取聯系人
*/
private void initData() {
new Thread() {
public void run() {
// 1,獲取內容解析器(訪問地址(后門))
ContentResolver contentResolver = getContentResolver();
// 2,對數據庫指定表進行查詢操作
Cursor cursor = contentResolver.query(Uri
.parse("content://com.android.contacts/raw_contacts"),
new String[] { "contact_id" }, null, null, null);
// 3,判斷游標中是否有數據,有數據一直度
while (cursor.moveToNext()) {
String id = cursor.getString(0);
Log.i(tag, "id = " + id);// 1,2,3
// 4,通過此id去關聯data表和mimetype表生成視圖,data1(數據),mimetype(數據類型)
Cursor indexCursor = contentResolver.query(
Uri.parse("content://com.android.contacts/data"),
new String[] { "data1", "mimetype" },
"raw_contact_id = ?", new String[] { id }, null);
HashMap<String, String> hashMap = new HashMap<String, String>();
// 5,游標向下移動獲取數據過程
while (indexCursor.moveToNext()) {
String data = indexCursor.getString(0);
String type = indexCursor.getString(1);
// Log.i(tag, "data = "+data);
// Log.i(tag, "type = "+type);
if (type.equals("vnd.android.cursor.item/phone_v2")) {
// data就為電話號碼
hashMap.put("phone", data);
} else if (type.equals("vnd.android.cursor.item/name")) {
// data 為聯系人名字
hashMap.put("name", data);
}
}
indexCursor.close();
mContactList.add(hashMap);
}
cursor.close();
// 告知主線程集合中的數據以及准備完畢,可以讓主線程去使用此集合,填充數據適配器
mHandler.sendEmptyMessage(0);
};
}.start();
}
private void initUI() {
lv_contact_list = (ListView) findViewById(R.id.lv_contact_list);
lv_contact_list.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// 1,position點中條目的索引值,集合的索引值
String phone = mContactList.get(position).get("phone");
// 2,將此電話號碼傳遞給前一個界面
Intent intent = new Intent();
intent.putExtra("phone", phone);
setResult(0, intent);
// 3,關閉此界面
finish();
}
});
}
class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return mContactList.size();
}
@Override
public HashMap<String, String> getItem(int position) {
return mContactList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder;
if (convertView == null) {
holder = new Holder();
// 1,生成當前listview一個條目相應的view對象
convertView = View.inflate(getApplicationContext(),
R.layout.list_item_contact, null);
// 2,找到view中的控件
holder.tv_name = (TextView) convertView
.findViewById(R.id.tv_name);
holder.tv_phone = (TextView) convertView
.findViewById(R.id.tv_phone);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
}
// 3,給控件賦值
holder.tv_name.setText(getItem(position).get("name"));
holder.tv_phone.setText(getItem(position).get("phone"));
return convertView;
}
}
class Holder {
public TextView tv_name;
public TextView tv_phone;
}
}
2. ListView 顯示布局如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/lv_contact_list"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
3. item 布局如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="vertical" >
<TextView
android:text="聯系人名稱"
android:id="@+id/tv_name"
android:textSize="18sp"
android:textColor="@color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="聯系人電話號碼"
android:id="@+id/tv_phone"
android:textSize="18sp"
android:textColor="@color/grey"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
注意:
獲取聯系人需要申請權限
<!-- 讀取聯系人的權限 -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
至此,已經可以獲取並顯示聯系人信息。
五、獲取短信內容的實現方法
短信內容數據也是Android
系統提供的,獲取方法如下:
1.短信內容獲取方法
public class MmsListActivity extends Activity {
private ContentResolver resolver;
private ListView listView;
private static final String SMS_URI = "content://sms";
private Cursor cursor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mms_list);
listView = (ListView) findViewById(R.id.lv_mms);
resolver = getContentResolver();
}
public void GetMMSBtn(View view) {
// 插入數據
ContentValues values = new ContentValues();
values.put("address", "136259");
values.put("body", "測試數據中。。。。。");
resolver.insert(Uri.parse(SMS_URI), values);
// 查詢數據方法
cursor = resolver.query(Uri.parse(SMS_URI), null, null, null, null);
// 將數據顯示到ListView中
listView.setAdapter(new MyAdapter(MmsListActivity.this, cursor,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER));
}
@Override
protected void onDestroy() {
super.onDestroy();
if (cursor != null) {
// 關閉cursor
// cursor.close();
}
}
class MyAdapter extends CursorAdapter {
public MyAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
}
// 創建一個視圖,引入listview要展示的子視圖
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return getLayoutInflater().inflate(R.layout.list_item_mms, null);
}
// 綁定數據的方法
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView tvNumber = (TextView) view.findViewById(R.id.tv_number);
TextView tvContent = (TextView) view.findViewById(R.id.tv_content);
TextView tvState = (TextView) view.findViewById(R.id.tv_state);
TextView tvDate = (TextView) view.findViewById(R.id.tv_date);
TextView tvId = (TextView) view.findViewById(R.id.tv_id);
TextView tvRead = (TextView) view.findViewById(R.id.tv_read);
String number = cursor.getString(cursor.getColumnIndex("address"));
String body = cursor.getString(cursor.getColumnIndex("body"));
String date = cursor.getString(cursor.getColumnIndex("date"));
int read = cursor.getInt(cursor.getColumnIndex("read"));
int id = cursor.getInt(cursor.getColumnIndex("_id"));
int type = cursor.getInt(cursor.getColumnIndex("type"));
if (read == 0) {
tvRead.setText("短信狀態:未讀");
} else {
tvRead.setText("短信狀態:已讀");
}
tvNumber.setText("手機號:" + number);
tvContent.setText("短信內容:" + body);
tvDate.setText("接收短信時間:" + date);
tvId.setText("短信Id:" + id);
if (type == 1) {
tvState.setText("短信狀態:已接收");
} else {
tvState.setText("短信狀態:已發送");
}
}
}
}
2.ListView 布局如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/lv_mms"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
3.item 布局如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddd" />
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddd" />
<TextView
android:id="@+id/tv_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddd" />
<TextView
android:id="@+id/tv_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddd" />
<TextView
android:id="@+id/tv_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddd" />
<TextView
android:id="@+id/tv_read"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddd" />
</LinearLayout>
六、ContentResolver 內容解析者
ContentResolver
主要是通過URI
調用getContentResolver()
獲取ContentProvider
提供的數據接口,進而進行增刪改查等操作。
ContentResolver
使用舉例如下:
// 查詢
Cursor cursor = getContentResolver().query(Uri.parse(uri), null, null, null, null);
// 插入數據到指定 URI 中
getContentResolver().insert(Uri.parse(uri), ContentValues);
七、ContentObserver 內容觀察者
ContentObserver
內容觀察者通過指定URI
監聽ContentProvider
數據是否改變。
下面介紹自定義 ContentObserver
內容觀察者
1.注冊ContentObserver 內容觀察者
/**
* 監聽ContentProvider數據庫變化
*/
private void ContentObserverDatabase() {
// [1]注冊內容觀察者
Uri uri = Uri.parse("content://ProgramAndroid/person");
// false 觀察的uri 必須是一個確切的uri 如果是true
getContentResolver().registerContentObserver(uri, true,
new CustomContentObserver(new Handler()));
}
2.繼承 ContentObserver 實現 onChange方法
public class CustomContentObserver extends ContentObserver {
/**
* @param handler
*/
public CustomContentObserver(Handler handler) {
super(handler);
// TODO Auto-generated constructor stub
}
// 當我們觀察的uri發生改變的時候調用
@Override
public void onChange(boolean selfChange) {
System.out.println(" 數據庫被操作了 ");
super.onChange(selfChange);
}
}
至此自定義內容觀察者已經實現完成
3.調用ContentObserver 監聽短信數據改變
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//[1]注冊一個內容觀察者
Uri uri = Uri.parse("content://sms/");
getContentResolver().registerContentObserver(uri, true, new MyContentObserver(new Handler()));
}
private class MyContentObserver extends ContentObserver{
public MyContentObserver(Handler handler) {
super(handler);
}
//當觀察的內容發生改變的時候調用
@Override
public void onChange(boolean selfChange) {
System.out.println(" 短信的數據庫發生了改變");
super.onChange(selfChange);
}
}
八、ContentProvider ContentResolver ContentObserver 三者關系
- 三者關系圖如下
至此,本篇已結束。轉載網絡的文章,小編覺得很優秀,歡迎點擊閱讀原文,支持原創作者,如有侵權,懇請聯系小編刪除,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!