使用ContentProvider

转载请注明出处: http://blog.csdn.net/a992036795/article/details/51610936

一、简介:

ContentProvider 在android中的作用是对外共享数据,也就是说可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对应用中的数据进行增、删、该、查。使用ContentProvider的好处是,统一了数据的访问方式。

ContentProvider的体层实现实际是Binder。

二、使用:

一般ContentProvider的实现都是对SqliteOpenHelp的进一步包装,通过Uri映射来判断选择需要操作数据库中的那个表,并且进行增、删、改、查处理。

我们先来看以一下ContentProvider的定义:

**
 * Content providers are one of the primary building blocks of Android applications, providing
 * content to applications. They encapsulate data and provide it to applications through the single
 * {@link ContentResolver} interface. A content provider is only required if you need to share
 * data between multiple applications. For example, the contacts data is used by multiple
 * applications and must be stored in a content provider. If you don‘t need to share data amongst
 * multiple applications you can use a database directly via
 * {@link android.database.sqlite.SQLiteDatabase}.
 *
 * <p>When a request is made via
 * a {@link ContentResolver} the system inspects the authority of the given URI and passes the
 * request to the content provider registered with the authority. The content provider can interpret
 * the rest of the URI however it wants. The {@link UriMatcher} class is helpful for parsing
 * URIs.</p>
 *
 * <p>The primary methods that need to be implemented are:
 * <ul>
 *   <li>{@link #onCreate} which is called to initialize the provider</li>
 *   <li>{@link #query} which returns data to the caller</li>
 *   <li>{@link #insert} which inserts new data into the content provider</li>
 *   <li>{@link #update} which updates existing data in the content provider</li>
 *   <li>{@link #delete} which deletes data from the content provider</li>
 *   <li>{@link #getType} which returns the MIME type of data in the content provider</li>
 * </ul></p>
 *
 * <p class="caution">Data access methods (such as {@link #insert} and
 * {@link #update}) may be called from many threads at once, and must be thread-safe.
 * Other methods (such as {@link #onCreate}) are only called from the application
 * main thread, and must avoid performing lengthy operations.  See the method
 * descriptions for their expected thread behavior.</p>
 *
 * <p>Requests to {@link ContentResolver} are automatically forwarded to the appropriate
 * ContentProvider instance, so subclasses don‘t have to worry about the details of
 * cross-process calls.</p>
 *
 * <div class="special reference">
 * <h3>Developer Guides</h3>
 * <p>For more information about using content providers, read the
 * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
 * developer guide.</p>
 */
public abstract class ContentProvider implements ComponentCallbacks2 {
    private static final String TAG = "ContentProvider";

通过注释我们大概可以了解到:

我们自定义一个ContentProvider,需要实现它的onCreate、query、insert、update、delete、getType方法。

因为它底层实现是Binder、其实对源码进行分析的话、可以看到如果是夸进程调用的话,OnCreate将发生在主线程、而其他方法将发生在Binder线程池中。

这一点,我们可以通过在方法打印进程名会得到证实。

06-08 01:46:21.903 3016-3016/com.blueberry.process1 I/SimpleContentProvider: onCreate: current thread: main
06-08 01:46:21.920 3016-3032/com.blueberry.process1 I/SimpleContentProvider: insert: current thread: Binder_2
06-08 01:46:22.968 3016-3032/com.blueberry.process1 I/SimpleContentProvider: query: current thread: Binder_2

这是我写的一个例子的测试结果。下面我们将自己写一个ContentProvider。

首先我们先定义个SQLiteOpenHelp,来创建1个数据库,其中存在2张表。

下面给出类的定义:


/**
 * Created by blueberry on 2016/6/7.
 */
public class UserInfoDbHelper extends SQLiteOpenHelper {

    private static final String TAG = "UserInfoDbHelper";

    private static final String DB_NAME = "userinfo.db"; /*数据库名*/
    private static final int DB_VERSION = 1;/*版本号*/

    public static final String TABLE_USER_INFO = "userinfo";/*用户信息表*/
    public static final String TABLE_COMPANY = "company";/*公司表*/

    public static final String TEL_COLUMN = "tel_num";/*电话号码*/
    public static final String DESC_COLUMN = "desc";/*描述*/
    public static final String COMP_ID_COLUMN = "comp_id";/*公司id*/

    public static final String ID_COLUMN = "id";/*公司的id*/
    public static final String BUSINESS_COLUMN = "business";/*公司的业务*/
    public static final String ADDR_COLUMN = "addr";/*公司位置*/

    //  表 userinfo
    //  | 字段名            | 类型          |意义             |
    //  | Tel_num           | TEXT         |电话号码          |
    //  | Desc              | TEXT         |描述              |
    //  | comp_id           | INTEGER      | 公司id           |
    //

    //  表 company
    //  |字段名              |类型           |意义             |
    //  |Id                 |INTEGER        |公司的id          |
    //  |Business           | TEXT          |公司的业务        |
    //  | Addr              | TEXT          | 公司位置         |

    private static final String POSTCODE_TABLE_SQL ="CREATE TABLE IF NOT EXISTS "+TABLE_USER_INFO +" ("
            +TEL_COLUMN+" TEXT ,"
            +COMP_ID_COLUMN+" INTEGER ,"
            +DESC_COLUMN+" TEXT"
            +")" ;
    private static final String COMPANY_TABLE_SQL ="CREATE TABLE IF NOT EXISTS "+TABLE_COMPANY+" ("
            +ID_COLUMN +" INTEGER PRIMEARY KEY ,"
            +BUSINESS_COLUMN+" TEXT ,"
            +ADDR_COLUMN+" TEXT" +")" ;

    public UserInfoDbHelper(Context context) {
        super(context, DB_NAME , null, DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(POSTCODE_TABLE_SQL);
        db.execSQL(COMPANY_TABLE_SQL);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

可以看到创建了2张表,一张为userinfo 一张为 company。字段名已在注释列出。

下面继续给出自定一ContentProvider的定义:

/**
 * Created by blueberry on 2016/6/7.
 */
public class SimpleContentProvider extends ContentProvider {

    private static final String TAG = "SimpleContentProvider";

    public static final String AUTHORITY = "com.blueberry.test08.provider";

    /*该ContentProvider返回的数据类型定义,数据集合*/
    private static final String CONTENT_TYPE ="vnd.android.cursor.dir/vnd."+AUTHORITY;
    /*单项数据*/
    private static final String CONTNET_TYPE_ITEM ="vnd.android.cursor.item/vnd."+AUTHORITY ;

    public static final Uri USERINFO_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
            + UserInfoDbHelper.TABLE_USER_INFO);
    public static final Uri COMPANY_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
            + UserInfoDbHelper.TABLE_COMPANY);

    public static final int USERINFO_CODE = 0;
    public static final int USERINFO_ITEM_CODE = 1;
    public static final int COMPANY_CODE = 2;
    public static final int COMPANY_ITEM_CODE = 3;

    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    static {
        /**
         * 这里使用2种通配符 "*"表示匹配任意长度的任意字符,"#"表示匹配任意长度的数字
         * 因此,content://com.blueberry.test08.provider/company 表示查询company表中的所有数据
         * 而 conent://com.blueberry.test08.provider/company/# 表示根据一个数字id 查询一条信息
         */
        sUriMatcher.addURI(AUTHORITY, "userinfo", USERINFO_CODE);
        sUriMatcher.addURI(AUTHORITY, "userinfo/*", USERINFO_ITEM_CODE);
        sUriMatcher.addURI(AUTHORITY, "company", COMPANY_CODE);
        sUriMatcher.addURI(AUTHORITY, "company/#", COMPANY_ITEM_CODE);
    }

    private SQLiteDatabase mDatabase;

    /**
     * 夸进程时发生在主线程
     *
     * @return
     */
    @Override
    public boolean onCreate() {
        Log.i(TAG, "onCreate: current thread: " + Thread.currentThread().getName());
        /*返回一个可读写的数据库*/
        mDatabase = new UserInfoDbHelper(getContext()).getWritableDatabase();
        return true;
    }

    /**
     * 夸进程时发生在工作线程
     *
     * @param uri
     * @param projection
     * @param selection
     * @param selectionArgs
     * @param sortOrder
     * @return
     */
    @Nullable
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        Log.i(TAG, "query: current thread: " + Thread.currentThread().getName());
        Cursor cursor = null;
        switch (sUriMatcher.match(uri)) {
            case USERINFO_CODE:
                cursor = mDatabase.query(UserInfoDbHelper.TABLE_USER_INFO, projection, selection, selectionArgs, null, null, sortOrder);
                break;
            case USERINFO_ITEM_CODE:
                String tel = uri.getPathSegments().get(1);
                cursor = mDatabase.query(UserInfoDbHelper.TABLE_USER_INFO, projection, "tel_num = ?", new String[]{tel}, null, null, sortOrder);
                break;
            case COMPANY_CODE:
                cursor = mDatabase.query(UserInfoDbHelper.TABLE_COMPANY, projection, selection, selectionArgs, null, null, sortOrder);
                break;
            case COMPANY_ITEM_CODE:
                String cid = uri.getPathSegments().get(1);
                cursor = mDatabase.query(UserInfoDbHelper.TABLE_COMPANY, projection, "id = ?", new String[]{cid}, null, null, sortOrder);
                break;
        }
        return cursor;
    }

    /**
     * 夸进程时发生在工作线程
     *
     * @param uri
     * @param values
     * @return
     */
    @Nullable
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        Log.i(TAG, "insert: current thread: " + Thread.currentThread().getName());
        long newId = 0;
        Uri newUri = null;
        switch (sUriMatcher.match(uri)) {
            case USERINFO_CODE:
                newId = mDatabase.insert(UserInfoDbHelper.TABLE_USER_INFO, null, values);
                newUri = Uri.parse("content://" + AUTHORITY + "/" + UserInfoDbHelper.TABLE_USER_INFO + "/" + newId);
                break;
            case COMPANY_CODE:
                newId = mDatabase.insert(UserInfoDbHelper.TABLE_COMPANY, null, values);
                newUri = Uri.parse("content://" + AUTHORITY + "/" + UserInfoDbHelper.TABLE_COMPANY + "/" + newId);
                break;
        }

        if (newId > 0) return newUri;
        throw new IllegalArgumentException("Failed to insert row info" + uri);
    }

    /**
     * 夸进程时发生在工作线程
     *
     * @param uri
     * @return
     */
    @Nullable
    @Override
    public String getType(Uri uri) {
        Log.i(TAG, "getType: current thread: " + Thread.currentThread().getName());
        switch (sUriMatcher.match(uri)){
            case USERINFO_CODE:
            case COMPANY_CODE:
                return CONTENT_TYPE;
            case USERINFO_ITEM_CODE:
            case COMPANY_ITEM_CODE:
                return CONTNET_TYPE_ITEM;
            default:
                throw new RuntimeException("错误的 uri");
        }
    }

    @Nullable
    @Override
    public Bundle call(String method, String arg, Bundle extras) {
        return super.call(method, arg, extras);
    }

    /**
     * 夸进程时发生在工作线程
     *
     * @param uri
     * @param selection
     * @param selectionArgs
     * @return
     */
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        Log.i(TAG, "delete: current thread: " + Thread.currentThread().getName());
        return 0;
    }

    /**
     * 夸进程时发生在工作线程
     *
     * @param uri
     * @param values
     * @param selection
     * @param selectionArgs
     * @return
     */
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        Log.i(TAG, "update: current thread: " + Thread.currentThread().getName());
        return 0;
    }
}

我这里只是测试,所以只实现了query和inser方法。这里主要用了一个 UriMatcher类。

这里对上面的程序简要分析一下:

我们先来简要看一下Uri,Uri代表了要操作的数据表的绝对路径,Uri主要包含两部分信息,一是需要操作的ContentProvider,二是对ContentProvider中的哪个表进行操作。一个Uri的组成为:

ContentProvider的Schema已经由Android固定设置为content://, Authority用于唯一标示这个ContentProvider,外部调用者可以根据这个标示来找到它,这里的path就是要查询的数据表,最后的id是可选字段,例如,我们操作特定的数据项时就会指定一个查询条件,如果所有联系人的uri为 content://contacts/people,某个联系人的Uri:content://contacts/people/5,这个5 就是联系人的id,也就对应了查询的关键字。

这里我们的Authority为 com.blueberry.test08.provider。

接下来我们看以UriMatcher

我们来看一下这个类的定义:

/**
Utility class to aid in matching URIs in content providers.

<p>To use this class, build up a tree of <code>UriMatcher</code> objects.
For example:
<pre>
    private static final int PEOPLE = 1;
    private static final int PEOPLE_ID = 2;
    private static final int PEOPLE_PHONES = 3;
    private static final int PEOPLE_PHONES_ID = 4;
    private static final int PEOPLE_CONTACTMETHODS = 7;
    private static final int PEOPLE_CONTACTMETHODS_ID = 8;

    private static final int DELETED_PEOPLE = 20;

    private static final int PHONES = 9;
    private static final int PHONES_ID = 10;
    private static final int PHONES_FILTER = 14;

    private static final int CONTACTMETHODS = 18;
    private static final int CONTACTMETHODS_ID = 19;

    private static final int CALLS = 11;
    private static final int CALLS_ID = 12;
    private static final int CALLS_FILTER = 15;

    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    static
    {
        sURIMatcher.addURI("contacts", "people", PEOPLE);
        sURIMatcher.addURI("contacts", "people/#", PEOPLE_ID);
        sURIMatcher.addURI("contacts", "people/#/phones", PEOPLE_PHONES);
        sURIMatcher.addURI("contacts", "people/#/phones/#", PEOPLE_PHONES_ID);
        sURIMatcher.addURI("contacts", "people/#/contact_methods", PEOPLE_CONTACTMETHODS);
        sURIMatcher.addURI("contacts", "people/#/contact_methods/#", PEOPLE_CONTACTMETHODS_ID);
        sURIMatcher.addURI("contacts", "deleted_people", DELETED_PEOPLE);
        sURIMatcher.addURI("contacts", "phones", PHONES);
        sURIMatcher.addURI("contacts", "phones/filter/*", PHONES_FILTER);
        sURIMatcher.addURI("contacts", "phones/#", PHONES_ID);
        sURIMatcher.addURI("contacts", "contact_methods", CONTACTMETHODS);
        sURIMatcher.addURI("contacts", "contact_methods/#", CONTACTMETHODS_ID);
        sURIMatcher.addURI("call_log", "calls", CALLS);
        sURIMatcher.addURI("call_log", "calls/filter/*", CALLS_FILTER);
        sURIMatcher.addURI("call_log", "calls/#", CALLS_ID);
    }
</pre>
<p>Starting from API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, paths can start
 with a leading slash.  For example:
<pre>
        sURIMatcher.addURI("contacts", "/people", PEOPLE);
</pre>
<p>Then when you need to match against a URI, call {@link #match}, providing
the URL that you have been given.  You can use the result to build a query,
return a type, insert or delete a row, or whatever you need, without duplicating
all of the if-else logic that you would otherwise need.  For example:
<pre>
    public String getType(Uri url)
    {
        int match = sURIMatcher.match(url);
        switch (match)
        {
            case PEOPLE:
                return "vnd.android.cursor.dir/person";
            case PEOPLE_ID:
                return "vnd.android.cursor.item/person";
... snip ...
                return "vnd.android.cursor.dir/snail-mail";
            case PEOPLE_ADDRESS_ID:
                return "vnd.android.cursor.item/snail-mail";
            default:
                return null;
        }
    }
</pre>
instead of:
<pre>
    public String getType(Uri url)
    {
        List<String> pathSegments = url.getPathSegments();
        if (pathSegments.size() >= 2) {
            if ("people".equals(pathSegments.get(1))) {
                if (pathSegments.size() == 2) {
                    return "vnd.android.cursor.dir/person";
                } else if (pathSegments.size() == 3) {
                    return "vnd.android.cursor.item/person";
... snip ...
                    return "vnd.android.cursor.dir/snail-mail";
                } else if (pathSegments.size() == 3) {
                    return "vnd.android.cursor.item/snail-mail";
                }
            }
        }
        return null;
    }
</pre>
*/
public class UriMatcher
{

可以看到,注释中已经把他的用法说的查不到了。

UriMather 会根据uri来匹配出对应的 code来使得我们判断该查询那张表,

这里我们定义了四个 code. 分别对用与 用户信息查询、单个用户信息查询、公司查询、单个公司查询。

 public static final int USERINFO_CODE = 0;
    public static final int USERINFO_ITEM_CODE = 1;
    public static final int COMPANY_CODE = 2;
    public static final int COMPANY_ITEM_CODE = 3;

我们通过如下方法将 对应信息添加进去:


    static {
        /**
         * 这里使用2种通配符 "*"表示匹配任意长度的任意字符,"#"表示匹配任意长度的数字
         * 因此,content://com.blueberry.test08.provider/company 表示查询company表中的所有数据
         * 而 conent://com.blueberry.test08.provider/company/# 表示根据一个数字id 查询一条信息
         */
        sUriMatcher.addURI(AUTHORITY, "userinfo", USERINFO_CODE);
        sUriMatcher.addURI(AUTHORITY, "userinfo/*", USERINFO_ITEM_CODE);
        sUriMatcher.addURI(AUTHORITY, "company", COMPANY_CODE);
        sUriMatcher.addURI(AUTHORITY, "company/#", COMPANY_ITEM_CODE);
    }

我们接着来看一下getType方法,根据UriMather推荐的方法,如果查询的是数据集合, 我们返回的类型应该是 vnd.android.cursor.dir/….. 如果是查询单个数据我们返回的类型应该是 vnd.android.cursor.item/….

  /*该ContentProvider返回的数据类型定义,数据集合*/
    private static final String CONTENT_TYPE ="vnd.android.cursor.dir/vnd."+AUTHORITY;
    /*单项数据*/
    private static final String CONTNET_TYPE_ITEM ="vnd.android.cursor.item/vnd."+AUTHORITY ;

 /**
     * 夸进程时发生在工作线程
     *
     * @param uri
     * @return
     */
    @Nullable
    @Override
    public String getType(Uri uri) {
        Log.i(TAG, "getType: current thread: " + Thread.currentThread().getName());
        switch (sUriMatcher.match(uri)){
            case USERINFO_CODE:
            case COMPANY_CODE:
                return CONTENT_TYPE;
            case USERINFO_ITEM_CODE:
            case COMPANY_ITEM_CODE:
                return CONTNET_TYPE_ITEM;
            default:
                throw new RuntimeException("错误的 uri");
        }
    }

接着来看 他的query 和 insert方法:

 /**
     * 夸进程时发生在工作线程
     *
     * @param uri
     * @param projection
     * @param selection
     * @param selectionArgs
     * @param sortOrder
     * @return
     */
    @Nullable
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        Log.i(TAG, "query: current thread: " + Thread.currentThread().getName());
        Cursor cursor = null;
        switch (sUriMatcher.match(uri)) {
            case USERINFO_CODE:
                cursor = mDatabase.query(UserInfoDbHelper.TABLE_USER_INFO, projection, selection, selectionArgs, null, null, sortOrder);
                break;
            case USERINFO_ITEM_CODE:
                String tel = uri.getPathSegments().get(1);
                cursor = mDatabase.query(UserInfoDbHelper.TABLE_USER_INFO, projection, "tel_num = ?", new String[]{tel}, null, null, sortOrder);
                break;
            case COMPANY_CODE:
                cursor = mDatabase.query(UserInfoDbHelper.TABLE_COMPANY, projection, selection, selectionArgs, null, null, sortOrder);
                break;
            case COMPANY_ITEM_CODE:
                String cid = uri.getPathSegments().get(1);
                cursor = mDatabase.query(UserInfoDbHelper.TABLE_COMPANY, projection, "id = ?", new String[]{cid}, null, null, sortOrder);
                break;
        }
        return cursor;
    }

    /**
     * 夸进程时发生在工作线程
     *
     * @param uri
     * @param values
     * @return
     */
    @Nullable
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        Log.i(TAG, "insert: current thread: " + Thread.currentThread().getName());
        long newId = 0;
        Uri newUri = null;
        switch (sUriMatcher.match(uri)) {
            case USERINFO_CODE:
                newId = mDatabase.insert(UserInfoDbHelper.TABLE_USER_INFO, null, values);
                newUri = Uri.parse("content://" + AUTHORITY + "/" + UserInfoDbHelper.TABLE_USER_INFO + "/" + newId);
                break;
            case COMPANY_CODE:
                newId = mDatabase.insert(UserInfoDbHelper.TABLE_COMPANY, null, values);
                newUri = Uri.parse("content://" + AUTHORITY + "/" + UserInfoDbHelper.TABLE_COMPANY + "/" + newId);
                break;
        }

        if (newId > 0) return newUri;
        throw new IllegalArgumentException("Failed to insert row info" + uri);
    }

可以看到,利用UriMatcher得到要怎样查询,然后代用了 database的方法。

最后说一个方法:

 @Nullable
    @Override
    public Bundle call(String method, String arg, Bundle extras) {
        return super.call(method, arg, extras);
    }

可以利用这个方法,扩展出一些查询方式。

最后我们来看以下在清单文件中的注册:

  <provider
            android:authorities="com.blueberry.test08.provider"
            android:name=".SimpleContentProvider"
            android:permission="com.blueberry.permission.provider"
            android:process="com.blueberry.process1"
            android:multiprocess="false"
            >

        </provider>

这里主要的字段为 authorities ,他是ContentProvider的唯一标识。

permission,它分为 读权限,和写权限 对应为 android:readpermission 和

android:writepermission 。 multiprocess如果设置为true标识每个调用进程都拥有一个示例,负责只有所有进程只有一个示例。process字段使得它运行在一个名为com.blueberry.process1的进程中。

最后我们来看一下调用程序:

public class MainActivity extends AppCompatActivity {

    private EditText etUserDesc,etUserPhoneNumber,etUserCompanyId;
    private EditText etCompanyId,etCompanyBussiness,etCompanyAddress ;
    private Button btnSubmitUserInfo,btnSubmitCompany;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        etUserDesc = (EditText) findViewById(R.id.et_user_desc);
        etUserPhoneNumber = (EditText) findViewById(R.id.et_user_phone_number);
        etUserCompanyId = (EditText) findViewById(R.id.et_user_company_id);

        etCompanyId = (EditText) findViewById(R.id.et_company_id);
        etCompanyBussiness  = (EditText) findViewById(R.id.et_company_bussiness);
        etCompanyAddress = (EditText) findViewById(R.id.et_company_address);

        btnSubmitUserInfo = (Button) findViewById(R.id.btn_save_userinfo);
        btnSubmitCompany = (Button) findViewById(R.id.btn_save_company);

        btnSubmitUserInfo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //存数用户信息数据
                saveUserInfoRecord();
                btnSubmitUserInfo.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        queryUserInfo();
                    }
                },1000);
            }
        });

        btnSubmitCompany.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                saveCompanyInfo();
                btnSubmitCompany.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                      queryCompanyInfo();
                    }
                },1000) ;
            }
        });
    }

    /**
     * 通过电话号码查询相关信息
     */
    private void queryUserInfo() {
        Uri queryUri = Uri.parse("content://com.blueberry.test08.provider/userinfo/123456") ;
        Cursor cursor = getContentResolver().query(queryUri,
                new String[]{UserInfoDbHelper.DESC_COLUMN,UserInfoDbHelper.COMP_ID_COLUMN,UserInfoDbHelper.TEL_COLUMN}
                ,null,null,null);
        if(cursor.moveToFirst()){
            Toast.makeText(this,
                    " 描述信息"+cursor.getString(0)
                    +" 公司id"+cursor.getString(1)
                    +" 电话来自"+cursor.getString(2),Toast.LENGTH_SHORT).show();
        }
        cursor.close();
    }

    /**
     * 存储用户信息到ContentProvider
     */
    private void saveUserInfoRecord() {
        ContentValues newRecord = new ContentValues();
        newRecord.put(UserInfoDbHelper.DESC_COLUMN,etUserDesc.getText().toString());
        newRecord.put(UserInfoDbHelper.COMP_ID_COLUMN,etUserCompanyId.getText().toString());
        newRecord.put(UserInfoDbHelper.TEL_COLUMN,etUserPhoneNumber.getText().toString());
        getContentResolver().insert(SimpleContentProvider.USERINFO_CONTENT_URI,newRecord) ;
    }

    private void saveCompanyInfo() {
        ContentValues newRecord = new ContentValues();
        newRecord.put(UserInfoDbHelper.ID_COLUMN,etCompanyId.getText().toString());
        newRecord.put(UserInfoDbHelper.BUSINESS_COLUMN,etCompanyBussiness.getText().toString());
        newRecord.put(UserInfoDbHelper.ADDR_COLUMN,etCompanyAddress.getText().toString());
        getContentResolver().insert(SimpleContentProvider.COMPANY_CONTENT_URI,newRecord);
    }

    private void queryCompanyInfo(){
        Cursor cursor = getContentResolver().query(SimpleContentProvider.COMPANY_CONTENT_URI,
                new String[]{UserInfoDbHelper.ID_COLUMN,UserInfoDbHelper.BUSINESS_COLUMN,UserInfoDbHelper.ADDR_COLUMN}
                ,null,null,null);
        StringBuffer sb = new StringBuffer();
        while (cursor.moveToNext()){
            sb.append("id: "+cursor.getString(0)+" business: "+cursor.getString(1)+" address: "+cursor.getString(2));
            sb.append("\n");
        }
        Toast.makeText(this,sb.toString(),Toast.LENGTH_LONG).show();
    }
}

