ContentProvider与ContentResolver

一、ContentProvider:

1.定义:

ContentProvider相当于一个接口,该接口的作用是对外暴露本APP的数据。
当我们想允许本应用的数据可以被别的应用进行读取,可以让本的APP实现ContentProvider类,同时注册一个URI,然后其他应用只要使用ContentResolver访问指定URI就可以操作我们APP里的数据了。

2.使用步骤:

ContentProvider为数据定义一个URI,其他Application想要操作本Application中的数据时,只需要获得一个ContentResolver对象并传入相应的URI,即可操作本Application中 URI 下的数据。

请添加图片描述

第一步.创建类继承ContentProvider:

需要重写onCreate( )、delete( )、getType( )、insert( )、query( )、update( )方法。
其中增删查改方法可以用来操作本应用的SQLite数据库

package com.example.myapplication;

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 MyContentProvider extends ContentProvider{
    /*创建ContentProvider时调用,其他应用程序第一次访问ContentProvider时,该ContentProvider会被创建出来,立即回调该方法
     */
    @Override
    public boolean onCreate() {
        return false;

    }
    /*根据ContentProvider传来的属性字段查询数据库中指定条件下的数据
            projection:要查询的列名
            selection:where子句的内容
            selectionArgs:selection中对应的参数
            sortOrder:排序规则
     */
    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        return null;
    }
    /*用于返回指定URI代表的数据的MIME类型
     */
    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }
    /*根据ContentProvider传来的属性字段插入contentValues中的的数据到数据库
     */
    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
        return null;
    }
    /*根据ContentProvider传来的属性字段删除数据库中where条件匹配的数据信息
     */
    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }
    /*根据ContentProvider传来的属性字段更新更新where条件匹配的数据为contentValues
     */
    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {
        return 0;
    }
}

第二步:注册ContentProvider:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApplication">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!--属性依次为:全限定类名,用于匹配的URI,是否对外暴露数据 -->
        <!--只有与uri.mycontentprovider该URI有关的请求才会被该应用捕获并处理-->
        <provider
            android:name="com.example.myapplication.MyContentProvider"
            android:authorities="uri.mycontentprovider"
            android:exported="true"/>
    </application>
</manifest>

二、URI:

请添加图片描述

每个对外暴露数据的Application都必须有一个URI,其他Application通过该URI访问本应用的数据。

1.常用方法:

//字符串转URI
Uri uri = Uri.parse("uri.mycontentprovider");
//获取uri中数据部分存入一个List中
List<String> segments = uri.getPathSegments();

2.解析URI:

请添加图片描述

不同URI代表着不同的操作,所以当ContentProvider接收到URI时,我们需要解析URI才能知道该条URI想进行什么操作。

(1)UriMatcher解析URI:

定义:

UriMatcher类用于匹配Uri。当应用程序通过URI访问ContentProvider时,UriMatcher用于检查URI是否符合我们预先定义好的若干条规则,如果符合某条规则,则可使用该URI,返回该条规则的匹配码。

使用步骤:
第一步:创建UriMatcher
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);//常量UriMatcher.NO_MATCH表示Uri不匹配时的返回码
第二步:设置URI匹配规则

ContentProvider接收到外部发来的请求URI后会根据匹配规则进行匹配。

