ContentProvider 使用詳解

極力推薦文章:歡迎收藏
Android 乾貨分享 java

閱讀五分鐘,每日十點,和您一塊兒終身學習,這裏是程序員Android

本篇文章主要介紹 Android 開發中的部分知識點,經過閱讀本篇文章,您將收穫如下內容:android

  1. ContentProvider
  2. 獲取聯繫人信息的方法
  3. 獲取短信內容的方法
  4. ContentResolver 內容解析者
  5. ContentObserver 內容觀察者
  6. ContentProvider ContentResolver ContentObserver 三者關係

ContentProvider Android 四大組件之一,其本質上是一個標準化的數據管道,它屏蔽了底層的數據管理和服務等細節,以標準化的方式在Android 應用間共享數據。用戶能夠靈活實現ContentProvider 所封裝的數據存儲以及增刪改查等,全部的ContentProvider 必須實現一個對外統一的接口(URI)程序員

1. ContentProvider 實現

ContentProvider 繼承關係

java.lang.Object
    ↳ android.content.ContentProvider

四大組件之一,必須在Androidmainfest.xml 中註冊

<provider           
            android:name="com.programandroid.CustomContentProviderMethod"
            android:authorities="ProgramAndroid"
            android:exported="true" />

注意 :sql

URI 中的元素
android:authorities="ProgramAndroid"

繼承 ContentProvider 實現增刪改查等方法

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) {

    }

}

其餘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的使用方法已經實現。微信

2. 獲取聯繫人信息的方法

Android 系統自帶一下ContentProvider ,好比 聯繫人
例如: 源碼 packages\providers 下的內容app

Android 系統Provider.png

本段主要實現獲取系統聯繫人(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;
    }
}

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>

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>

注意:
獲取聯繫人須要申請權限ide

<!-- 讀取聯繫人的權限 -->
    <uses-permission android:name="android.permission.READ_CONTACTS" />

至此,已經能夠獲取並顯示聯繫人信息。佈局

3.獲取短信內容的方法

短信內容數據也是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("短信狀態:已發送");
            }
        }
    }

}

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>

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>

# 4. ContentResolver 內容解析者

ContentResolver 主要是經過URI調用getContentResolver()獲取ContentProvider 提供的數據接口,進而進行增刪改查等操做。

// 查詢
    Cursor cursor = getContentResolver().query(Uri.parse(uri), null, null, null, null);
// 插入數據到指定 URI 中
 getContentResolver().insert(Uri.parse(uri), ContentValues);

5.ContentObserver 內容觀察者

ContentObserver 內容觀察者經過指定URI 監聽ContentProvider數據是否改變。

自定義 ContentObserver 內容觀察者

1.註冊ContentObserver 內容觀察者 registerContentObserver
/**
     * 監聽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方法
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);
    }

}

至此自定義內容觀察者已經實現完成

調用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);
        }

    }

6. ContentProvider ContentResolver ContentObserver 三者關係

  • 三者關係圖以下

關係圖.png

至此,本篇已結束,若有不對的地方,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!

微信關注公衆號:  程序員Android,領福利

相關文章
相關標籤/搜索