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

《第一行程式碼》第二版 學習總結17 ContentProvider學習總結 Part2

        最近利用下班時間,找了看什麼書比較適合初學android的朋友,很多人推薦了這本書,於是就買了一本,感覺看書,思考,動手,再思考和總結這樣過程還是很有必要的,於是就打算把自己學習的東西簡單的總結一下;方便自己以後查詢,也有利於學習的鞏固。在這裡首先要感謝一下書籍的作者——郭霖前輩。

       上一部分我們介紹了一些基礎知識以及如何訪問別的程式的中資料,並給出了訪問系統聯絡人應用中的聯絡人資料,今天我們就來看看其他應用究竟是怎麼通過內容提供者把自己的資料提供出來的。關於這部分的內容,如果是對SQLite比較陌生的朋友,可以提前熟悉一下

SQLite的基本使用好的,在這些條件都具備的時候,我們就可以開始具體的內容了。

 

1,通過內容提供者提供資料訪問介面實現步驟

 

  • 自定義內容提供者

  • 構建外部訪問的Uri,並新增到UriMatcher裡面

  • 重寫內部六個方法,分別是CURD四個方法以及onCreate()和getType(),利用外部訪問Uri與自定義程式碼建立聯絡

這樣三步,就完成了我們的目標。

 

(1)自定義內容提供者

我們實現主要有兩種方式:

  • 自定義類繼承android.content.ContentProvider,需要手動新增配置檔案
  • 通過AS快捷鍵或者new的方式,不需要手動新增配置檔案

(2)構建外部訪問的Uri,並新增到UriMatcher裡面

這個操作的目的主要是我們之前說的,控制外部可訪問的資料,保護自身的隱私資料,也就是說只有在UriMatcher裡面新增的Uri子項的資料外部才可以訪問,例如如下程式碼:

 static {
        matcher = new UriMatcher(UriMatcher.NO_MATCH);
        //新增對外內容URI,通常是包名+表名/或者萬用字元+萬用字元
        matcher.addURI(authority, "student", TAB_STUDENT);
        matcher.addURI(authority, "student/#", COW_STUDENT);
        matcher.addURI(authority, "teacher", TAB_TEACHER);
        matcher.addURI(authority, "teacher/#", COW_TEACHER);
    }

(3)重寫ContentProvider中的六個方法,實現外部對可訪問資料的操作,例如insert():

 @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        SQLiteDatabase sqLiteDatabase = sqLiterHelper.getReadableDatabase();
        Uri uriReturn=null;
        switch (matcher.match(uri)) {
            case TAB_STUDENT:
                long newStudentId =sqLiteDatabase.insert("student",null,values);
                uriReturn=Uri.parse("content://"+authority+"/student/"+newStudentId);
                break;
            case COW_STUDENT:

                break;
            case TAB_TEACHER:
                long newTeacherId =sqLiteDatabase.insert("teacher",null,values);
                uriReturn=Uri.parse("content://"+authority+"/teacher/"+newTeacherId);
                break;
            case COW_TEACHER:
                break;
                default:
                    break;
        }
        return uriReturn;
    }

 

2,示例

這一部分,為了效果,建立了兩個應用,分別是OperationContentProviderB(提供資料)OperationContentProviderA(訪問資料),下面就來看看具體的程式碼和實現效果:

 OperationContentProviderB(提供資料)中

MainActivity.java程式碼:

package com.hfut.operationcontentproviderb;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.content.ContentValues;
import android.widget.TextView;