matcher.addURI("uri.mycontentprovider", "studentall", 1);//查询所有学生记录,如果URI为:uri.mycontentprovider/studentall时会返回1
matcher.addURI("uri.mycontentprovider", "students/*", 2);//根据学号和姓名模糊查询获得多个记录。*是字符通配符,可以匹配任何字符,例如:将来可以匹配students/stuId="+stuId+"&stuName="+stuName
matcher.addURI("uri.mycontentprovider", "student/#", 3);//单个学生,需要根据studentid来判断,#是数字通配符,可以匹配任何数字,例如:将来可以匹配student/001,student/002等
matcher.addURI("uri.mycontentprovider", "insertStudent", 4);//插入学生
matcher.addURI("uri.mycontentprovider", "deleteStudent", 5);//删除单个学生,需要根据studentid来判断,#将来调用时实参使用学号来代替
matcher.addURI("uri.mycontentprovider", "updateStudent", 6);//修改学生信息
第三步:在需要匹配的地方调用match()方法检查是否匹配
//点击”查询全部学生“按钮时,ContentResolver会执行query方法,发送URI,ContentProvider捕获到该URI后需要判断匹配规则是否符合,符合才执行查询操作
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        switch (matcher.match(Uri.parse("uri.mycontentprovider/studentall"))){
            //URI符合我们设置的匹配规则
            case 1:{
                //查询操作
            }
            //URI不匹配
            default:{
                break;
            }
        }    
    }
});

(2)ContentUris解析URI:

ContentUris类用于操作Uri路径后面的ID(唯一标识符)部分。

/*
public static Uri withAppendedId (Uri contentUri, long id):用于为路径加上ID部分。
*/
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person");
Uri resultUri = ContentUris.withAppendedId(uri, 10);
//生成后的Uri为:content://cn.itcast.provider.personprovider/person/10

/*
public static long parseId (Uri contentUri)该方法用于从路径中获取ID部分。
*/
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person/10")
long personid = ContentUris.parseId(uri);//获取的结果为:10

三、ContentResolver:

1.定义:

当外部应用需要对ContentProvider中的数据进行增删改查操作时,可以使用ContentResolver类完成。

2.使用步骤:

第一步:获取ContentResolver对象

通过Activity的静态方法获取ContentResolver对象。

ContentResolver resolver = this.getContentResolver();

第二步:使用ContentResolver对象进行增删查改

ContentResolver 类提供了与ContentProvider 类相同签名的四个方法,通过给这些方法提供ContentProvider的URI使得这些方法能够调用ContenProvider中与之对应的CRUD方法,并得到返回的结果。
请添加图片描述

ContentResolver resolver = this.getContentResolver();
/*根据传入的URI查询指定条件下的数据
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
*/
resolver.query(ContentProviderURI,SQL参数...);
/*根据传入的URI插入contentValues对应的数据
public Uri insert(Uri uri, ContentValues values)
*/
resolver.insert(ContentProviderURI,SQL参数...);
/*根据传入的URI删除where条件匹配的所有数据
public int delete(Uri uri, String selection, String[] selectionArgs)
*/
resolver.delete(ContentProviderURI,SQL参数...);
/*根据传入的URI更新更新where条件匹配的数据为contentValues
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
*/
resolver.update(ContentProviderURI,SQL参数...);

四、ContentObserve监听器:

1.定义:

用于监听ContentProvider中单个URI下数据的变化。

2.使用步骤:

第一步:设置ContentProvider发送通知

在ContentProvider 能使数据发生变化的方法中 调用以下方法:

//该方法的作用是:通知注册在该URI:content://uri.mycontentprovider/studentall上的监听器:该URI上的数据发生变化
this.getContext().getContentResolver().notifyChange(Uri.parse("content://uri.mycontentprovider/studentall"), null);        

第二步:创建类并继承ContentObserver类

需要重写构造方法和onChange方法。

class MyContentObserve extends ContentObserver{
    /*
    当观察到Uri代表的数据发生变化时,会触发该方法
     */
    @Override
    public void onChange(boolean selfChange, @Nullable Uri uri) {
		//消息弹框,通知所有注册了监听的Application该URI下的数据发生变化
        Toast.makeText(MainActivity.this,"来自ContentObserver的通知:ContentProvider的数据发生改变",Toast.LENGTH_LONG).show();
    }

    public MyContentObserve(Handler handler) {
        super(handler);
    }
}

第三步:ContentResolver中开启监听:

