Four components of Android (3) ContentProvider

Posted by huntrguy102 on Fri, 05 Jul 2019 19:23:07 +0200

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)

  1. Define a content provider, define a class that inherits from ContentProvider
  2. 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>
    
  3. Define a UriMatcher

    private static final UriMatcher sURIMatcher = new UriMatcher(
        UriMatcher.NO_MATCH);
    
  4. 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);
    }
    
  5. Expose the methods you want to expose to implement query(),insert(), and so on, following the matching rules we added

  6. 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.

  1. 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)
  2. The contact_id in the raw_contacts table is raw_contact_id of the data table

Query Contact Step:

  1. Query the contact_id column of the raw_contacts table to see how many contacts there are
  2. I query the data table, the data1 column, and the mimetype column based on contact_id
  3. 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

  1. 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()));
    
  2. 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);
        }
    
    }
    
  3. Scenario: SMS Monitor

Topics: Database Android