極力推薦文章:歡迎收藏
Android 乾貨分享 java
本篇文章主要介紹 Android
開發中的部分知識點,經過閱讀本篇文章,您將收穫如下內容:android
- ContentProvider
- 獲取聯繫人信息的方法
- 獲取短信內容的方法
- ContentResolver 內容解析者
- ContentObserver 內容觀察者
- ContentProvider ContentResolver ContentObserver 三者關係
ContentProvider
是Android
四大組件之一,其本質上是一個標準化的數據管道,它屏蔽了底層的數據管理和服務等細節,以標準化的方式在Android
應用間共享數據。用戶能夠靈活實現ContentProvider
所封裝的數據存儲以及增刪改查等,全部的ContentProvider
必須實現一個對外統一的接口(URI)
。程序員
java.lang.Object ↳ android.content.ContentProvider
<provider android:name="com.programandroid.CustomContentProviderMethod" android:authorities="ProgramAndroid" android:exported="true" />
注意 :sql
URI 中的元素 android:authorities="ProgramAndroid"
package com.programandroid.ContentProvider; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.support.annotation.Nullable; /* * ContentProviderMethod.java * * Created on: 2017-9-13 * Author: wangjie * * Welcome attention to weixin public number get more info * * WeiXin Public Number : ProgramAndroid * 微信公衆號 :程序員Android * */ 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; } }
package com.programandroid.ContentProvider; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; /* * DBHelper.java * * Created on: 2017-9-13 * Author: wangjie * * Welcome attention to weixin public number get more info * * WeiXin Public Number : ProgramAndroid * 微信公衆號 :程序員Android * */ 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) { } }
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
的使用方法已經實現。微信
Android
系統自帶一下ContentProvider
,好比 聯繫人
例如: 源碼 packages\providers
下的內容app
(ContactProvider)
提供的一些信息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; } }
<?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>
<?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>
注意:
獲取聯繫人須要申請權限ide
<!-- 讀取聯繫人的權限 --> <uses-permission android:name="android.permission.READ_CONTACTS" />
至此,已經能夠獲取並顯示聯繫人信息。佈局
短信內容數據也是Android
系統提供的,獲取方法以下:學習
package com.programandroid.ContentProvider; import android.app.Activity; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.support.v4.widget.CursorAdapter; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ListView; import android.widget.TextView; import com.programandroid.MainActivity; import com.programandroid.R; /* * MmsListActivity.java * * Created on: 2017-9-13 * Author: wangjie * * Welcome attention to weixin public number get more info * * WeiXin Public Number : ProgramAndroid * 微信公衆號 :程序員Android * */ 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("短信狀態:已發送"); } } } }
<?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>
<?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>
# 4. ContentResolver 內容解析者
ContentResolver
主要是經過URI
調用getContentResolver()
獲取ContentProvider
提供的數據接口,進而進行增刪改查等操做。
// 查詢 Cursor cursor = getContentResolver().query(Uri.parse(uri), null, null, null, null); // 插入數據到指定 URI 中 getContentResolver().insert(Uri.parse(uri), ContentValues);
ContentObserver
內容觀察者經過指定URI
監聽ContentProvider
數據是否改變。
/** * 監聽ContentProvider數據庫變化 */ private void ContentObserverDatabase() { // [1]註冊內容觀察者 Uri uri = Uri.parse("content://ProgramAndroid/person"); // false 觀察的uri 必須是一個確切的uri 若是是true getContentResolver().registerContentObserver(uri, true, new CustomContentObserver(new Handler())); }
package com.programandroid.ContentProvider; import android.database.ContentObserver; import android.os.Handler; /* * CustomContentObserver.java * * Created on: 2017-9-13 * Author: wangjie * * Welcome attention to weixin public number get more info * * WeiXin Public Number : ProgramAndroid * 微信公衆號 :程序員Android * */ 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); } }
至此自定義內容觀察者已經實現完成
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); } }
至此,本篇已結束,若有不對的地方,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!