Android Basic Training Course: Using Content Provider

    Content Provider is a 4th fundamental component of an Android app after Activity, Service and Intent. A Content Provider component supplies data from one application to others on request. Such requests are handled by the methods of the ContentResolver class. A content provider can use different ways to store it's data and the data can be stored in a database, in files, or even over a network.
    There are 2 types of Content Provider in Android: system (standard)  and user-defined Content Provider. All these standard Providers are defined in the package android.provider. The following table lists the standard providers and what they are used for:

Provider
Since    
Usage
Browser
SDK 1
Manages your web-searches, bookmarks and browsing-history.
CalendarContract
SDK 14
Manages the calendars on the user’s device.
CallLog
SDK 1
Keeps track of your call history.
Contacts
SDK 1
The old and deprecated content provider for managing contacts. You should only use this provider if you need to support an SDK prior to SDK 5!
ContactsContract
SDK 5
Deals with all aspects of contact management. Supersedes the Contacts-content provider.
MediaStore
SDK 1
The content provider responsible for all your media files like music, video and pictures.
Settings
SDK 1
Manages all global settings of your device.
UserDictionary
SDK 3
Keeps track of words you add to the default dictionary.
    In this post, I will present using the standard Content Provider in Android OS, with another one, you'll learn in next post.
    DEMO VIDEO:


Content URIs

    The most important concept to understand when dealing with content providers is the content URI. Whenever you want to access data from a content provider you have to specify a URI. URIs for content providers look like this:
<prefix>://<authority>/<data_type>/<id>
    Detail of these parts of the URI:
  • prefix: always is content:// 
  • authority: this specifies the name of the content provider, for example contacts, browser etc. For user-defined ContentProviders, this could be the fully declared name, such as info.devexchanges.contentprovider.
  • data_type: this indicates the type of data that this particular Provider provides. For example, if you are getting all the bookmarks from the Browser ContentProvider, then the data path would be people and URI would look like this content://browser/bookmarks.
  • id: the specific record requested.
    To query data in ContentProviders, we can use CursorLoader or ContentResolver.

CursorLoader

    A CursorLoader can run an asynchronous query in the background against a ContentProvider, and returns the results to Activity from which it was called. This allows the Activity to continue to interact with the user while the query is ongoing.
    When using it, declaring an instance first and make it load data in background thread, the code below will get all Media objects in Provider:
        CursorLoader loader = new CursorLoader(this, Media.EXTERNAL_CONTENT_URI, projection, null, null, null);
        Cursor c = loader.loadInBackground();
    Detail of these parts in CursorLoader constructor:
  • Context: usually is the current Activity (use with "this").
  • URI: The URI of the object(s) to access. This is the only argument that must not be null, for example:  Media.EXTERNAL_CONTENT_URI.
  •  projection: a String array indicates which columns/attributes of the objects you want to access
  • selection: the selection clause, can usually set null.
  • selectionArgs: the selection argument, can usually set null.
  • sortOrder: sorting order for data, default is null.
    After this process, data will available in a Cursor instance, we can get it for our own aim.

ContentResolver

    The 2nd way to request data in ContentProvider is using ContentResolver. The ContentResolver decides which provider to use based on the authority part of the URI. As you will see in the third part of this mini-series a content provider must provide its authority within the manifest file. From these entries Android creates a mapping between the authorities and the corresponding ContentProvider implementations to use.
    You can get the ContentResolver object by calling getContentResolver() on the Context object (usually is current Activity or Service). Like CursorLoader in initializing, this code is use to get all Browser bookmarks:
Cursor c = getContentResolver().query(Browser.BOOKMARKS_URI, projection, null, null, null);
    The return value of the query method is a Cursor instance, too. Cursors are important resources that have to be closed whenever you have no more use for them – otherwise you keep valuable resources from being released.

Sample Project

    Of course, thousand document lines are not good as an example. In this project, I will access Media, Call Log and Browser bookmarks and save data to an ArrayList and displaying them by a ListView.
    Access the Browser ContentProvider, getting all bookmarks and parse data by using ContentResolver like this:
public void accessBookmarks() {
        Toast.makeText(this, "Show all Bookmarks", Toast.LENGTH_SHORT).show();
        String[] projection = {
                Browser.BookmarkColumns.TITLE,
                Browser.BookmarkColumns.URL,
        };
        Cursor c = getContentResolver().query(Browser.BOOKMARKS_URI, projection, null, null, null);
        assert c != null;
        c.moveToFirst(); // move Cursor to the first entity
        arrayList.clear(); // reset data before querying

        while (!c.isAfterLast()) {
            int titleIndex = c.getColumnIndex(Browser.BookmarkColumns.TITLE);
            if (!c.getString(titleIndex).equals("")) {
                arrayList.add(c.getString(titleIndex));
            }
            c.moveToNext(); //go to next entity for loop
        }
        c.close();
        setListViewAdapter();
    }
    Output for this result, bookmarks will available in ListView:
    Absolutely similar with above case, get all Media from Media Store by CursorLoader:
 public void accessMediaStore() {
        Toast.makeText(this, "Show all Media Objects!", Toast.LENGTH_SHORT).show();
        String[] projection = {
                MediaStore.MediaColumns.DISPLAY_NAME,
                MediaStore.MediaColumns.DATE_ADDED,
                MediaStore.MediaColumns.MIME_TYPE
        };
        CursorLoader loader = new CursorLoader(this, Media.EXTERNAL_CONTENT_URI, projection, null, null, null);
        Cursor c = loader.loadInBackground();
        c.moveToFirst();
        arrayList.clear();

        while (!c.isAfterLast()) {
            String mediaName = MediaStore.MediaColumns.DISPLAY_NAME;
            int nameIndex = c.getColumnIndex(mediaName);
            arrayList.add(c.getString(nameIndex));
            c.moveToNext();
        }

        c.close();
        setListViewAdapter();
    }
    Output result:
    And this code will getting all calls history in Call Log:
