Android - use ContentProvider to share data

Experiment Name: Sharing Data Using a ContentProvider                                                

Purpose:

(1) Can use ContentProvider to share data

(2) Can use content observers to observe data changes of other programs

Experimental content and principle:

Designing a monitoring database project requires:

  1. Ability to manipulate database data 
  2. Respond immediately when database changes

Create the project, design the interface and functions, complete the debugging of the project, and record the code and running results of the program.

Experimental equipment and experimental procedures:

Experimental equipment: Windows+Android Studio

Problems that may be encountered in configuration

1. Instead of right-clicking New-Other-Content Provider to generate content observers, AndroidManifest.xml is not registered.

Error message: INSTALL_FAILED_CONFLICTING_PROVIDER

2. Android java.lang.SecurityException: Failed to find provider exception description

This is because Android 8.0 and above have permission management. This code is relatively old, and I haven't solved it yet. You can refer to it. If you use a version below 8.0, it should be able to run. (1 message) Android java.lang.SecurityException: Failed to find provider exception description_hellopeng1's blog-CSDN blog_failed to find provider

Experimental steps:

1. Create a ContentObserverDB program

Create a program named ContentObserverDB and specify the package name as cn.itcast.contenobserverdb.

2. Import interface pictures

Set a background image. The background can be modified in drawable by yourself

3. Place button controls

Place 4 Button controls to display "Add", "Update", "Delete" and "Query" respectively. The background can be modified in drawable by yourself

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_insert"
        android:layout_width="120dp"
        android:layout_height="40dp"
        android:layout_marginLeft="40dp"
        android:layout_marginTop="30dp"
        android:background="@drawable/btn_bg"
        android:text="添加"
        android:textColor="#006000"
        android:textSize="20dp" />

    <Button
        android:id="@+id/btn_update"
        android:layout_width="120dp"
        android:layout_height="40dp"
        android:layout_marginLeft="80dp"
        android:layout_marginTop="30dp"
        android:background="@drawable/btn_bg"
        android:text="更新"
        android:textColor="#006000"
        android:textSize="20dp" />

    <Button
        android:id="@+id/btn_delete"
        android:layout_width="120dp"
        android:layout_height="40dp"
        android:layout_marginLeft="120dp"
        android:layout_marginTop="30dp"
        android:background="@drawable/btn_bg"
        android:text="删除"
        android:textColor="#006000"
        android:textSize="20dp" />

    <Button
        android:id="@+id/btn_select"
        android:layout_width="120dp"
        android:layout_height="40dp"
        android:layout_marginLeft="160dp"
        android:layout_marginTop="30dp"
        android:background="@drawable/btn_bg"
        android:text="查询"
        android:textColor="#006000"
        android:textSize="20dp" />
</LinearLayout>

4. Create database PersonDBOpenHelper.java

code show as below

package cn.itcast.contentobserverdb;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class PersonDBOpenHelper extends SQLiteOpenHelper {
    //构造方法,调用该方法创建一个person.db数据库
    public PersonDBOpenHelper(Context context) {
        super(context, "person.db", null, 1);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        //创建该数据库的同时新建一个info表,表中有_id,name这两个字段
        db.execSQL("create table info (_id integer primary key autoincrement, name varchar(20))");
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}

5. Create a content provider PersonProvider.java

You need to right-click and select New-Other-Content Provider, that is, register in AndroidManifest.xml, the code is as follows.

package cn.itcast.contentobserverdb;
//省略导包
public class PersonProvider extends ContentProvider {
    //定义一个uri路径的匹配器,如果路径匹配不成功返回-1
    private static UriMatcher mUriMatcher = new UriMatcher(-1);
    private static final int SUCCESS = 1; //匹配路径成功时的返回码
    private PersonDBOpenHelper helper;     //数据库操作类的对象
    //添加路径匹配器的规则
    static {
        mUriMatcher.addURI("cn.itcast.contentobserverdb", "info", SUCCESS);
    }
    @Override
    public boolean onCreate() { //当内容提供者被创建时调用
        helper = new PersonDBOpenHelper(getContext());
        return false;
    }
    /**
     * 查询数据操作
     */
    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        //匹配查询的Uri路径
        int code = mUriMatcher.match(uri);
        if (code == SUCCESS) {
            SQLiteDatabase db = helper.getReadableDatabase();
            return db.query("info", projection, selection, selectionArgs,
                    null, null, sortOrder);
        } else {
            throw new IllegalArgumentException("路径不正确,无法查询数据!");
        }
    }
    /**
     * 添加数据操作
     */
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        int code = mUriMatcher.match(uri);
        if (code == SUCCESS) {
            SQLiteDatabase db = helper.getReadableDatabase();
            long rowId = db.insert("info", null, values);
            if (rowId > 0) {
                Uri insertedUri = ContentUris.withAppendedId(uri, rowId);
                //提示数据库的内容变化了
                getContext().getContentResolver().notifyChange(insertedUri, null);
                return insertedUri;
            }
            db.close();
            return uri;
        } else {
            throw new IllegalArgumentException("路径不正确,无法插入数据!");
        }
    }
    /**
     * 删除数据操作
     */
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int code = mUriMatcher.match(uri);
        if (code == SUCCESS) {
            SQLiteDatabase db = helper.getWritableDatabase();
            int count = db.delete("info", selection, selectionArgs);
            //提示数据库的内容变化了
            if (count > 0) {
                getContext().getContentResolver().notifyChange(uri, null);
            }
            db.close();
            return count;
        } else {
            throw new IllegalArgumentException("路径不正确,无法随便删除数据!");
        }
    }
    /**
     * 更新数据操作
     */
    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        int code = mUriMatcher.match(uri);
        if (code == SUCCESS) {
            SQLiteDatabase db = helper.getWritableDatabase();
            int count = db.update("info", values, selection, selectionArgs);
            //提示数据库的内容变化了
            if (count > 0) {
                getContext().getContentResolver().notifyChange(uri, null);
            }
            db.close();
            return count;
        } else {
            throw new IllegalArgumentException("路径不正确,无法更新数据!");
        }
    }
    @Override
    public String getType(Uri uri) {
        return null;
    }
}