布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.blueberry.test08.MainActivity">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/et_user_desc"
        android:hint="请输入用户描述信息"
        android:contentDescription="用户描述信息"
        />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/et_user_phone_number"
        android:hint="输入用户电话号码"
        android:contentDescription="用户电话号码"
        />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/et_user_company_id"
        android:hint="用户公司id"
        android:contentDescription="用户公司id"
        />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn_save_userinfo"
        android:text="存储用户信息"
        />

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/et_company_id"
        android:hint="公司id"
        />

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/et_company_bussiness"
        android:hint="请输入公司业务"
        android:contentDescription="公司业务"
        />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/et_company_address"
        android:hint="请输入公司地址"
        android:contentDescription="请输入公司地址"
        />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn_save_company"
        android:text="保存公司信息"
        />
</LinearLayout>

时间: 2024-10-24 21:42:41

使用ContentProvider的相关文章

四大组件之ContentProvider小结

总结提高,与君共勉 1.什么是Content Provider Content Provider维护特定的应用数据,并可以让其它应用轻松访问该数据.对数据使用者来说它是数据提供者.它提供统一的接口对数据进行操作,使用者不用关心数据到底是如何存储的以及数据类型到底是什么.也就是说,Content Provider作为数据提供者,提供了对外共享本地数据一种机制,使Android应用能方便地基于该机制进行数据访问.为了便于管理和访问,每个Content Provider必须有唯一标示,用Uri表示.U

