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>

 

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