Implementation of custom ContentProvider for Android (very, very)

When I first learned the ContentProvider of the system, I didn't encounter any problems, but when I learned the implementation of custom ContentProvider, alas, I encountered several problems and spent a lot of time.

My problems:

1.  java.lang.IllegalArgumentException: column '_id' does not exist

Solution: insert a data table named_ The type of id column is self increment, because this column is required when using the Cursor related Adapter

2.Failed to find provider <authority> for user 0 ; expected to find a valid ContentProvider for

Solution: add the following code in the AndroidManifest.xml of the first application

 <provider
            android:authorities="cn.sch.myprovider"
            android:name=".MyProvide"
            android:exported="true"
            android:multiprocess="false"
            android:grantUriPermissions="true"
            android:writePermission="cn.sch.myprovider.Write"
            android:readPermission="cn.sch.myprovider.Read"
            >
        </provider>

However, when I use API 30, I still report errors and null pointer exceptions. It hasn't been solved yet. It's really a dish, so in order to make the program run, I choose API 29 to run normally

3. Note: when writing sql statements in the database class, it is most likely to make mistakes. For example, if there are no spaces, it is the wrong sql statement. The English comma is written as a Chinese comma. When adding, deleting and changing the query, the table name and column name should be written correctly

4. The authorities in uri are also very easy to make mistakes. If you make a mistake, you will report that uri cannot find an exception

5. There are many small problems that will not be described one by one. Be careful and serious. I believe you can solve them yourself

In order for you (novices, including myself) to run my program correctly, I post all classes, layout files and configuration information. If you look at the implementation of user-defined ContentProvider written by others, you will find these problems. You dare not say all of them. Most of them are like this. The implementation of user-defined ContentProvider is originally oriented to novices, so you can write all the information to learn, imitate and innovate.

1. The lack of layout files is really outrageous for a white man like me. I don't know which is which

2. Some classes are missing, not as good as database classes.

3. It's really hard for Xiaobai to post only some important code fragments

4. There is a lack of configuration information, which can only be seen. It is difficult to imitate. There are a lot of bugs waiting for you

5. The complete source code should be VIP or charged

I won't explain the detailed code in the project. Most of them have explanations. If you really don't understand it, you can baidu by yourself. It must be clearer, more detailed and easier to understand than what I said here. My article mainly allows you to implement a custom ContentProvider and run

Let's see my effect first

20211021

First take a look at my project structure, and you will know which class and layout files to write

 

 

The module gamedemo is the first application