ContentProvider

android使用一种称为contentprovider的概念来将数据抽象为服务. 这种内容提供给程序的理念看起来像是启用了REST的数据提供程序.REST(REpresentational State Transfer具象状态传输),它是一种设计风格,通常基于使用HTTP,URI和XML以及HTML这些现有的广泛流行的协议和标准.资源由URI指定,对资源的操作包括获取,创建,修改和删除资源:这些操作正好对应HTTP协议提供的GET,POST和DELETE方法. 要从ContentProvide

关于ContentProvider的一些例子(获取联系人)

ContentResolver:是Android的四大组件之一,主要用于对外共享数据. Android提供了一些主要数据类型的ContentProvider,比如音频.视频.图片和私人通讯录等.前提是已经获取其权限. 主要方法 public boolean onCreate() 在创建ContentProvider时调用public Cursor query(Uri, String[], String, String[], String) 查询ContentProvider,返回一个Cursor

安卓中的数据存储方式以及ContentProvider的简单介绍

1.介绍android的数据存储方式 File存储 sharedPrefrence存储方式 conmtentprovider sqlitedatabase 网络存储 2.请介绍下ContentProvider是如何实现数据共享的 安卓中如果想将自己应用程序的数据暴露给其他的应用程序的时候就需要创建内容提供者.第三方可以通过contentResolver来访问该provider 3.为什么要使用ContentProvider?它和sql的实现上有什么差别? ContentProvider屏蔽了数据