@SuppressWarnings("PointlessBooleanExpression")
    public void accessTheCallLog() {
        Toast.makeText(this, "Get all Call logs", Toast.LENGTH_SHORT).show();
        String[] projection = new String[]{Calls.DATE, Calls.NUMBER, Calls.DURATION};

        Cursor c = getContentResolver().query(CallLog.Calls.CONTENT_URI, projection, null, null, null);

        assert c != null;
        arrayList.clear();
        c.moveToFirst();

        while (!c.isAfterLast()) {
            String phoneNumber = Calls.NUMBER;
            int phoneIndex = c.getColumnIndex(phoneNumber);
            arrayList.add(c.getString(phoneIndex));
            c.moveToNext();
        }
        c.close();
        setListViewAdapter();
    }
    Full Activity code:
package info.devexchanges.contentprovidersample;

import android.os.Bundle;
import android.provider.Browser;
import android.provider.CallLog;
import android.provider.CallLog.Calls;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio.Media;
import android.content.CursorLoader;
import android.database.Cursor;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends ActionBarActivity implements View.OnClickListener {

    private View btnGetCallLogs;
    private View btnGetBookmarks;
    private View btnGetMedia;
    private ArrayList<String> arrayList;
    private ListView listView;

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

        btnGetBookmarks = findViewById(R.id.btn_get_bookmark);
        btnGetCallLogs = findViewById(R.id.btn_get_call_log);
        btnGetMedia = findViewById(R.id.btn_get_media);
        listView = (ListView) findViewById(R.id.list_view);

        btnGetMedia.setOnClickListener(this);
        btnGetCallLogs.setOnClickListener(this);
        btnGetBookmarks.setOnClickListener(this);

        arrayList = new ArrayList<>();
    }

    @SuppressWarnings("PointlessBooleanExpression")
    public void accessTheCallLog() {
        Toast.makeText(this, "Get all Call logs", Toast.LENGTH_SHORT).show();
        String[] projection = new String[]{Calls.DATE, Calls.NUMBER, Calls.DURATION};

        Cursor c = getContentResolver().query(CallLog.Calls.CONTENT_URI, projection, null, null, null);

        assert c != null;
        arrayList.clear();
        c.moveToFirst();

        while (!c.isAfterLast()) {
            String phoneNumber = Calls.NUMBER;
            int phoneIndex = c.getColumnIndex(phoneNumber);
            arrayList.add(c.getString(phoneIndex));
            c.moveToNext();
        }
        c.close();
        setListViewAdapter();
    }


    public void accessMediaStore() {
        Toast.makeText(this, "Show all Media Objects!", Toast.LENGTH_SHORT).show();
        String[] projection = {
                MediaStore.MediaColumns.DISPLAY_NAME,
                MediaStore.MediaColumns.DATE_ADDED,
                MediaStore.MediaColumns.MIME_TYPE
        };
        CursorLoader loader = new CursorLoader(this, Media.EXTERNAL_CONTENT_URI, projection, null, null, null);
        Cursor c = loader.loadInBackground();
        c.moveToFirst();
        arrayList.clear();

        while (!c.isAfterLast()) {
            String mediaName = MediaStore.MediaColumns.DISPLAY_NAME;
            int nameIndex = c.getColumnIndex(mediaName);
            arrayList.add(c.getString(nameIndex));
            c.moveToNext();
        }

        c.close();
        setListViewAdapter();
    }

    private void setListViewAdapter() {
        ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, arrayList);
        listView.setAdapter(adapter);
    }

    public void accessBookmarks() {
        Toast.makeText(this, "Show all Bookmarks", Toast.LENGTH_SHORT).show();
        String[] projection = {
                Browser.BookmarkColumns.TITLE,
                Browser.BookmarkColumns.URL,
        };
        Cursor c = getContentResolver().query(Browser.BOOKMARKS_URI, projection, null, null, null);
        assert c != null;
        c.moveToFirst();
        arrayList.clear();

        while (!c.isAfterLast()) {
            int titleIndex = c.getColumnIndex(Browser.BookmarkColumns.TITLE);
            if (!c.getString(titleIndex).equals("")) {
                arrayList.add(c.getString(titleIndex));
            }
            c.moveToNext();
        }
        c.close();
        setListViewAdapter();
    }

    @Override
    public void onClick(View v) {
        if (v == btnGetBookmarks) {
            accessBookmarks();
        } else if (v == btnGetCallLogs) {
            accessTheCallLog();
        } else if (v == btnGetMedia) {
            accessMediaStore();
        } else {
            //????
        }
    }
}

Need more example?

    Through this post, you can learn about using system ContentProvider. Up to the next chapter, I will guide to creating your own ones. In this sample project, I only provide the code to get data from ContentProvider, and of course, you can update, delete it. I also have a post about access and configuring our Contact (a system ContentProvider) here, you can find out the way to do after query to Provider content (edit, delete, add new Contact).

References

References to official docs:
- ContentProvider: http://developer.android.com/reference/android/content/ContentProvider.html
- ContentResolver: http://developer.android.com/reference/android/content/ContentResolver.html
- CursorLoader: http://developer.android.com/reference/android/content/CursorLoader.html
- Cursor: http://developer.android.com/reference/android/database/Cursor.html
Accessing and Configuring Device Contacts post: http://www.devexchanges.info/2015/03/android-simple-contentprovider-and.html



Share


Previous post
« Prev Post
Next post
Next Post »