The MainActivity code is as follows

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements View.OnClickListener {

    private static final String TAG = "lzs";
    private DbHelp dbHelp;
    private SQLiteDatabase db;
    private TextView userTv;
    private Button btn_query;
    private Button btn_insert;
    private Button btn_delete;
    private Button btn_update;
    private int m=2;
    private int n=3;
    private EditText xuhao;
    private EditText xingming;
    private EditText zhiye;
    private int id;
    private String name;
    private String job;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.dbHelp = new DbHelp(this); //Create database
        this.db = this.dbHelp.getWritableDatabase();
        init(); //Initialize control
    }

    private void init() {
        btn_query = findViewById(R.id.btn_query);
        btn_insert = findViewById(R.id.btn_insert);
        btn_delete = findViewById(R.id.btn_delete);
        btn_update = findViewById(R.id.btn_update);
        xuhao = findViewById(R.id.xuhao);
        xingming = findViewById(R.id.xingming);
        zhiye = findViewById(R.id.zhiye);

        btn_query.setOnClickListener(this);
        btn_insert.setOnClickListener(this);
        btn_delete.setOnClickListener(this);
        btn_update.setOnClickListener(this);
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        db.close();
        dbHelp.close();
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.btn_query:
                btn_query();
                break;
            case R.id.btn_insert:
                btn_insert();
                break;
            case R.id.btn_delete:
                btn_delete();
                break;
            case R.id.btn_update:
                btn_update();
                break;
        }
    }


    //Query function
    private void btn_query(){

        Cursor user = this.db.query("user", null, null, null, null, null, null);
        this.userTv = findViewById(R.id.id_user_db);

        //Clear the text to prevent repeated query and multiple display
        if(!TextUtils.isEmpty(this.userTv.getText()))
        {
            this.userTv.setText("");
        }

        while (user.moveToNext()){
            String id = user.getString(0);
            String name = user.getString(1);
            String jobs = user.getString(2);
            this.userTv.append("Serial number:"+id+"  full name:"+name+"  work:"+jobs+"\n");
        }
    }
    //Insert function (no SQL statement, Android method)
    private void btn_insert(){
        if(!TextUtils.isEmpty(xuhao.getText())&&!TextUtils.isEmpty(xingming.getText())&&!TextUtils.isEmpty(zhiye.getText())){
            id = Integer.parseInt(xuhao.getText().toString());
            name = xingming.getText().toString();
            job = zhiye.getText().toString();
            Cursor result=db.rawQuery("select * from user where _id = "+id,null);
            if(!result.isAfterLast()){
                Toast.makeText(MainActivity.this,"Failed to insert. The modified record already exists or the sequence number is duplicate!",Toast.LENGTH_SHORT).show();
            }else {
                Uri uri_user = Uri.parse("content://cn.sch.myprovider/user");
                // Insert data into user table
                ContentValues values3 = new ContentValues();
                values3.put("_id", id);
                values3.put("name", name);
                values3.put("jobs", job);
                // Get ContentResolver
                ContentResolver resolver3 = getContentResolver();
                // Insert data into ContentProvider according to URI through ContentResolver
                resolver3.insert(uri_user, values3);
                Toast.makeText(MainActivity.this,"Insert successful",Toast.LENGTH_SHORT).show();
            }

        }else {
            Toast.makeText(MainActivity.this,"Please fill in completely and cannot be blank!",Toast.LENGTH_SHORT).show();
        }
    }
    //Delete function (use SQL statement to delete, you can also delete by Android). Because the serial number is unique, you can delete it directly according to the serial number provided
    private void btn_delete(){
        if(!TextUtils.isEmpty(xuhao.getText())){
            id = Integer.parseInt(xuhao.getText().toString());
            Cursor result=db.rawQuery("select _id from user where _id="+id,null);
            if(!result.isAfterLast()){
                db.execSQL("delete from user where _id="+id);
                Toast.makeText(MainActivity.this,"Delete succeeded",Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(MainActivity.this,"Deletion failed, there is no record!",Toast.LENGTH_SHORT).show();
            }

        }else {
            Toast.makeText(MainActivity.this,"Please fill in completely and cannot be blank!",Toast.LENGTH_SHORT).show();
        }

    }
    //Update function (update with SQL statement, you can also update with Android). Because the serial number is unique, it can be changed directly according to the entered serial number
    private void btn_update(){
        if(!TextUtils.isEmpty(xuhao.getText())&&!TextUtils.isEmpty(xingming.getText())&&!TextUtils.isEmpty(zhiye.getText())){
            id = Integer.parseInt(xuhao.getText().toString());
            name = xingming.getText().toString();
            job = zhiye.getText().toString();
            Cursor result=db.rawQuery("select * from user where _id="+id,null);
            if(!result.isAfterLast()){
                db.execSQL("update user set _id="+id +" where _id="+id);
                db.execSQL("update user set name='"+name +"' where _id="+id);//Note that if set='name 'is not clear, you can look at the database knowledge again
                db.execSQL("update user set jobs='"+job +"' where _id="+id);
                Toast.makeText(MainActivity.this,"Update succeeded",Toast.LENGTH_SHORT).show();
            }else {

                Toast.makeText(MainActivity.this,"Failed to update. The modified record does not exist!",Toast.LENGTH_SHORT).show();
            }

        }else {
            Toast.makeText(MainActivity.this,"Please fill in completely and cannot be blank!",Toast.LENGTH_SHORT).show();
        }

    }

}

