安卓四大组件之一——ContentProvider

ContenProvider简介

定义及作用

ContendProvider是不同应用程序之间进行数据交换的标准API,ContentProvider以某种Uri的形式对外提供数据,允许其他应用访问或修改数据;其他应用程序使用ContentReslover根据Uri去访问操作指定数据,是Android四大组件之一,主要的作用是:实现各个应用程序之间的(跨应用)数据共享。
ContentProvider提供了在应用程序之前共享数据的一种机制。
1.存储和获取数据提供了统一的接口。
2.对数据进行封装,不用关心数据存储的细节。
3.Android为常见的一些数据提供了默认的ContentProvider(包括音频、视频、图片和通讯录等)。

使用方法

(参考博客)

统一资源标识符(URI)

定义:Uniform Resource Identifier,即统一资源标识符
作用:唯一标识 ContentProvider和其中的数据,外界进程通过URI找到对应的ContentProvider和其中的数据,再进行数据操作
具体使用:URI分为系统预置和自定义,分别对应系统内置的数据(如通讯录、日程表等等)和自定义数据库
在这里插入图片描述

// 设置URI
Uri uri = Uri.parse("content://xxxxxx/User/1") 
// 上述URI指向的资源是:名为 `com.carson.provider`的`ContentProvider` 中表名 为`User` 中的 `id`为1的数据
// 特别注意:URI模式存在匹配通配符* & #
// *:匹配任意长度的任何有效字符的字符串
// 以下的URI 表示 匹配provider的任何内容
content://com.example.app.provider/* 
// #:匹配任意长度的数字字符的字符串
// 以下的URI 表示 匹配provider中的table表的所有行
content://com.example.app.provider/table/# 

ContentProvider类

组织数据方式:ContentProvider主要以表格的形式组织数据,同时也支持文件数据,只是表格形式用得比较多,每个表格中包含多张表,每张表包含行和列,分别对应记录和字段,同数据库
使用方法:进程间共享数据的本质是:添加、删除、获取和修改(更新)数据,所以ContentProvider的核心方法也主要是上述4个作用

<-- 4个核心方法 -->
  public Uri insert(Uri uri, ContentValues values) 
  // 外部进程向 ContentProvider 中添加数据
  public int delete(Uri uri, String selection, String[] selectionArgs) 
  // 外部进程 删除 ContentProvider 中的数据
  public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
  // 外部进程更新 ContentProvider 中的数据
  public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,  String sortOrder)  
  // 外部应用 获取 ContentProvider 中的数据
// 注:
  // 1. 上述4个方法由外部进程回调,并运行在ContentProvider进程的Binder线程池中(不是主线程)
 // 2. 存在多线程并发访问,需要实现线程同步
   // a. 若ContentProvider的数据存储方式是使用SQLite & 一个,则不需要,因为SQLite内部实现好了线程同步,若是多个SQLite则需要,因为SQL对象之间无法进行线程同步
  // b. 若ContentProvider的数据存储方式是内存,则需要自己实现线程同步
<-- 2个其他方法 -->
public boolean onCreate() 
// ContentProvider创建后 或 打开系统后其它进程第一次访问该ContentProvider时 由系统进行调用
// 注:运行在ContentProvider进程的主线程,故不能做耗时操作
public String getType(Uri uri)
// 得到数据类型,即返回当前 Url 所代表数据的MIME类型

Android为常见的数据(如通讯录、日程表等)提供了内置了默认的ContentProvider,也可根据需求自定义ContentProvider,但上述6个方法必须重写,ContentProvider类并不会直接与外部进程交互,而是通过ContentResolver 类

ContentResolver类

作用:统一管理不同 ContentProvider间的操作,即通过URI即可操作 不同的ContentProvider 中的数据,外部进程通过 ContentResolver类从而与ContentProvider类进行交互
使用方法:ContentResolver 类提供了与ContentProvider类相同名字和作用的4个方法

