1. 程式人生 > >《第一行程式碼》第二版 學習總結16 ContentProvider學習總結 Part1

《第一行程式碼》第二版 學習總結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許可權簡單介紹