Layout file for MainActivity_ The main.xml code is as follows

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    android:gravity="center">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center"
        android:orientation="vertical">

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="50dp"
            android:text="First application"
            android:textSize="30dp"/>

        <TextView
            android:id="@+id/id_user_db"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="250dp"
            android:text="" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="2"
        android:gravity="center"
        android:orientation="vertical">


        <EditText
            android:id="@+id/xuhao"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="10"
            android:hint="Please enter serial number"
            android:inputType="number" />

        <EditText
            android:id="@+id/xingming"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="10"
            android:hint="Please enter your name"
            android:inputType="textPersonName" />

        <EditText
            android:id="@+id/zhiye"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="10"
            android:hint="Please enter occupation"
            android:inputType="textPersonName" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="2"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal">

            <Button
                android:id="@+id/btn_query"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:text="Query data" />

            <Button
                android:id="@+id/btn_insert"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:text="insert data" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="horizontal">

            <Button
                android:id="@+id/btn_delete"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Delete data" />

            <Button
                android:id="@+id/btn_update"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="20dp"
                android:text="Update data" />
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

The MyProvide code is as follows

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


public class MyProvide extends ContentProvider {

    private Context mContext;
    private DbHelp dbHelp = null;
    private SQLiteDatabase db = null;

    public static final String AUTHORITY = "cn.sch.myprovider";

    public static final int User_Code = 1;

    private UriMatcher mMatcher;

    @Override
    public boolean onCreate() {
        mContext = getContext();
        mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        //initialization
        // If URI resource path= content://cn.sch.myprovider/user  User, the registration code is returned_ Code
        mMatcher.addURI(AUTHORITY, "user", User_Code);

        dbHelp = new DbHelp(mContext);
        this.db = dbHelp.getWritableDatabase();
        // Initialize the data of the table
        db.execSQL("delete from user");
        db.execSQL("insert into user values(1,'xiaoming','Android Development')");
        db.execSQL("insert into user values(2,'xiaohua','Java Development')");
        return true;
    }

    @Override
    public Cursor query( Uri uri,  String[] projection, String selection,  String[] selectionArgs, String sortOrder) {
        String tableName = getTableName(uri);
        return db.query(tableName,projection,selection,selectionArgs,null,null,sortOrder,null);
    }

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

    @Override
    public Uri insert( Uri uri,  ContentValues values) {
        String tableName = getTableName(uri);
        //Insert data into a table
        db.insert(tableName,null,values);
        mContext.getContentResolver().notifyChange(uri,null);
        return uri;
    }

    @Override
    public int delete( Uri uri,  String selection,  String[] selectionArgs) {
        String tableName = getTableName(uri);
        int count=db.delete(tableName, null, null);
        if(count>0){
            getContext().getContentResolver().notifyChange(uri, null);
            return count;
        }
        return 0;
    }

    @Override
    public int update( Uri uri,  ContentValues values,  String selection,  String[] selectionArgs) {
        String tableName = getTableName(uri);
        int count = db.update(tableName, values, selection,selectionArgs);
        if(count>0){
            getContext().getContentResolver().notifyChange(uri, null);
            return count;
        }
        return 0;
    }


    private String getTableName(Uri uri) {
        String tableName = null;
        switch (mMatcher.match(uri)){
            case User_Code:
                tableName = DbHelp.USER_TABLE_NAME;
                break;
        }
        return tableName;
    }

}

DbHelp code is as follows

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

public class DbHelp extends SQLiteOpenHelper {
    // Database name
    private static final String DATABASE_NAME = "finch.db";
    // Table name
    public static final String USER_TABLE_NAME = "user";
    //Database version number
    private static final int DATABASE_VERSION = 1;

    public DbHelp(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        //Create database tables
        //be careful; If you change the data statement the second time after the first run, and only change the attribute without the table name, you will find an error when you run the App again, and the newly changed attribute does not exist
        //Solution: manually delete the created table, or delete the App and reinstall it, so that your changed properties can take effect
        db.execSQL("CREATE TABLE IF NOT EXISTS "+USER_TABLE_NAME+"(_id INTEGER PRIMARY KEY AUTOINCREMENT,"+" name TEXT,"+"jobs TEXT)");
    }

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

    }
}