6. Write interface code MainActivity.java

package cn.itcast.contentobserverdb;
//省略导包
public class MainActivity extends AppCompatActivity implements
        View.OnClickListener {
    private ContentResolver resolver;
    private Uri uri;
    private ContentValues values;
    private Button btnInsert;
    private Button btnUpdate;
    private Button btnDelete;
    private Button btnSelect;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView(); //初始化界面
        createDB(); //创建数据库
    }
    private void initView() {
        btnInsert = findViewById(R.id.btn_insert);
        btnUpdate = findViewById(R.id.btn_update);
        btnDelete = findViewById(R.id.btn_delete);
        btnSelect = findViewById(R.id.btn_select);
        btnInsert.setOnClickListener(this);
        btnUpdate.setOnClickListener(this);
        btnDelete.setOnClickListener(this);
        btnSelect.setOnClickListener(this);
    }
    private void createDB() {
        //创建数据库并向info表中添加3条数据
        PersonDBOpenHelper helper = new PersonDBOpenHelper(this);
        SQLiteDatabase db = helper.getWritableDatabase();
        for (int i = 0; i < 3; i++) {
            ContentValues values = new ContentValues();
            values.put("name", "itcast" + i);
            db.insert("info", null, values);
        }
        db.close();
    }
    @Override
    public void onClick(View v) {
        //得到一个内容提供者的解析对象
        resolver = getContentResolver();
        //获取一个Uri路径
        uri = Uri.parse("content://cn.itcast.contentobserverdb/info");
        //新建一个ContentValues对象,该对象以key-values的形式来添加数据到数据库表中
        values = new ContentValues();
        switch (v.getId()) {
            case R.id.btn_insert:
                Random random = new Random();
                values.put("name", "add_itcast" + random.nextInt(10));
                Uri newuri = resolver.insert(uri, values);
                Toast.makeText(this, "添加成功", Toast.LENGTH_SHORT).show();
                Log.i("数据库应用", "添加");
                break;
            case R.id.btn_delete:
                //返回删除数据的条目数
                int deleteCount = resolver.delete(uri, "name=?",
                        new String[]{"itcast0"});
                Toast.makeText(this, "成功删除了" + deleteCount + "行",
                        Toast.LENGTH_SHORT).show();
                Log.i("数据库应用", "删除");
                break;
            case R.id.btn_select:
                List<Map<String, String>> data = new ArrayList<Map<String, String>>();
                //返回查询结果,是一个指向结果集的游标
                Cursor cursor = resolver.query(uri, new String[]{"_id", "name"},
                        null, null, null);
                //遍历结果集中的数据,将每一条遍历的结果存储在一个List的集合中
                while (cursor.moveToNext()) {
                    Map<String, String> map = new HashMap<String, String>();
                    map.put("_id", cursor.getString(0));
                    map.put("name", cursor.getString(1));
                    data.add(map);
                }
                //关闭游标,释放资源
                cursor.close();
                Log.i("数据库应用", "查询结果:" + data.toString());
                break;
            case R.id.btn_update:
                //将数据库info表中name为itcast1的这条记录更改为name是update_itcast
                values.put("name", "update_itcast");
                int updateCount = resolver.update(uri, values, "name=?",
                        new String[]{"itcast1"});
                Toast.makeText(this, "成功更新了" + updateCount + "行",
                        Toast.LENGTH_SHORT).show();
                Log.i("数据库应用", "更新");
                break;
        }
    }
}

7. Create a MonitorData program

Create a new project and create a program named MonitorData without setting its interface. code show as below.

package cn.itcast.monitordata;
//省略导包
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 该uri路径指向数据库应用中的数据库info表
        Uri uri = Uri.parse("content://cn.itcast.contentobserverdb/info");
        //注册内容观察者,参数uri指向要监测的数据库info表,
        //参数true定义了监测的范围,最后一个参数是一个内容观察者对象
        getContentResolver().registerContentObserver(uri, true,
                new MyObserver(new Handler()));
    }
    private class MyObserver extends ContentObserver {
        public MyObserver(Handler handler) {//handler 是一个消息处理器。
            super(handler);
        }
        @Override
        //当info表中的数据发生变化时则执行该方法
        public void onChange(boolean selfChange) {
            Log.i("监测数据变化", "有人动了你的数据库!");
            super.onChange(selfChange);
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //取消注册内容观察者
        getContentResolver().unregisterContentObserver(new MyObserver(
                new Handler()));
    }

Experimental results and analysis:

Program interface running results:

    

Access database info data:

Response result:

Content watcher response result:

Questions and thoughts:

Briefly describe how content observers work.

Content Observer (ContentObserver) is used to observe the data represented by the specified Uri. When the ContentObserver observes that the data represented by the specified Uri has changed, the onChange() method of the ContentObserver will be triggered. At this time, the changed data can be queried by using ContentResovler in the onChange() method.

Guess you like

Origin blog.csdn.net/Liwo4418/article/details/128093763