/**
 * @author why
 * @date 2018-11-6 18:47:07
 */
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private MySQLiterHelper mySQLiteHelperBase;

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

    public void createStudentTab(View view) {
        mySQLiteHelperBase = new MySQLiterHelper(this, "school", null, 1);
        SQLiteDatabase sqLiteDatabase = mySQLiteHelperBase.getReadableDatabase();//建立資料庫

        initDataStudent(sqLiteDatabase);//初始化資料庫資料
    }


    public void createTeacherTab(View view) {
        mySQLiteHelperBase = new MySQLiterHelper(this, "school", null, 1);
        SQLiteDatabase sqLiteDatabase = mySQLiteHelperBase.getReadableDatabase();//建立資料庫

        initDataTeacher(sqLiteDatabase);//初始化資料庫資料
    }


    /**
     * 初始化資料庫student資料
     */
    private void initDataStudent(SQLiteDatabase sqLiteDatabase) {
        ContentValues contentValues = new ContentValues();
        contentValues.put("name", "why");
        contentValues.put("age", 26);
        contentValues.put("sex", "male");
        sqLiteDatabase.insert("student", null, contentValues);
        contentValues.clear();
        contentValues.put("name", "jr");
        contentValues.put("age", 24);
        contentValues.put("sex", "female");
        sqLiteDatabase.insert("student", null, contentValues);
        contentValues.clear();
        contentValues.put("name", "xiaoming");
        contentValues.put("age", 34);
        contentValues.put("sex", "unkown");
        sqLiteDatabase.insert("student", null, contentValues);
        contentValues.clear();
        Log.d(TAG, "initData: 執行了資料新增操作");


        Cursor cursor = sqLiteDatabase.query("student", null, null, null, null, null, null);
        StringBuilder builder = new StringBuilder();
        builder.append(" student表資料:\n");
        while (cursor.moveToNext()) {
            builder.append("name: " + cursor.getString(cursor.getColumnIndex("name")) +
                    "  age: " + cursor.getInt(cursor.getColumnIndex("age")) +
                    "  sex: " + cursor.getString(cursor.getColumnIndex("sex")) + "\n");
        }
        ((TextView) findViewById(R.id.dbData)).setText(builder.toString());

    }

    /**
     * 初始化資料庫teacher資料
     */
    private void initDataTeacher(SQLiteDatabase sqLiteDatabase) {
        ContentValues contentValues = new ContentValues();
        contentValues.put("name", "why");
        contentValues.put("teacherID", 1);
        contentValues.put("subject", "computer");
        sqLiteDatabase.insert("teacher", null, contentValues);
        contentValues.clear();
        contentValues.put("name", "jr");
        contentValues.put("teacherID", 2);
        contentValues.put("subject", "math");
        sqLiteDatabase.insert("teacher", null, contentValues);
        contentValues.clear();
        contentValues.put("name", "xiaoming");
        contentValues.put("teacherID", 3);
        contentValues.put("subject", "biology");
        sqLiteDatabase.insert("teacher", null, contentValues);
        contentValues.clear();
        Log.d(TAG, "initData: 執行了資料新增操作");


        Cursor cursor = sqLiteDatabase.query("teacher", null, null, null, null, null, null);
        StringBuilder builder = new StringBuilder();
        builder.append("  teacher表資料\n");
        while (cursor.moveToNext()) {
            builder.append("name: " + cursor.getString(cursor.getColumnIndex("name")) +
                    "  teacherID: " + cursor.getInt(cursor.getColumnIndex("teacherID")) +
                    "  subject: " + cursor.getString(cursor.getColumnIndex("subject")) + "\n");
        }
        ((TextView) findViewById(R.id.dbData)).setText(builder.toString());

    }
}

MyProvider.java程式碼:

package com.hfut.operationcontentproviderb;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

/**
 * author:why
 * created on: 2018/11/6 18:51
 * description:
 */
public class MyProvider extends ContentProvider {

    public static final int TAB_STUDENT = 1;
    public static final int COW_STUDENT = 2;
    public static final int TAB_TEACHER = 3;
    public static final int COW_TEACHER = 4;
    private static UriMatcher matcher;
    private MySQLiterHelper sqLiterHelper;
    private static String authority = "com.hfut.operationcontentproviderb";
    private String dirType = "vnd.android.cursor.dir/";
    private String itemType = "vnd.android.cursor.item/";

    static {
        matcher = new UriMatcher(UriMatcher.NO_MATCH);
        //新增對外內容URI,通常是包名+表名/或者萬用字元+萬用字元
        matcher.addURI(authority, "student", TAB_STUDENT);
        matcher.addURI(authority, "student/#", COW_STUDENT);
        matcher.addURI(authority, "teacher", TAB_TEACHER);
        matcher.addURI(authority, "teacher/#", COW_TEACHER);
    }