AndroidManifest.xml for the first application

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

    <uses-permission android:name="android.permission.READ_PERSON_DB" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
        tools:ignore="ProtectedPermissions" />

    <uses-permission android:name="cn.sch.myprovider.Read"/>
    <uses-permission android:name="cn.sch.myprovider.Write"/>

    <permission android:name="cn.sch.myprovider.Read"
        android:label="Permission for read content provider"
        android:protectionLevel="normal"
        ></permission>

    <permission android:name="cn.sch.myprovider.Write"
        android:label="Permission for write content provider"
        android:protectionLevel="normal"
        ></permission>


    <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/Theme.MyApplication1">
        <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>

        <provider
            android:authorities="cn.sch.myprovider"
            android:name=".MyProvide"
            android:exported="true"
            android:multiprocess="false"
            android:grantUriPermissions="true"
            android:writePermission="cn.sch.myprovider.Write"
            android:readPermission="cn.sch.myprovider.Read"
            >
        </provider>
    </application>

</manifest>

build.gradle for the first application

plugins {
    id 'com.android.application'
}

android {
    compileSdk 29

    defaultConfig {
        applicationId "com.example.gamedemo"
        minSdk 21
        targetSdk 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

The module contentprovidertest is the second application

The MainActivity code is as follows

package com.example.contentprovidertest;

import android.Manifest;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "lzs";
    private TextView userTv;
    private Button btn_query2;
    private Button btn_insert2;
    private Button btn_delete2;
    private Button btn_update2;
    private EditText xuhao2;
    private EditText xingming2;
    private EditText zhiye2;
    private int id;
    private String name;
    private String job;

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

        this.userTv = findViewById(R.id.id_tv);

        //Get permissions dynamically
        if(ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)==PackageManager.PERMISSION_GRANTED
                ||ActivityCompat.checkSelfPermission
                (this, Manifest.permission.WRITE_EXTERNAL_STORAGE)==PackageManager.PERMISSION_GRANTED) {
            init(); //Initialize control
        }else {
            ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE},0x10);
        }
    }

    private void init() {

        xuhao2 = findViewById(R.id.xuhao2);
        xingming2 = findViewById(R.id.xingming2);
        zhiye2 = findViewById(R.id.zhiye2);

        btn_query2 = findViewById(R.id.btn_query2);
        btn_insert2 = findViewById(R.id.btn_insert2);
        btn_delete2 = findViewById(R.id.btn_delete2);
        btn_update2 = findViewById(R.id.btn_update2);

        btn_query2.setOnClickListener(this);
        btn_insert2.setOnClickListener(this);
        btn_delete2.setOnClickListener(this);
        btn_update2.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.btn_query2:
                btn_query2();
                break;
            case R.id.btn_insert2:
                btn_insert2();
                break;
            case R.id.btn_delete2:
                btn_delete2();
                break;
            case R.id.btn_update2:
                btn_update2();
                break;
        }
    }

    private void btn_update2() {
        id = Integer.parseInt(xuhao2.getText().toString());
        name = xingming2.getText().toString();
        job = zhiye2.getText().toString();
        if(!TextUtils.isEmpty(xuhao2.getText())&&!TextUtils.isEmpty(xingming2.getText())&&!TextUtils.isEmpty(zhiye2.getText())){
            Uri uri = Uri.parse("content://cn.sch.myprovider/user");
            ContentResolver resolver2 = getContentResolver();
            ContentValues values2 = new ContentValues();
            values2.put("_id", id);
            values2.put("name", name);
            values2.put("jobs", job);
            resolver2.update(uri,values2,"_id="+id,null);
            Toast.makeText(MainActivity.this, "Update succeeded", Toast.LENGTH_SHORT).show();
        }else {
            Toast.makeText(MainActivity.this,"Please fill in completely and cannot be blank!",Toast.LENGTH_SHORT).show();
        }

    }

    private void btn_delete2() {
        id = Integer.parseInt(xuhao2.getText().toString());
        if(!TextUtils.isEmpty(xuhao2.getText())){
            Uri uri = Uri.parse("content://cn.sch.myprovider/user");
            ContentResolver resolver2 = getContentResolver();
            resolver2.delete(uri,"_id ="+id,null);
            Toast.makeText(MainActivity.this, "Delete succeeded", Toast.LENGTH_SHORT).show();
        }else {
            Toast.makeText(MainActivity.this,"Please fill in completely and cannot be blank!",Toast.LENGTH_SHORT).show();
        }

    }

    private void btn_insert2() {

        this.userTv.setText("");
        id = Integer.parseInt(xuhao2.getText().toString());
        name = xingming2.getText().toString();
        job = zhiye2.getText().toString();
        if(!TextUtils.isEmpty(xuhao2.getText())&&!TextUtils.isEmpty(xingming2.getText())&&!TextUtils.isEmpty(zhiye2.getText())){
            Uri uri = Uri.parse("content://cn.sch.myprovider/user");
            // Insert data in table
            ContentValues values2 = new ContentValues();
            values2.put("_id", id);
            values2.put("name", name);
            values2.put("jobs", job);
            // Get ContentResolver
            ContentResolver resolver2 = getContentResolver();
            // Insert data into ContentProvider according to URI through ContentResolver
            resolver2.insert(uri, values2);
            // Query data from ContentProvider through ContentResolver
            Cursor cursor2 = resolver2.query(uri, new String[]{"_id", "name","jobs"}, null, null, null);
            while (cursor2.moveToNext()) {
                // Output all data in the table
                this.userTv.append("    Serial number:" + cursor2.getInt(0) + "    full name:" + cursor2.getString(1) +"    work:"+cursor2.getString(2)+ "\n");
            }
            Toast.makeText(MainActivity.this,"Insert successful",Toast.LENGTH_SHORT).show();
            // Close cursor
            cursor2.close();

        }else {
            Toast.makeText(MainActivity.this,"Please fill in completely and cannot be blank!",Toast.LENGTH_SHORT).show();
        }
    }

    private void btn_query2() {
        Uri uri  = Uri.parse("content://cn.sch.myprovider/user");

        Cursor query = getContentResolver().query(uri, null, null, null, null);
        //Clear the text to prevent repeated query and multiple display
        if(!TextUtils.isEmpty(this.userTv.getText()))
        {
            this.userTv.setText("");
        }
        while (query.moveToNext()) {
            int id = query.getInt(0);
            String name = query.getString(1);
            String job = query.getString(2);

            this.userTv.append("    Serial number:" + id + "    full name:" + name +"    work:"+job+ "\n");
        }
        query.close();
    }
}