[Android] ContentProvider实例详解

1.ContentProvider是什么? ContentProvider(内容提供者)是Android的四大组件之一,管理android以结构化方式存放的数据,以相对安全的方式封装数据(表)并且提供简易的处理机制和统一的访问接口供其他程序调用. Android的数据存储方式总共有五种,分别是:Shared Preferences.网络存储.文件存储.外储存储.SQLite.但一般这些存储都只是在单独的一个应用程序之中达到一个数据的共享,有时候我们需要操作其他应用程序的一些数据,就会用到Cont

android 53 ContentProvider内容提供者

ContentProvider内容提供者:像是一个中间件一样,一个媒介一样,可以以标准的增删改差操作对手机的文件.数据库进行增删改差.通过ContentProvider查找sd卡的音频文件,可以提供标准的方法而且不用知道音频文件在那个文件夹里面,只要设置条件就可以找到. 安卓系统把音视频.图片存在系统内部的数据库里面,ContentProvider操作的是数据库不是去文件夹里面去找.sd卡和内存卡的文件安卓系统都会登记,登记文件类型.路径,文件名,文件大小都保存在数据库里.ContentProv

用自定义ContentProvider实现对数据库的增、删、改、查操作

本次对于数据库的操作是在不同的APP中进行的.下面的前四篇是在一个APP中,后面的是在另一个APP中 ------------------------------------------------------------------------------------------------- 首先自定义一个SqliteOpenHelper.完成对数据库的创建和数据库内table的创建 package com.example.content_provider_03; import androi