    @Override
    public boolean onCreate() {
        sqLiterHelper = new MySQLiterHelper(getContext(), "school", null, 1);
        return true;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
                        @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        SQLiteDatabase sqLiteDatabase = sqLiterHelper.getReadableDatabase();
        Cursor cursor = null;
        switch (matcher.match(uri)) {
            case TAB_STUDENT://查詢student全表
                cursor = sqLiteDatabase.query("student", projection, selection, selectionArgs,
                        null, null, sortOrder);
                break;
            case COW_STUDENT://查詢student表中i指定id的行
                String studentId = uri.getPathSegments().get(1);
                cursor = sqLiteDatabase.query("student", projection, "id=?",
                        new String[]{studentId}, null, null, sortOrder);

                break;
            case TAB_TEACHER:
                cursor = sqLiteDatabase.query("teacher", projection, selection, selectionArgs,
                        null, null, sortOrder);
                break;
            case COW_TEACHER:
                String teacherId = uri.getPathSegments().get(1);
                cursor = sqLiteDatabase.query("teacher", projection, "id=?",
                        new String[]{teacherId}, null, null, sortOrder);
                break;
            default:
                break;
        }
        return cursor;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        String str = "";
        switch (matcher.match(uri)) {
            case TAB_STUDENT:
                str = dirType + "vnd." + authority + ".student";
                break;
            case COW_STUDENT:
                str = itemType + "vnd." + authority + ".student";
                break;
            case TAB_TEACHER:
                str = dirType + "vnd." + authority + ".teacher";
                break;
            case COW_TEACHER:
                str = itemType + "vnd." + authority + ".teacher";
                break;
            default:
                break;
        }
        return str;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        SQLiteDatabase sqLiteDatabase = sqLiterHelper.getReadableDatabase();
        Uri uriReturn = null;
        switch (matcher.match(uri)) {
            case TAB_STUDENT:
                long newStudentId = sqLiteDatabase.insert("student", null, values);
                uriReturn = Uri.parse("content://" + authority + "/student/" + newStudentId);
                break;
            case COW_STUDENT:

                break;
            case TAB_TEACHER:
                long newTeacherId = sqLiteDatabase.insert("teacher", null, values);
                uriReturn = Uri.parse("content://" + authority + "/teacher/" + newTeacherId);
                break;
            case COW_TEACHER:
                break;
            default:
                break;
        }
        return uriReturn;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }
}

MySQLiteHelper.java程式碼:

package com.hfut.operationcontentproviderb;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;

/**
 * author:why
 * created on: 2018/11/6 19:10
 * description:
 */
public class MySQLiterHelper extends SQLiteOpenHelper {
    //資料型別可以有integer,text(文字),real(浮點型),blob(二進位制型別)
    public static final String createStudentSql = "create table student(" +
            "stuID integer primary key autoincrement," +
            "name text," +
            "age integer," +
            "sex text)";
    public static final String createTeacherSql = "create table teacher(" +
            "name text," +
            "teacherID integer," +
            "subject text)";
    private Context myContext;

    public MySQLiterHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        this.myContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(createStudentSql);
        db.execSQL(createTeacherSql);
        Toast.makeText(myContext, "執行了資料庫建立操作", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("drop table  if exists student");
        db.execSQL("drop table if exists teacher");
        onCreate(db);
    }
}

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.operationcontentproviderb.MainActivity">

    <Button
        android:id="@+id/btn1"
        android:layout_marginTop="30dp"
        android:onClick="createStudentTab"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="建立表student並初始化資料"
        android:textAllCaps="false"
        android:textSize="25sp" />
    <Button
        android:id="@+id/btn2"
        app:layout_constraintTop_toBottomOf="@+id/btn1"
        android:layout_marginTop="5dp"
        android:onClick="createTeacherTab"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="建立表teacher並初始化資料"
        android:textAllCaps="false"
        android:textSize="25sp" />

    <TextView
        android:id="@+id/dbData"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn2"
        android:textSize="25sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</android.support.constraint.ConstraintLayout>