Activity of MainActivity_ The main.xml code is as follows

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    android:gravity="center">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="50dp"
            android:text="Second application"
            android:textSize="30dp" />

        <TextView
            android:id="@+id/id_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="250dp"
            android:text="" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="2"
        android:gravity="center"
        android:orientation="vertical">


        <EditText
            android:id="@+id/xuhao2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="10"
            android:hint="Please enter serial number"
            android:inputType="number" />

        <EditText
            android:id="@+id/xingming2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="10"
            android:hint="Please enter your name"
            android:inputType="textPersonName" />

        <EditText
            android:id="@+id/zhiye2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="10"
            android:hint="Please enter occupation"
            android:inputType="textPersonName" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="2"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal">

            <Button
                android:id="@+id/btn_query2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:text="Query data" />

            <Button
                android:id="@+id/btn_insert2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:text="insert data" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="horizontal">

            <Button
                android:id="@+id/btn_delete2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Delete data" />

            <Button
                android:id="@+id/btn_update2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="20dp"
                android:text="Update data" />
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

AndroidManifest.xml for the second application

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

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
        tools:ignore="ProtectedPermissions" />
    <uses-permission android:name="android.permissions.READ_DATABASE"/>
    <uses-permission android:name="android.permissioms.WRITE_DATABASE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="cn.sch.myprovider.Read"/>
    <uses-permission android:name="cn.sch.myprovider.Write"/>

    <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/Theme.MyApplication1">
        <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>
    </application>

</manifest>

build.gradle for the second application

plugins {
    id 'com.android.application'
}

android {
    compileSdk 29

    defaultConfig {
        applicationId "com.example.contentprovidertest"
        minSdk 21
        targetSdk 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

If you encounter any problems, you can leave a message and solve them together.

So far, all the codes have been displayed. I hope you like it. If you think it's good, you can give me a compliment, hehe.

Tags: Java Android Android Studio

Posted on Thu, 21 Oct 2021 13:28:27 -0400 by jakeklem