Android ContentProvider 學習記錄

概述

ContentProvider是Android中提供的專門用於不同應用間數據交互和共享的組件。

ContentProvider實際上是對SQLiteOpenHelper的進一步封裝,以一個或多個表的形式將數據呈現給外部應用,通過Uri映射來選擇需要操作數據庫中的哪個表,並對錶中的數據進行增刪改查處理。ContentProvider其底層使用了Binder來完成APP進程之間的通信,同時使用匿名共享內存來作爲共享數據的載體。ContentProvider支持訪問權限管理機制,以控制數據的訪問者及訪問方式,保證數據訪問的安全性。

 

使用ContentProvider進行數據訪問

Content Provider分爲兩類:

  • Native Content Provider
  • Custom Content Provider

 我們首先來看看Custom Content Provider,在Custom Content Provider中,又可以分爲兩個部分:Content Provider和Customer,我們接下來通過ContentProvider創建一個數據庫以及提供訪問的接口,並由Customer進行數據的插入操作。

  • Content Provider(數據提供方)的實現方法

a. create a Custom Content Prov (創建一個自定義的數據提供者)

首先我們創建一個名爲phoneProvider的應用程序

 在項目中,我們創建一個名爲MyPro的類來實現ContentProvide的功能。

package com.example.phoneprovider;
import android.content.ContentProvider;
public class MyProv extends ContentProvider {}

使用自動補全將所有繼承ContentProvider類需要實現的方法補全。

 得到代碼如下:

package com.example.phoneprovider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class MyProv extends ContentProvider {

    @Override
    public boolean onCreate() {
        return false;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
        return null;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
        return null;
    }

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

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {
        return 0;
    }
}

b. Implement query handling methods(實現訪問的處理方法)

在這裏,我們以數據庫的插入操作作爲訪問的處理方法示例。

我們需要在MyPro類中先實現 繼承 SQLiteOpenHelper 類中的方法,並通過該繼承的子類進行數據庫的訪問操作。

private static class OpenHelper extends SQLiteOpenHelper {
        public OpenHelper(Context cont ){
            super(cont,"test.db",null,1);
        }
        @Override
        public void onCreate(SQLiteDatabase sqLiteDatabase) {}

        @Override
        public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {}
    }

聲明 SQLiteDatabase 和 SQLiteOpenHelper 類的對象。

    SQLiteDatabase sqlDB = null;
    SQLiteOpenHelper oh = null;

 實現 MyPro 中的 insert 方法

@Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
        oh = new OpenHelper(getContext());
        sqlDB = oh.getWritableDatabase();
        sqlDB.insert("tb1",null,contentValues); //將提供的contentValues插入到表tb1中
        return null;
    }

我們實現完插入數據的方法,當然我們還需要在phoneProvider這個應用程序中先生成數據庫和表,我們在MainAcitivity中實現該功能,這樣,在應用程序啓動時,會自動在程序的目錄中創建數據庫 test.db 和表 tb1 。

具體生成路徑可參考:https://blog.csdn.net/GUYIIT/article/details/100591538

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SQLiteDatabase sqlDB = openOrCreateDatabase("test.db", SQLiteDatabase.CREATE_IF_NECESSARY, null);
        sqlDB.execSQL("CREATE TABLE tb1 (id INTEGER PRIMARY KEY,name TEXT,phone LONG)");
        sqlDB.close();
    }

c. Specify the URI of Content Prov (指定一個Content Prov的URI,URI是統一資源標識符)

d. Register a custom content provider(註冊一個自定義的Content provider,也就是我們需要向系統進行註冊,註冊完成之後,系統才知道有這麼一個數據源,當使用者通過地址來找的時候,系統纔可以找得到數據提供者)

那麼我們怎麼進行註冊呢?

只需要向項目中 AndroidMainfest.xml 文件的 <application> 中加入這段代碼即可。

<provider
    android:name="MyProv"
    android:authorities="com.example.phoneprovider"
    android:exported="true">
</provider>

 該段代碼中的 android:name 寫的是 ContentProvider 的類名,android:authorities 中寫的是項目的名稱,在這裏我們僅僅使用到了 provider 中的三個屬性,更多的屬性使用方法可以參考 android 的開發文檔。