在需要进行监听的位置加入下面的代码,当该URI下的数据发生变化时,ContentProvider会发送通知,然后就会被下面的代码接收到通知,接收到通知后会调用MyContentObserve的onChange方法

//获取ContentResolver
ContentResolver resolver = this.getContentResolver();
//注册ContentObserver的监听器,当uri="content://uri.mycontentprovider/studentall"的数据有变化时,就触发,回调MyObserver对象的onChange(boolean selfChange, Uri uri)方法
contentResolver.registerContentObserver(Uri.parse("content://uri.mycontentprovider/studentall"),true,new MyContentObserve(new Handler()));

五、案例:对外部Application的数据库进行CRUD:

1.项目结构:

数据库位于app中,app2访问app的数据库进行增删查改。
在这里插入图片描述

2.app:

(1)ContentProvider:
package com.example.myapplication;

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

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

import java.util.List;

public class MyContentProvider extends ContentProvider{
    //数据库对象,MyContentProvider是用来对外暴露数据库数据的
    private MySQLiteOpenHelper openHelper;
    //URI解析器
    private UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);

    /*创建ContentProvider时调用,其他应用程序第一次访问ContentProvider时,该ContentProvider会被创建出来,立即回调该方法
     */
    @Override
    public boolean onCreate() {
        //获得数据库dbHelper对象,将来用它得到SQLLiteDatabase对象
        openHelper = new MySQLiteOpenHelper(this.getContext());
        //设置该ContentProvider下的URI匹配规则
        //当ContentResolver发送的请求为content://uri.mycontentprovider/studentall时,会执行匹配码1对应的方法
        matcher.addURI("uri.mycontentprovider","studentall",1);
        //当ContentResolver发送的请求为content://uri.mycontentprovider/student/......时,会执行匹配码2对应的方法
        matcher.addURI("uri.mycontentprovider","student/#",2);
        //当ContentResolver发送的请求为content://uri.mycontentprovider/insertStudent时,会执行匹配码3对应的方法
        matcher.addURI("uri.mycontentprovider","insertStudent",3);
        //当ContentResolver发送的请求为content://uri.mycontentprovider/deleteStudent时,会执行匹配码4对应的方法
        matcher.addURI("uri.mycontentprovider","deleteStudent",4);
        //当ContentResolver发送的请求为content://uri.mycontentprovider/updateStudent时,会执行匹配码5对应的方法
        matcher.addURI("uri.mycontentprovider","updateStudent",5);
        return true;
    }
    /*根据ContentProvider传来的属性字段查询数据库中指定条件下的数据
            projection:要查询的列名
            selection:where子句的内容
            selectionArgs:selection中对应的参数
            sortOrder:排序规则
     */
    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        SQLiteDatabase database = openHelper.getWritableDatabase();
        Cursor cursor = null;
        //根据ContentResolver传来的URI匹配相应的匹配码,并执行匹配码下的方法
        switch (matcher.match(uri)){
            //匹配码1对应的方法
            case 1:{
                //操作本ContentProvider的数据库,根据ContentResolver传来的数据进行查询操作
                cursor = database.query("student", projection, selection, selectionArgs, "", "", sortOrder);
                break;
            }
            //匹配码2对应的方法
            case 2:{
                //操作本ContentProvider的数据库,根据ContentResolver传来的数据进行查询操作
                cursor = database.query("student", projection, selection, selectionArgs, "", "", sortOrder);
                break;
            }
            //不匹配时执行的默认方法,即ContentResolver想执行query方法但是匹配码对应不上,也就是请求的URI在ContentProvider中没有相应的匹配码
            default:{
                break;
            }
        }
        //database.close();
        //返回结果给方法调用者ContentResolver
        return cursor;
    }
    /*用于返回指定URI代表的数据的MIME类型
     */
    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }
    /*根据ContentProvider传来的属性字段插入contentValues中的的数据到数据库
     */
    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
        SQLiteDatabase database = openHelper.getWritableDatabase();
        //根据ContentResolver传来的URI匹配相应的匹配码,并执行匹配码下的方法
        switch (matcher.match(uri)){
            //匹配码3对应的方法
            case 3:{
                //操作本ContentProvider的数据库,根据ContentResolver传来的数据执行插入操作
                database.insert("student",null,contentValues);
                //发送通知给所有注册了监听的ContentResolver,告诉它们数据库中的信息发生改变
                this.getContext().getContentResolver().notifyChange(Uri.parse("content://uri.mycontentprovider/studentall"), null);
                break;
            }
            //不匹配时执行的默认方法,即ContentResolver想执行query方法但是匹配码对应不上,也就是请求的URI在ContentProvider中没有相应的匹配码
            default:{
                break;
            }
        }
        //database.close();
        //返回结果给方法调用者ContentResolver
        return uri;
    }
    /*根据ContentProvider传来的属性字段删除数据库中where条件匹配的数据信息
     */
    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        SQLiteDatabase database = openHelper.getWritableDatabase();
        int i =0;
        //根据ContentResolver传来的URI匹配相应的匹配码,并执行匹配码下的方法
        switch (matcher.match(uri)){
            //匹配码4对应的方法
            case 4:{
                //操作本ContentProvider的数据库,根据ContentResolver传来的数据执行删除操作
                i = database.delete("student", selection, selectionArgs);
                //发送通知给所有注册了监听的ContentResolver,告诉它们数据库中的信息发生改变
                this.getContext().getContentResolver().notifyChange(Uri.parse("content://uri.mycontentprovider/studentall"), null);
                break;
            }
            //不匹配时执行的默认方法,即ContentResolver想执行query方法但是匹配码对应不上,也就是请求的URI在ContentProvider中没有相应的匹配码
            default:{
                break;
            }
        }
        //database.close();
        //返回结果给方法调用者ContentResolver
        return i;
    }
    /*根据ContentProvider传来的属性字段更新更新where条件匹配的数据为contentValues
     */
    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String selection, @Nullable String[] selectionArgs) {
        SQLiteDatabase database = openHelper.getWritableDatabase();
        int i = 0;
        //根据ContentResolver传来的URI匹配相应的匹配码,并执行匹配码下的方法
        switch (matcher.match(uri)){
            //匹配码5对应的方法
            case 5:{
                //操作本ContentProvider的数据库,根据ContentResolver传来的数据执行更新操作
                i = database.update("student",contentValues, selection, selectionArgs);
                //发送通知给所有注册了监听的ContentResolver,告诉它们数据库中的信息发生改变
                this.getContext().getContentResolver().notifyChange(Uri.parse("content://uri.mycontentprovider/studentall"), null);
                break;
            }
            //不匹配时执行的默认方法,即ContentResolver想执行query方法但是匹配码对应不上,也就是请求的URI在ContentProvider中没有相应的匹配码
            default:{
                break;
            }
        }
        //database.close();
        //返回结果给方法调用者ContentResolver
        return i;
    }
}
(2)配置文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApplication">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!--属性依次为:全限定类名,用于匹配的URI,是否对外暴露数据 -->
        <!--只有与uri.mycontentprovider该URI有关的请求才会被该应用捕获并处理-->
        <provider
            android:name="com.example.myapplication.MyContentProvider"
            android:authorities="uri.mycontentprovider"
            android:exported="true"/>
    </application>
