ContentProvider Content Provider
1. Why do you need a content provider
ContentProvider can expose private database content. Written in a program
ContentProvider provides access to the database of the first application based on standards in other applications.
2. Implement the ContentProvider step (not commonly used in development because you want to hide data)
- Define a content provider, define a class that inherits from ContentProvider
-
Configure it in a manifest file like
<!-- Configure content providers,android:authorities Name the content provider as the only identity in this application --> <provider android:name="com.itheima.provider.AccoutProvider" android:authorities="com.itheima.provider" android:exported="true"> </provider>
-
Define a UriMatcher
private static final UriMatcher sURIMatcher = new UriMatcher( UriMatcher.NO_MATCH);
-
Write a static block of code to add matching rules
static { // Static code blocks pass in expected matches 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); }
Expose the methods you want to expose to implement query(),insert(), and so on, following the matching rules we added
-
As long as the data is exposed by the content provider, other applications access it the same way, through the content parser
ContentResolver contentResolver = mContext.getContentResolver(); Uri uri = Uri.parse("content://com.itheima.provider/query"); Cursor cursor = contentResolver.query(uri, new String[] { "name", "money" }, null, null, null); if (cursor != null && cursor.moveToFirst()) { do { String name = cursor.getString(cursor.getColumnIndex("name")); String money = cursor.getString(cursor.getColumnIndex("money")); Log.d("xfhy", "Procedure 2: name:"+name+" money:"+money); } while (cursor.moveToNext()); } else { Toast.makeText(mContext, "No data queried", Toast.LENGTH_SHORT).show(); }
3. Read Contact Cases
QQ, WeChat, Momo, etc.
- The data table data1 list contains all the information (including name, address, mailbox, etc.) for all contacts.
The raw_contact_id column is used to distinguish a total of several contact information
The mimetype_id column is used to distinguish data types (name, address, or mailbox) - The contact_id in the raw_contacts table is raw_contact_id of the data table
Query Contact Step:
- Query the contact_id column of the raw_contacts table to see how many contacts there are
- I query the data table, the data1 column, and the mimetype column based on contact_id
- view_data is a combination of data and mimetype tables
Samples from Android's first line of code book
ArrayAdapter<String> adapter; List<String> contactList = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView lv_contact = (ListView) findViewById(R.id.lv_contact); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, contactList); lv_contact.setAdapter(adapter); //Check to see if the user has authorized the right to read contacts. If equal, authorize if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { //Unequal applies for permission ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 1); } else { readContacts(); } } /** * Read Contacts */ private void readContacts() { Cursor cursor = null; try{ //Query contact data to get Cursor object cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null,null); if(cursor != null){ while(cursor.moveToNext()){ //Get Contact Name String name = cursor.getString(cursor.getColumnIndex( ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); //Get Contact Number String phone = cursor.getString(cursor.getColumnIndex( ContactsContract.CommonDataKinds.Phone.NUMBER)); contactList.add(name+"\n"+phone); } adapter.notifyDataSetChanged(); //Refresh ListView } } catch (Exception e){ e.printStackTrace(); } finally { //Last but not least, remember to close cursor if(cursor != null){ cursor.close(); } } } //This method will be transferred once for every application for this dangerous right @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); //Judge by application code 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: break; } }
Write your own full read contacts and sort them
public class ContactListActivity extends BaseActivity { private ListView lvContact; private final static String TAG = "ContactListActivity"; /** * Encapsulate contact data */ private List<HashMap<String, String>> contactList = new ArrayList<>(); /** * Contact data ready */ private final static int DATA_IS_READY = 10001; /** * key in HashMap, a collection encapsulating contact data */ private final static String CONTACT_NAME_KEY = "contact_name"; private final static String CONTACT_PHONE_KEY = "contact_phone"; /** * Adapter */ private MyContactAdapter mContactAdapter; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case DATA_IS_READY: //Initialize adapter mContactAdapter = new MyContactAdapter(); //Set adapter for ListView lvContact.setAdapter(mContactAdapter); break; default: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_contact_list); initUI(); requestReadContactPermission(); } /** * Apply for Contact Rights */ private void requestReadContactPermission() { //Apply to read contact rights first //Check to see if the user has authorized us, equal is authorized, unequal is not authorized if (ContextCompat.checkSelfPermission(this, Manifest.permission .READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { //Parameters: Context context, permission array, application code (request code only works if it is unique) ActivityCompat.requestPermissions(this, new String[]{Manifest .permission.READ_CONTACTS}, ConstantValue.MY_PERMISSIONS_READ_CONTACTS); } else { //If you already have permissions initData(); } } /** * Initialize data */ private void initData() { //1, Read Contacts Because there are many possible contacts, it may be read for a long time, and you don't want to block the main thread, so read Contacts in sub-threads new Thread(new Runnable() { @Override public void run() { //2, get the ContentResolver object through which you can query the system contact database ContentResolver contentResolver = getContentResolver(); String sortOrder = "sort_key COLLATE LOCALIZED ASC"; /* * Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) */ //3, Query contact data Cursor cursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone .CONTENT_URI , null, null, null, sortOrder); //4, if there is data, loops through the Cursor data inside if (cursor != null && cursor.moveToFirst()) { contactList.clear(); LogUtil.d(TAG, "Contact Data"); do { //Contact Name String contactName = cursor.getString(cursor.getColumnIndex (ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); //Get Contact Number String contactPhone = cursor.getString(cursor.getColumnIndex( ContactsContract.CommonDataKinds.Phone.NUMBER)); LogUtil.d(TAG, contactName + "----> " + contactPhone); //5. Determine if the contact data is empty. If any of the names or phone calls are empty, they will not be saved if (!TextUtils.isEmpty(contactName) && !TextUtils.isEmpty(contactPhone)) { HashMap<String, String> contact = new HashMap<>(); contactPhone = contactPhone.replace("-", ""); contact.put(CONTACT_NAME_KEY, contactName); contact.put(CONTACT_PHONE_KEY, contactPhone); contactList.add(contact); } } while (cursor.moveToNext()); //6, remember to close when used up cursor.close(); //7, Contact data ready, sent to main thread, update UI Message msg = Message.obtain(); msg.what = DATA_IS_READY; mHandler.sendMessage(msg); } } }).start(); } /** * Initialize UI */ private void initUI() { lvContact = (ListView) findViewById(R.id.lv_contact); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case ConstantValue.MY_PERMISSIONS_READ_CONTACTS: if (grantResults.length > 0 && grantResults[0] == PackageManager .PERMISSION_GRANTED) { //Permission application succeeded LogUtil.d(TAG, "Successful application for contact rights"); initData(); } else { //Failed to apply for permission ToastUtil.showWarning("Dear~Read contacts without authorization"); backToSetup3Activity(""); } break; default: break; } } /** * Return to Setup3Activity */ private void backToSetup3Activity(String number) { Intent intent = new Intent(); intent.putExtra(ConstantValue.EXTRA_FOR_CONTACT_NUMBER, number); setResult(REQUEST_CODE, intent); finish(); //Close current Activity } /** * ListView Adapter for */ class MyContactAdapter extends BaseAdapter { @Override public int getCount() { return contactList != null ? contactList.size() : 0; } @Override public Object getItem(int position) { return contactList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { //1, get the current item's data first HashMap<String, String> contactModel = (HashMap<String, String>) getItem(position); View view; ViewHolder viewHolder; if (convertView == null) { //2, if not previously loaded, then there is no cached View and it needs to be loaded view = View.inflate(MyApplication.getContext(), R.layout.item_contact_layout, null); viewHolder = new ViewHolder(); //3, get the control id in an option layout viewHolder.tvContactName = (TextView) view.findViewById(R.id.tv_contact_name); viewHolder.tvContactPhone = (TextView) view.findViewById(R.id.tv_contact_phone); //4, save this internal class (cached data class) into the view (cached) view.setTag(viewHolder); } else { //5, for the second load, only the previously cached data needs to be loaded view = convertView; viewHolder = (ViewHolder) view.getTag(); } //6. Set the data of the controls in the layout file viewHolder.tvContactName.setText(contactModel.get(CONTACT_NAME_KEY)); viewHolder.tvContactPhone.setText(contactModel.get(CONTACT_PHONE_KEY)); //7, return this view to the layout as the subitem return view; } /** * Used to cache all control objects on item entries */ class ViewHolder { TextView tvContactName; TextView tvContactPhone; } } }
4. Content Observer
-
The content observer is not one of the four components and does not need to be configured in the manifest file
// 1. Registered Content Watchers Uri uri = Uri.parse("content://sms/"); getContentResolver().registerContentObserver(uri, true, new MyContentObserver(new Handler()));
-
Define Content Observer
// 2. Define a content observer class MyContentObserver extends ContentObserver { public MyContentObserver(Handler handler) { super(handler); } // The monitored database, called when the database sends changes @Override public void onChange(boolean selfChange) { Log.d("xfhy", "Text Message Database Content Sending Change"); super.onChange(selfChange); } }
- Scenario: SMS Monitor