主配置檔案:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hfut.operationcontentproviderb">

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

        <provider
            android:authorities="com.hfut.operationcontentproviderb"
            android:name=".MyProvider"
            android:exported="true"
            android:enabled="true">

        </provider>
    </application>

</manifest>

 

Okay,資料通過方的程式碼搞定了,我這裡為了簡化程式碼,只寫查詢和增加資料,其他的類似;如何訪問其實就和上一篇中一樣了,拿著指定的Uri就可以了。下面來看看其程式碼:           

 OperationContentProviderA

MainActivity.java程式碼:

package com.hfut.operationcontentprovidera;

import android.database.Cursor;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.content.ContentValues;

/**
 * @author why
 * @date 2018-11-6 20:31:48
 */
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

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


    public void queryStudentTab(View view) {
        Uri uri = Uri.parse("content://com.hfut.operationcontentproviderb/student");
        Cursor cursor = getContentResolver().query(uri, null, null, null, null);
        if (cursor != null) {
            StringBuilder builder = new StringBuilder();
            builder.append(" student表資料:\n");
            while (cursor.moveToNext()) {
                builder.append("name: " + cursor.getString(cursor.getColumnIndex("name")) +
                        "  age: " + cursor.getInt(cursor.getColumnIndex("age")) +
                        "  sex: " + cursor.getString(cursor.getColumnIndex("sex")) + "\n");
            }
            ((TextView) findViewById(R.id.dbData)).setText(builder.toString());
        }
    }


    public void queryTeacherTab(View view) {
        Uri uri = Uri.parse("content://com.hfut.operationcontentproviderb/teacher");
        Cursor cursor = getContentResolver().query(uri, null, null, null, null);
        if (cursor != null) {
            StringBuilder builder = new StringBuilder();
            builder.append(" teacher表資料:\n");
            while (cursor.moveToNext()) {
                builder.append("name: " + cursor.getString(cursor.getColumnIndex("name")) +
                        "  teacherID: " + cursor.getInt(cursor.getColumnIndex("teacherID")) +
                        "  teacherID: " + cursor.getString(cursor.getColumnIndex("subject")) + "\n");
            }
            ((TextView) findViewById(R.id.dbData)).setText(builder.toString());
        }
    }

    /**
     * 新增Tom到student表中
     *
     * @param view
     */
    public void addDataToStudent(View view) {
        Uri uri = Uri.parse("content://com.hfut.operationcontentproviderb/student");
        ContentValues contentValues = new ContentValues();
        StringBuilder builder = new StringBuilder();
        builder.append("  新增資料:\n");
        contentValues.put("name", "Tom");
        builder.append(" name:Tom ");
        contentValues.put("age", 6);
        builder.append(" age:6 ");
        contentValues.put("sex", "male");
        builder.append(" sex:male ");
        Uri newUri = getContentResolver().insert(uri, contentValues);
        Log.d(TAG, "addDataToStudent: " + newUri.getPathSegments().get(1));
        ((TextView) findViewById(R.id.dbData)).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.operationcontentprovidera.MainActivity">

    <Button
        android:id="@+id/btn1"
        android:layout_marginTop="30dp"
        android:onClick="queryStudentTab"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="查詢表student資料"
        android:textAllCaps="false"
        android:textSize="25sp" />
    <Button
        android:id="@+id/btn2"
        app:layout_constraintTop_toBottomOf="@+id/btn1"
        android:layout_marginTop="5dp"
        android:onClick="queryTeacherTab"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="查詢表teacher資料"
        android:textAllCaps="false"
        android:textSize="25sp" />
    <Button
        android:id="@+id/btn3"
        app:layout_constraintTop_toBottomOf="@+id/btn2"
        android:layout_marginTop="5dp"
        android:onClick="addDataToStudent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="新增Tom到student表中"
        android:textAllCaps="false"
        android:textSize="25sp" />

    <TextView
        android:id="@+id/dbData"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn3"
        android:textSize="25sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</android.support.constraint.ConstraintLayout>

到這裡,所有的編碼就結束了。

 

 

3,效果演示

 

  • 查詢資料

  • 新增資料

到這裡,關於內容提供者的知識就介紹完了。還有幾個細節後續會補充一下,今天就到這裡了