</manifest>
(3)数据库创建类:
package com.example.myapplication;

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

import androidx.annotation.Nullable;

public class MySQLiteOpenHelper extends SQLiteOpenHelper {
    //创建数据库mydatabase
    public MySQLiteOpenHelper(@Nullable Context context) {
        super(context, "mydatabase", null, 1);
    }
    //建表student
    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL("create table student(stuId varchar(20) primary key ,stuName varchar(20) ,stuSex varchar(20) ,stuAge varchar(20))");
    }

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

3.app2:

(1)ContentResolver:
package com.example.app2;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //获取ContentResolver
        ContentResolver resolver = this.getContentResolver();
        //获取控件对象
        EditText stuId = findViewById(R.id.stuId);
        EditText stuName = findViewById(R.id.stuName);
        EditText stuSex = findViewById(R.id.stuSex);
        EditText stuAge = findViewById(R.id.stuAge);
        ListView listview = findViewById(R.id.listview);
        Button addBtn = findViewById(R.id.addbtn);
        Button deleteBtn = findViewById(R.id.deletebtn);
        Button selectBtn = findViewById(R.id.selectbtn);
        Button updateBtn = findViewById(R.id.updatebtn);

        //注册ContentObserver的监听器,当uri="content://uri.mycontentprovider/studentall"的数据有变化时,就触发,在MyObserver对象的onChang()方法
        resolver.registerContentObserver(Uri.parse("content://uri.mycontentprovider/studentall"),true,new MyObserver(new Handler()));

        //点击按钮插入数据
        addBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ContentValues values = new ContentValues();
                values.put("stuId",stuId.getText().toString());
                values.put("stuName",stuName.getText().toString());
                values.put("stuSex",stuSex.getText().toString());
                values.put("stuAge",stuAge.getText().toString());
                //发送请求,调用resolver的insert方法并传入URI,管理该URI的ContentProvider捕获到该请求后会执行对应的insert方法,返回结果给该请求(相当于该方法调用了ContentProvider中的inserrt方法)
                resolver.insert(Uri.parse("content://uri.mycontentprovider/insertStudent"), values);
                //消息弹框
                Toast.makeText(MainActivity.this,"远程插入成功",Toast.LENGTH_LONG).show();
                //将输入框数据置空
                stuId.setText("");
                stuName.setText("");
                stuSex.setText("");
                stuAge.setText("");
                //唤醒查询点击事件
                selectBtn.callOnClick();
            }
        });
        //点击按钮查询数据,查询需要主键_id,这是SQLite的规定
        selectBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //游标
                Cursor cursor = null;
                //根据ID判断查一条信息还是查所有学生信息
                if (stuId.getText().toString().trim().equals("")){
                    //发送请求,调用resolver的query方法并传入URI,管理该URI的ContentProvider捕获到该请求后会执行对应的query方法,返回结果给该请求
                    cursor = resolver.query(Uri.parse("content://uri.mycontentprovider/studentall"),new String[]{"stuId as _id","stuName","stuSex","stuAge"},null,null,null);
                }else{
                    //发送请求,调用resolver的query方法并传入URI,管理该URI的ContentProvider捕获到该请求后会执行对应的query方法,返回结果给该请求
                    cursor = resolver.query(Uri.parse("content://uri.mycontentprovider/student/"+stuId.getText().toString()),new String[]{"stuId as _id","stuName","stuSex","stuAge"},"_id = ?",new String[]{stuId.getText().toString()},"");
                }
                //将查询结果通过适配器渲染到listview控件中
                SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(MainActivity.this,R.layout.one,cursor,new String[]{"_id","stuName","stuSex","stuAge"},new int[]{R.id.oneid,R.id.onename,R.id.onesex,R.id.oneage});
                listview.setAdapter(cursorAdapter);
                //消息弹框
                Toast.makeText(MainActivity.this,"远程查询成功",Toast.LENGTH_LONG).show();
            }
        });
        //点击某一列表项触发该事件,将列表信息填入输入框
        listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                TextView id = view.findViewById(R.id.oneid);
                TextView name = view.findViewById(R.id.onename);
                TextView age = view.findViewById(R.id.oneage);
                TextView sex = view.findViewById(R.id.onesex);
                //获取数据
                stuId.setText(id.getText());
                stuName.setText(name.getText());
                stuSex.setText(age.getText());
                stuAge.setText(sex.getText());
            }
        });
        //点击按钮删除数据
        deleteBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //发送请求,调用resolver的delete方法并传入URI,管理该URI的ContentProvider捕获到该请求后会执行对应的delete方法,返回结果给该请求
                resolver.delete(Uri.parse("content://uri.mycontentprovider/deleteStudent"),"stuId=?",new String[]{stuId.getText().toString()});
                //消息弹框
                Toast.makeText(MainActivity.this,"远程删除成功",Toast.LENGTH_LONG).show();
                //清空输入框数据
                stuId.setText("");
                stuName.setText("");
                stuSex.setText("");
                stuAge.setText("");
                //唤醒查询点击事件
                selectBtn.callOnClick();
            }
        });
        //修改数据
        updateBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ContentValues contentValues = new ContentValues();
                contentValues.put("stuName",stuName.getText().toString());
                contentValues.put("stuAge",stuAge.getText().toString());
                contentValues.put("stuSex",stuSex.getText().toString());
                //发送请求,调用resolver的update方法并传入URI,管理该URI的ContentProvider捕获到该请求后会执行对应的delete方法,返回结果给该请求
                resolver.update(Uri.parse("content://uri.mycontentprovider/updateStudent"),contentValues,"stuId=?",new String[]{stuId.getText().toString()});
                //消息弹框
                Toast.makeText(MainActivity.this,"远程修改成功",Toast.LENGTH_LONG).show();
                //将输入框数据置空
                stuId.setText("");
                stuName.setText("");
                stuSex.setText("");
                stuAge.setText("");
                //唤醒查询点击事件
                selectBtn.callOnClick();
            }
        });
    }
    //监听器类,监听ContentProvider的某个URI下数据的变化
    class MyObserver extends ContentObserver {
        public MyObserver(Handler handler) {
            super(handler);
            Toast.makeText(MainActivity.this,"开始",Toast.LENGTH_LONG).show();
        }
        //URI下的数据发生变化时会回调该方法
        public void onChange(boolean selfChange, Uri uri) {
            //消息弹框,通知所有注册了监听的Application该URI下的数据发生变化
            Toast.makeText(MainActivity.this,"来自ContentObserver的通知:ContentProvider的数据发生改变",Toast.LENGTH_LONG).show();
        }
    }
}
(2)布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="学号:"
            android:textSize="20sp"
            android:gravity="center"/>
        <EditText
            android:id="@+id/stuId"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:drawableBottom="@drawable/border_bottom"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="姓名:"
            android:textSize="20sp"
            android:gravity="center"/>
        <EditText
            android:id="@+id/stuName"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:drawableBottom="@drawable/border_bottom"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="性别:"
            android:textSize="20sp"
            android:gravity="center"/>
        <EditText
            android:id="@+id/stuSex"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:drawableBottom="@drawable/border_bottom"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="年龄:"
            android:textSize="20sp"
            android:gravity="center"/>
        <EditText
            android:id="@+id/stuAge"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:drawableBottom="@drawable/border_bottom"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/addbtn"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="添加"/>
        <Button
            android:id="@+id/deletebtn"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="删除"/>
        <Button
            android:id="@+id/updatebtn"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="修改"/>
        <Button
            android:id="@+id/selectbtn"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="查询"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="学号"/>
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="姓名"/>
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="性别"/>
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="年龄"/>
    </LinearLayout>
    <ListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    </ListView>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:id="@+id/one">
    <TextView
        android:id="@+id/oneid"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"/>
    <TextView
        android:id="@+id/onename"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"/>
    <TextView
        android:id="@+id/onesex"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"/>
    <TextView
        android:id="@+id/oneage"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"/>
</LinearLayout>

4.运行效果:

必须先运行app创建数据库,之后才能运行app2操作app的数据库。
在这里插入图片描述

在这里插入图片描述

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姓蔡小朋友

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值