《第一行代码》第二版 学习总结16 ContentProvider学习总结 Part1

       最近利用下班时间,找了看什么书比较适合初学android的朋友,很多人推荐了这本书,于是就买了一本,感觉看书,思考,动手,再思考和总结这样过程还是很有必要的,于是就打算把自己学习的东西简单的总结一下;方便自己以后查找,也有利于学习的巩固。在这里首先要感谢一下书籍的作者——郭霖前辈。

       这部分内容本应该很久之前就应该完成的,今天特地的补充一下,关于ContentProvider部分,我将使用两篇博客来记录一下,第一部分是简单介绍一下理论基础以及读取手机联系人的实现第二部分也是学习ContentProvider的意义所在,也就是如何实现像某些系统应用那样,把自己的应用的部分可以公开的数据提供给别的应用程序访问,这也是ContentProvider存在的意义。Okay,今天我们就来看看ContentProvider的知识,还是那些套路:它是什么,它能干什么,应该怎么使用它。

1,初识

  • 它是什么:ContentProvider直译过来是内容提供者的意思,和其本名是一样的,顾名思义,就是一个用于提供本应用数据给其他应用访问的API。
  • 它能干什么:它能做的在上面已经说了,就是通过这个API,可以为其他应用提供访问本应用指定数据的接口
  • 如何使用它:先看下面几个知识。

(1)ContentResolver

This class provides applications access to the content model. 
这个类为其他应用提供可访问数据的入口,可见,其主要作用是在访问数据通道已经建立的情况下,实现打开通道的功能;任何想要访问内容提供者中的数据必然需要使用到这个类。其官方文档给出的方法主要如下:

 IContentProvider acquireProvider(String name)
           
 IContentProvider acquireProvider(Uri uri)
          Returns the content provider for the given content URI..
 int bulkInsert(Uri url, ContentValues[] values)
          Inserts multiple rows into a table at the given URL.
 void cancelSync(Uri uri)
           
 int delete(Uri url, String where, String[] selectionArgs)
          Deletes row(s) specified by a content URI.
 String getType(Uri url)
          Return the MIME type of the given content URL.
 Uri insert(Uri url, ContentValues values)
          Inserts a row into a table at the given URL.
static int modeToMode(Uri uri, String mode)
           
 void notifyChange(Uri uri, ContentObserver observer)
          Notify registered observers that a row was updated.
 void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork)
          Notify registered observers that a row was updated.
 AssetFileDescriptor openAssetFileDescriptor(Uri uri, String mode)
          Open a raw file descriptor to access data under a "content:" URI.
 ParcelFileDescriptor openFileDescriptor(Uri uri, String mode)
          Open a raw file descriptor to access data under a "content:" URI.
 InputStream openInputStream(Uri uri)
          Open a stream on to the content associated with a content URI.
 OutputStream openOutputStream(Uri uri)
          Synonym for openOutputStream(uri, "w").
 OutputStream openOutputStream(Uri uri, String mode)
          Open a stream on to the content associated with a content URI.
 Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
          Query the given URI, returning a Cursor over the result set.
 void registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer)
          Register an observer class that gets callbacks when data identified by a given content URI changes.
abstract  boolean releaseProvider(IContentProvider icp)
           
 void startSync(Uri uri, Bundle extras)
          Start an asynchronous sync operation.
 void unregisterContentObserver(ContentObserver observer)
          Unregisters a change observer.
 int update(Uri uri, ContentValues values, String where, String[] selectionArgs)
          Update row(s) in a content URI.
static void validateSyncExtrasBundle(Bundle extras)
          Check that only values of the following types are in the Bundle: Integer Long Boolean Float Double String null

这里面的方法还是较多的;书中总结的比较到位:这些方法就是对数据进行增删改查的。下面我们就来以其中的一个方法query()为例,以便再引出下一个知识点,关于query()官方给出的详细的文档如下:

public final Cursor query(Uri uri,
                          String[] projection,
                          String selection,
                          String[] selectionArgs,
                          String sortOrder)

Query the given URI, returning a Cursor over the result set.

参数:

uri - The URI, using the content:// scheme, for the content to retrieve.

projection - A list of which columns to return. Passing null will return all columns, which is discouraged to prevent reading data from storage that isn't going to be used.

selection - A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given URI.

selectionArgs - You may include ?s in selection, which will be replaced by the values from selectionArgs, in the order that they appear in the selection. The values will be bound as Strings.

sortOrder - How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort order, which may be unordered.

返回

A Cursor object, which is positioned before the first entry, or null

因为是英文的,但是还都是比较简单的,而且其和SQLite学习中SQLiteDatabase的query()方法很类似。就是参数有些不同,那么我们就来看看具体的参数释义

uri:用于内容获取,格式是content://scheme

projection:指定返回列,null表示所有列

selection:指定放回行,null表示所有行

selectionArgs:selection中?表示的值,没有就是null

sortOrder:查询结果行的排序方式

由此可见,还是比较简单的,书中还给出了很详细的释义表格,我这里只是简单的翻译了一下。

(2)Uri

从上面的方法列表中,我们不难看出,几乎所有的方法都有Uri这个参数,其被称作是内容URI,我们在上面也说了它的格式是:

content://scheme
或者更详细一点:
content://authority/path其中:

  • authority:用于区分应用,通常是应用包名(当然源头由ContentProvider也就是提供数据的应用指定)
  • path:用于区分一个应用当中的不同的表

下面是一个内容URI示例:
content://hfut.edu.myprovider/tab1

2,示例

下面就以读取系统联系人列表为例说一下基本使用

MainActivity.java代码:

package com.hfut.operationcontentprovider;

import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

/**
 * @author why
 * @date 2018-11-5 19:03:54
 */
public class MainActivity extends AppCompatActivity {

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

    /**
     * 读取本机联系人
     *
     * @param view
     */
    public void queryContacts(View view) {
        queryAll();
    }


    public void deleteFirstContact(View view) {
        Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
        //getContentResolver().delete(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
        getContentResolver().delete(uri,
                "display_name=?", new String[]{"Why"});
        queryAll();
    }

    public void queryAll() {
        Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                null, null, null, null);
        StringBuilder builder = new StringBuilder();
        if (cursor != null) {
            while (cursor.moveToNext()) {
                String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                builder.append(name + ":\n" + "      " + number + "\n\n");
            }
        }
        ((TextView) findViewById(R.id.contacts_list)).setText(builder.toString());
    }

}

activity_main.xml代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.hfut.operationcontentprovider.MainActivity">

    <ScrollView
        android:layout_marginLeft="10dp"
        android:id="@+id/contacts_container"
        android:layout_width="match_parent"
        android:layout_height="400dp">
        <TextView
            android:id="@+id/contacts_list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:textSize="25sp" />
    </ScrollView>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="vertical"
        app:layout_constraintTop_toBottomOf="@+id/contacts_container">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="queryContacts"
            android:text="查看联系人"
            android:textSize="20sp" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="deleteFirstContact"
            android:text="删除Why"
            android:textSize="20sp" />

    </LinearLayout>


</android.support.constraint.ConstraintLayout>

主配置文件AndroidManifest.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hfut.operationcontentprovider">
    <uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>
    <uses-permission android:name="android.permission.WRITE_CONTACTS"></uses-permission>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

运行结果:

注意:我这里是5.1的系统,如果是6.0或者以上,需要动态的权限申请,更多关于权限的知识以及动态权限申请请查看Android权限简单介绍

猜你喜欢

转载自blog.csdn.net/hfut_why/article/details/83755950