Content provider
1. Introduction to content provider
Content provider is mainly used to realize the function of data sharing between different applications. It provides a complete mechanism to allow one program to access the data in another program, and the ring can ensure the security of the accessed data
2. Runtime permissions
1. Detailed explanation of Android permission mechanism
AndroidManifest.xml file
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
On the one hand, if the user installs the program on a device lower than 6.0, a reminder of the required permissions will pop up
On the one hand, users can view the permission of any program at any time in the application management interface
The runtime permission function is added to the 6.0 system Users do not need to authorize all permissions at one time when installing the software, but can authorize a permission application during the use of the software
2. Apply for permission when the program is running
Mobile phones lower than Android 6.0 system can work normally
<Button android:id="@+id/make_call" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Make Call"/>
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button makeCall=(Button) findViewById(R.id.make_call); makeCall.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { try { Intent intent=new Intent(Intent.ACTION_CALL); intent.setData(Uri.parse("tel:10086")); startActivity(intent); } catch (Exception e) { e.printStackTrace(); } } }); } }
Modify androidmanifest xml
<uses-permission android:name="android.permission.CALL_PHONE"/>
Above 6.0
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button makeCall = (Button) findViewById(R.id.make_call); makeCall.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Judge whether the user has been authorized Parameter 1: Context, parameter 2: specific permission name if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) { //Apply for permission from the user. Parameter 1: Activity instance, parameter 2: String array, requested permission name, parameter 3: request code ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE}, 1); } else { call(); } } }); } private void call(){ try { Intent intent=new Intent(Intent.ACTION_CALL); intent.setData(Uri.parse("tel:10086")); startActivity(intent); } catch (Exception e) { e.printStackTrace(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode){ case 1: if (grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){ call(); }else{ Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show(); } break; default: } } }
3. Access data in other programs
1. Basic usage of contentresolver
query
if(cursor!=null){ while(cursor.moveToNext()){ String column1=cursor.getString(cursor.getColumnIndex("column1")); int column2=cursor.getInt(cursor.getColumnIndex("column2")); } cursor.close(); }
increase
ContentValues values=new ContentValues(); values.put("column1","text"); values.put("column2",1); getContentResolver().insert(uri,values);
modify
ContentValues values=new ContentValues(); values.put("column1",""); getContentResolver()..update(uri,values,"column1=? and column2=?",new String[]{"text","1"});
delete
getContentResolver().delete(uri,"column2=?",new String[]{"1"});
2. Read system contact
activity_main.xml
<ListView android:id="@+id/contacts_view" android:layout_width="match_parent" android:layout_height="match_parent"/>
public class MainActivity extends AppCompatActivity { ArrayAdapter<String> adapter; List<String> contactsList=new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView contactsView=(ListView) findViewById(R.id.contacts_view); adapter=new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,contactsList); contactsView.setAdapter(adapter); if(ContextCompat.checkSelfPermission(this,Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_CONTACTS},1); }else{ readContacts(); } } //ContactsContract. CommonDataKinds. The phone () method parses a content URI string and provides an encapsulated constant content_ URL, that is, use URI The parse () method parses the result private void readContacts(){ Cursor cursor=null; try { //Query contact data cursor=getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null); if(cursor!=null){ while (cursor.moveToNext()){ //Get contact name @SuppressLint("Range") String displayName=cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); //Get contact phone number @SuppressLint("Range") String number=cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); contactsList.add(displayName+"\n"+number); } adapter.notifyDataSetChanged(); } } catch (Exception e) { e.printStackTrace(); }finally { if(cursor!=null){ cursor.close(); } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch(requestCode){ case 1: if (grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){ readContacts(); }else{ Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show(); } break; default: } } }
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_CONTACTS"/>
4. Create your own content provider
1. Steps
public class MyProvider extends ContentProvider { //Initialize the content provider The database creation and upgrade operations are usually completed here. A return of true indicates that the initialization of the content provider is successful, and a return of false indicates failure @Override public boolean onCreate() { return false; } //Query data from the content provider The uri parameter is used to determine the table, the projection parameter is used to determine which columns to query, the selection and selectionArgs parameters are used to constrain which rows to query, the sortOrder parameter is used to sort the results, and the query results are stored and returned in the Cursor object @Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) { return null; } //The corresponding MIME type is returned according to the incoming content URL @Nullable @Override public String getType(@NonNull Uri uri) { return null; } //Add a piece of data to the content provider The url parameter is used to determine the data in the table to be updated. The new data is saved in the values parameter. The selection and selectionArgs parameters are used to restrict the rows to be updated. The number of affected rows will be used as the return value @Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) { return null; } //Delete data from the content provider The uri parameter is used to determine the data in a table. The selection and selectionArgs parameters are used to restrict the deletion of those rows. The number of deleted rows is returned as the return value @Override public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) { return 0; } //Update existing data in the content provider The uri parameter is used to determine the data in the table to be updated. The new data is saved in the values parameter. The selection and selectionArgs parameters are used to restrict the rows to be updated. The number of affected rows will be returned as the return value @Override public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) { return 0; } }
A standard Uri writing method
content"//com.example.app.provider/table1 indicates that the caller expects to access the data in the table1 table of com.example.app
content"//com.example.app.provider/table1/1: indicates that the caller expects to access the data with id 1 in the table1 table of com.example.app
*: represents any string that matches any length
#: indicates a number that matches any length
A content URL format that can match any table:
content"//com.example.app.provider/*
A content URL format that can match any row of data in the table:
content"//com.example.app.provider/table/#
modify
public class MyProvider extends ContentProvider { public static final int TABLE1_DIR=0; public static final int TABLE1_ITEM=1; public static final int TABLE2_DIR=2; public static final int TABLE2_ITEM=3; public static UriMatcher uriMatcher; static { uriMatcher=new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI("com.example.app.provider","table1",TABLE1_DIR); uriMatcher.addURI("com.example.app.provider","table1/#",TABLE1_ITEM); uriMatcher.addURI("com.example.app.provider","table2",TABLE2_DIR); uriMatcher.addURI("com.example.app.provider","table2/#",TABLE2_ITEM); } ... @Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) { switch (uriMatcher.match(uri)){ case TABLE1_DIR: //Query all data in table1 table break; case TABLE1_ITEM: //Query single data in table1 table break; case TABLE2_DIR: //Query all data in table2 table break; case TABLE2_ITEM: //Query a single piece of data in table2 table break; default: break; } ... } ... }
MIME string format corresponding to a content URL:
1. Must start with vnd
2. If the content URL ends with a path, it is followed by Android cursor. Dir /, followed by Android if the content URL ends with id cursor. item/.
3. Finally connect vnd< authority>,<path>
The corresponding MIME type of content"//com.example.app.provider/table1 can be written as
vnd.android.cursor.dir/vnd.com.example.app.provider.table1
The corresponding MIME type of content"//com.example.app.provider/table1/1 can be written as
vnd.android.cursor.item/vnd.com.example.app.provider.table1
@Nullable @Override public String getType(@NonNull Uri uri) { switch (uriMatcher.match(uri)) { case TABLE1_DIR: return "vnd.android.cursor.dir/vnd.com.example.app.provider.table1"; case TABLE1_ITEM: return "vnd.android.cursor.item/vnd.com.example.app.provider.table1"; case TABLE2_DIR: return "vnd.android.cursor.dir/vnd.com.example.app.provider.table2"; case TABLE2_ITEM: return "vnd.android.cursor.item/vnd.com.example.app.provider.table2"; default: break; } return null; }
2. Realize cross program data sharing
public class DatabaseProvider extends ContentProvider { public static final int BOOK_DIR = 0; public static final int BOOK_ITEM = 1; public static final int CATEGORY_DIR = 2; public static final int CATEGORY_ITEM = 3; public static final String AUTHORITY = "com.example.databasetest.provider"; private static UriMatcher uriMatcher; private MyDatabaseHelper dbHelper; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR); uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM); uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR); uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM); } @Override public boolean onCreate() { dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 2); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // Query data SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor cursor = null; switch (uriMatcher.match(uri)) { case BOOK_DIR: cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder); break; case BOOK_ITEM: String bookId = uri.getPathSegments().get(1); cursor = db.query("Book", projection, "id = ?", new String[] { bookId }, null, null, sortOrder); break; case CATEGORY_DIR: cursor = db.query("Category", projection, selection, selectionArgs, null, null, sortOrder); break; case CATEGORY_ITEM: String categoryId = uri.getPathSegments().get(1); cursor = db.query("Category", projection, "id = ?", new String[] { categoryId }, null, null, sortOrder); break; default: break; } return cursor; } @Override public Uri insert(Uri uri, ContentValues values) { // Add data SQLiteDatabase db = dbHelper.getWritableDatabase(); Uri uriReturn = null; switch (uriMatcher.match(uri)) { case BOOK_DIR: case BOOK_ITEM: long newBookId = db.insert("Book", null, values); uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId); break; case CATEGORY_DIR: case CATEGORY_ITEM: long newCategoryId = db.insert("Category", null, values); uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId); break; default: break; } return uriReturn; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // Update data SQLiteDatabase db = dbHelper.getWritableDatabase(); int updatedRows = 0; switch (uriMatcher.match(uri)) { case BOOK_DIR: updatedRows = db.update("Book", values, selection, selectionArgs); break; case BOOK_ITEM: String bookId = uri.getPathSegments().get(1); updatedRows = db.update("Book", values, "id = ?", new String[] { bookId }); break; case CATEGORY_DIR: updatedRows = db.update("Category", values, selection, selectionArgs); break; case CATEGORY_ITEM: String categoryId = uri.getPathSegments().get(1); updatedRows = db.update("Category", values, "id = ?", new String[] { categoryId }); break; default: break; } return updatedRows; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // Delete data SQLiteDatabase db = dbHelper.getWritableDatabase(); int deletedRows = 0; switch (uriMatcher.match(uri)) { case BOOK_DIR: deletedRows = db.delete("Book", selection, selectionArgs); break; case BOOK_ITEM: String bookId = uri.getPathSegments().get(1); deletedRows = db.delete("Book", "id = ?", new String[] { bookId }); break; case CATEGORY_DIR: deletedRows = db.delete("Category", selection, selectionArgs); break; case CATEGORY_ITEM: String categoryId = uri.getPathSegments().get(1); deletedRows = db.delete("Category", "id = ?", new String[] { categoryId }); break; default: break; } return deletedRows; } @Override public String getType(Uri uri) { switch (uriMatcher.match(uri)) { case BOOK_DIR: return "vnd.android.cursor.dir/vnd.com.example.databasetest. provider.book"; case BOOK_ITEM: return "vnd.android.cursor.item/vnd.com.example.databasetest. provider.book"; case CATEGORY_DIR: return "vnd.android.cursor.dir/vnd.com.example.databasetest. provider.category"; case CATEGORY_ITEM: return "vnd.android.cursor.item/vnd.com.example.databasetest. provider.category"; } return null; } }
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" android:orientation="vertical"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Add To Book" android:id="@+id/add_data" tools:ignore="MissingConstraints" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Update Book" android:id="@+id/update_data" tools:ignore="MissingConstraints" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Delete From Book" android:id="@+id/delete_data" tools:ignore="MissingConstraints" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Query From Book" android:id="@+id/query_data" tools:ignore="MissingConstraints" /> </LinearLayout>
public class MainActivity extends AppCompatActivity { private MyDatabaseHelper dbHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2); Button createDatabase = (Button) findViewById(R.id.create_database); createDatabase.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dbHelper.getWritableDatabase(); } }); Button addData = (Button) findViewById(R.id.add_data); addData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SQLiteDatabase db = dbHelper.getWritableDatabase(); ContentValues values = new ContentValues(); // Start assembling the first data values.put("name", "The Da Vinci Code"); values.put("author", "Dan Brown"); values.put("pages", 454); values.put("price", 16.96); db.insert("Book", null, values); // Insert first data values.clear(); // Start assembling the second data values.put("name", "The Lost Symbol"); values.put("author", "Dan Brown"); values.put("pages", 510); values.put("price", 19.95); db.insert("Book", null, values); // Insert second data } }); Button updateData = (Button) findViewById(R.id.update_data); updateData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SQLiteDatabase db = dbHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("price", 10.99); db.update("Book", values, "name = ?", new String[] { "The Da Vinci Code" }); } }); Button deleteButton = (Button) findViewById(R.id.delete_data); deleteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SQLiteDatabase db = dbHelper.getWritableDatabase(); db.delete("Book", "pages > ?", new String[] { "500" }); } }); Button queryButton = (Button) findViewById(R.id.query_data); queryButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SQLiteDatabase db = dbHelper.getWritableDatabase(); // Query all data in the Book table Cursor cursor = db.query("Book", null, null, null, null, null, null); if (cursor.moveToFirst()) { do { // Traverse the Cursor object, take out the data and print String name = cursor.getString(cursor.getColumnIndex("name")); String author = cursor.getString(cursor.getColumnIndex("author")); int pages = cursor.getInt(cursor.getColumnIndex("pages")); double price = cursor.getDouble(cursor.getColumnIndex("price")); Log.d("MainActivity", "book name is " + name); Log.d("MainActivity", "book author is " + author); Log.d("MainActivity", "book pages is " + pages); Log.d("MainActivity", "book price is " + price); } while (cursor.moveToNext()); } cursor.close(); } }); } }