Android(java)学习笔记245:ContentProvider之银行数据库创建和增删改查的实现

1.Android的四大组件: (1)Activity  用户交互的UI界面 (2)Service  后台运行的服务 (3)BroadcastReceiver 广播接收者 (4)ContentProvider  内容提供者 2. ContentProvider  内容提供者 用途:把应用程序私有的数据暴露给别的应用程序. 3.下面通过一个银行数据库创建和增删改查的实现案例说明ContentProvider的使用: (1)首先我们这里要用到数据库,首先我们必须先扩展一个抽象类SQLiteOpenH

ContentProvider中的数据生成时机

MainActivity.java 1 package com.wyl.contentprovidermine; 2 3 4 import android.app.Activity; 5 import android.content.ContentResolver; 6 import android.content.ContentValues; 7 import android.os.Bundle; 8 import android.view.View; 9 import android.vie

android,ContentProvider+ContentObserver+ContentResolver,用法。

这个是传智播客老师讲android开发时的一个图. 一. PersonProvider继承ContentProvider,实现ContentProvider中的数据操作类. 在需要监听的操作中添加添加数据变化通知. this.getContext().getContentResolver().notifyChange(uri, null); 第二个参数,数据变化的监听者,可以不设置,也即是设为null,如果给定了这个监听者,不管外面有多少个应用要设置监听,进行监听数据变化,这个getConten