// 外部进程向 ContentProvider 中添加数据
public Uri insert(Uri uri, ContentValues values)  
// 外部进程 删除 ContentProvider 中的数据
public int delete(Uri uri, String selection, String[] selectionArgs)
// 外部进程更新 ContentProvider 中的数据
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)  
// 外部应用 获取 ContentProvider 中的数据
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
// 使用ContentResolver前,需要先获取ContentResolver
// 可通过在所有继承Context的类中 通过调用getContentResolver()来获得ContentResolver
ContentResolver resolver =  getContentResolver(); 
// 设置ContentProvider的URI
Uri uri = Uri.parse("content://xxxxxx/user"); 
// 根据URI 操作 ContentProvider中的数据
// 此处是获取ContentProvider中 user表的所有记录 
Cursor cursor = resolver.query(uri, null, null, null, "userid desc"); 

ContentUris类

作用:操作 URI
具体使用:核心方法有两个:withAppendedId()和parseId()

// withAppendedId()作用:向URI追加一个id
Uri uri = Uri.parse("content://xxxxxx/user") 
Uri resultUri = ContentUris.withAppendedId(uri, 7);  
// 最终生成后的Uri为:content://xxxxxx/user/7
// parseId()作用:从URL中获取ID
Uri uri = Uri.parse("content://xxxxxx/user/7") 
long personid = ContentUris.parseId(uri); 
//获取的结果为:7

ContenProvider实例(SQLite增加数据)

需要在resolver的manifest文件中添加授权信息

 <queries>
        <package android:name="com.example.contentprovider"></package>
 </queries>

绿色部分为即将调用该程序的app包名,在provider程序的任意java文件首部可以查看

ContentProvider类

Provider页面设计

在这里插入图片描述
相关参数代码

<?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="contentprovider"
        android:textSize="35sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.338" />

</androidx.constraintlayout.widget.ConstraintLayout>

Java文件

MainActivity
package com.example.contentprovider;

import androidx.appcompat.app.AppCompatActivity;

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

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
MyDAO
package com.example.contentprovider;

import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

public class MyDAO {
    private Context context;
    private SQLiteDatabase database;
    public MyDAO(Context context){
        this.context = context;
        MyDBhelper dBhelper = new MyDBhelper(context,"wzyDB",null,1);
        database = dBhelper.getWritableDatabase();
    }

    public Uri DAOinsert(ContentValues contentValues){
        long rowid = database.insert("student",null,contentValues);
        Uri uri=Uri.parse("content://wzy.provider2");
        Uri inserturi = ContentUris.withAppendedId(uri,rowid);
        context.getContentResolver().notifyChange(inserturi,null);
        return inserturi;
    }
}
MyDBhelper
package com.example.contentprovider;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

import androidx.annotation.Nullable;

public class MyDBhelper extends SQLiteOpenHelper {      //名字            nullable允许为null 游标工厂
    public MyDBhelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        Log.d("wzy","MyDBhelper is run....");
    }
    //未定义数据库访问规则 所以onCreate无法启用
    @Override  //建表
    public void onCreate(SQLiteDatabase sqLiteDatabse) {
        //建table表
        sqLiteDatabse.execSQL("create table student(id integer primary key autoincrement,name varchar,age integer)");
        Log.d("wzy","oncreate is run....");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}
MyContentProvider

右键新建contentprovider类
在这里插入图片描述
使用默认的classname,填写自定义的URI授权信息
在这里插入图片描述

ContentResolver类

Resolver页面设计

在这里插入图片描述
相关控件参数代码

<?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:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="resovler"
        android:textSize="35sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.399" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Insert"
        android:textSize="35sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.554" />

</androidx.constraintlayout.widget.ConstraintLayout>

Java文件

MainActivity
package com.example.resovler;

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 {

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

        ContentResolver resolver = getContentResolver();

        ContentValues values = new ContentValues();
        values.put("name","wzy");
        values.put("age",20);

        Uri uri=Uri.parse("content://wzy.provider2/student");

        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                resolver.insert(uri,values);
            }
        });
    }
}

运行结果展示

打开名为provider的app,并通过App Inspection查询数据库
实验数据库及表已经被创建,还未插入数据,表为空
在这里插入图片描述
在这里插入图片描述
先在resolver项目下运行app后退出,再在provider的模拟机中打开resolver app,点击insert,刷新数据库,数据插入成功
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Clone地址

gitee地址无效请直接搜索https://gitee.com/waiaiy/android.git

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值