到這裏,我們就實現了整個Content Provider 的應用程序了,接下來我們需要另外創建一個項目作爲 Customer (數據使用方),並利用它對我們已經寫好的 phoneProvider 這個應用程序的數據庫進行插入操作。

  • Customer(數據使用方)

我們首先創建一個名爲phoneUser的項目。

 在該項目中,我們使用按鈕觸發事件的方式,但用戶點擊按鈕時,觸發事件,向 phoneProvider 應用程序中的數據庫進行數據插入操作。因此我們需要在main_activity.xml加入一個button,並在MainActivity中定義該button的事件處理方法。

<Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        tools:layout_editor_absoluteX="167dp"
        tools:layout_editor_absoluteY="262dp" />
public class MainActivity extends AppCompatActivity {
    private  final static  String urlPro = "content://com.example.phoneprovider/tb1";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button bt1 = (Button)findViewById(R.id.button);
        bt1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

            }
        });
    }
}

 

a. ContentResolver (解析器,根據地址查找數據源) 

在 onClick 事件中定義 ContentResolver 對象,用於查找數據源。

                ContentResolver cr = getContentResolver();

定義數據源地址

                Uri url = Uri.parse(urlPro);

 進行數據的插入操作

                ContentValues cv = new ContentValues();
                cv.put("name","name1");
                cv.put("phone",135125222222L);

b. Cursor c = ContentResolver.query()   (在獲得ContentResolver之後,調用其中的query方法來返回查找的指針)

使用 ContentResolver 對象完成插入數據操作

                cr.insert(url,cv);

c. c.moveToNext()  (遍歷訪問我們所查找的數據,類似與Android中對數據庫的操作)

 

結果展示:

啓動 phoneProvider 程序

查看 phoneProvider 數據庫以及表的生成情況,可以看到已經成功生成了 test.db 以及 tb1 ,並且 tb1 中沒有任何數據。

 啓動 phoneUser 程序

點擊按鈕後,查看數據庫情況(點擊一次按鈕以及兩次按鈕的情況)

 

 

完整代碼展示:

phoneProvider

/*MainActivity.java*/

package com.example.phoneprovider;

import androidx.appcompat.app.AppCompatActivity;

import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SQLiteDatabase sqlDB = openOrCreateDatabase("test.db", SQLiteDatabase.CREATE_IF_NECESSARY, null);
        sqlDB.execSQL("CREATE TABLE tb1 (id INTEGER PRIMARY KEY,name TEXT,phone LONG)");
        sqlDB.close();
    }
}

 

/*MyPro.java*/

package com.example.phoneprovider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class MyProv extends ContentProvider {
    SQLiteDatabase sqlDB = null;
    SQLiteOpenHelper oh = null;

    @Override
    public boolean onCreate() {
        return false;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
        return null;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
        oh = new OpenHelper(getContext());
        sqlDB = oh.getWritableDatabase();
        sqlDB.insert("tb1",null,contentValues);
        return null;
    }

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

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {
        return 0;
    }

    private static class OpenHelper extends SQLiteOpenHelper {
        public OpenHelper(Context cont ){
            super(cont,"test.db",null,1);
        }
        @Override
        public void onCreate(SQLiteDatabase sqLiteDatabase) {

        }

        @Override
        public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

        }
    }
}

 

/*AndroidManifest.xml*/

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

    <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:name="MyProv"
            android:authorities="com.example.phoneprovider"
            android:exported="true">
        </provider>
    </application>

</manifest>

 

phoneUser:

/*MainActivity.java*/

package com.example.phoneuser;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {
    private  final static  String urlPro = "content://com.example.phoneprovider/tb1";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button bt1 = (Button)findViewById(R.id.button);
        bt1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ContentResolver cr = getContentResolver();
                Uri url = Uri.parse(urlPro);
                ContentValues cv = new ContentValues();
                cv.put("name","name1");
                cv.put("phone",135125222222L);
                cr.insert(url,cv);
            }
        });
    }
}

 

/*activity_main.xml*/

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        tools:layout_editor_absoluteX="167dp"
        tools:layout_editor_absoluteY="262dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章