Welcome to my Android Content Provider tutorial. I’ve received many questions about this topic. I have received many questions specifically about how to access a Content Provider from another application. So here I’ll make to apps. One will function as the Content Provider and the other will access data using a Content Resolver.
I haven’t found a tutorial online that explains how easy it is to use Content Resolvers in this way, so I hope this video is very useful. All of the code follows the video below and it is heavily commented.
If you find videos like this to be useful, it helps to tell Google Plus with a click here [googleplusone]
Code From the Video
Contact Provider Code
AndroidManifest.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.newthinktank.derekbanas.contactprovider" > <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- The Content Provider is declared --> <provider android:name=".ContactProvider" android:authorities="com.newthinktank.derekbanas.contactprovider.ContactProvider" android:exported="true" android:multiprocess="true" > </provider> </application> </manifest> |
ContactProvider.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
package com.newthinktank.derekbanas.contactprovider; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.widget.Toast; import java.util.HashMap; // Contact Providers allow applications to share data using an API // The interface provides access using delete, insert, query and update methods public class ContactProvider extends ContentProvider{ // The Java namespace for the Content Provider static final String PROVIDER_NAME = "com.newthinktank.derekbanas.contactprovider.ContactProvider"; // Assigned to a content provider so any application can access it // cpcontacts is the virtual directory in the provider static final String URL = "content://" + PROVIDER_NAME + "/cpcontacts"; static final Uri CONTENT_URL = Uri.parse(URL); static final String id = "id"; static final String name = "name"; static final int uriCode = 1; private static HashMap<String, String> values; // Used to match uris with Content Providers static final UriMatcher uriMatcher; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(PROVIDER_NAME, "cpcontacts", uriCode); } private SQLiteDatabase sqlDB; static final String DATABASE_NAME = "myContacts"; static final String TABLE_NAME = "names"; static final int DATABASE_VERSION = 1; static final String CREATE_DB_TABLE = " CREATE TABLE " + TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, " + " name TEXT NOT NULL);"; @Override public boolean onCreate() { DatabaseHelper dbHelper = new DatabaseHelper(getContext()); sqlDB = dbHelper.getWritableDatabase(); if (sqlDB != null) { return true; } return false; } // Returns a cursor that provides read and write access to the results of the query // Uri : Links to the table in the provider (The From part of a query) // projection : an array of columns to retrieve with each row // selection : The where part of the query selection // selectionArgs : The argument part of the where (where id = 1) // sortOrder : The order by part of the query @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // Used to create a SQL query SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); // Set table to query queryBuilder.setTables(TABLE_NAME); // Used to match uris with Content Providers switch (uriMatcher.match(uri)) { case uriCode: // A projection map maps from passed column names to database column names queryBuilder.setProjectionMap(values); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } // Cursor provides read and write access to the database Cursor cursor = queryBuilder.query(sqlDB, projection, selection, selectionArgs, null, null, sortOrder); // Register to watch for URI changes cursor.setNotificationUri(getContext().getContentResolver(), uri); return cursor; } // Handles requests for the MIME type (Type of Data) of the data at the URI @Override public String getType(Uri uri) { // Used to match uris with Content Providers switch (uriMatcher.match(uri)) { // vnd.android.cursor.dir/cpcontacts states that we expect multiple pieces of data case uriCode: return "vnd.android.cursor.dir/cpcontacts"; default: throw new IllegalArgumentException("Unsupported URI: " + uri); } } // Used to insert a new row into the provider // Receives the URI (Uniform Resource Identifier) for the Content Provider and a set of values @Override public Uri insert(Uri uri, ContentValues values) { // Gets the row id after inserting a map with the keys representing the the column // names and their values. The second attribute is used when you try to insert // an empty row long rowID = sqlDB.insert(TABLE_NAME, null, values); // Verify a row has been added if (rowID > 0) { // Append the given id to the path and return a Builder used to manipulate URI // references Uri _uri = ContentUris.withAppendedId(CONTENT_URL, rowID); // getContentResolver provides access to the content model // notifyChange notifies all observers that a row was updated getContext().getContentResolver().notifyChange(_uri, null); // Return the Builder used to manipulate the URI return _uri; } Toast.makeText(getContext(), "Row Insert Failed", Toast.LENGTH_LONG).show(); return null; } // Deletes a row or a selection of rows @Override public int delete(Uri uri, String selection, String[] selectionArgs) { int rowsDeleted = 0; // Used to match uris with Content Providers switch (uriMatcher.match(uri)) { case uriCode: rowsDeleted = sqlDB.delete(TABLE_NAME, selection, selectionArgs); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } // getContentResolver provides access to the content model // notifyChange notifies all observers that a row was updated getContext().getContentResolver().notifyChange(uri, null); return rowsDeleted; } // Used to update a row or a selection of rows // Returns to number of rows updated @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int rowsUpdated = 0; // Used to match uris with Content Providers switch (uriMatcher.match(uri)) { case uriCode: // Update the row or rows of data rowsUpdated = sqlDB.update(TABLE_NAME, values, selection, selectionArgs); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } // getContentResolver provides access to the content model // notifyChange notifies all observers that a row was updated getContext().getContentResolver().notifyChange(uri, null); return rowsUpdated; } // Creates and manages our database private static class DatabaseHelper extends SQLiteOpenHelper { DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase sqlDB) { sqlDB.execSQL(CREATE_DB_TABLE); } // Recreates the table when the database needs to be upgraded @Override public void onUpgrade(SQLiteDatabase sqlDB, int oldVersion, int newVersion) { sqlDB.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); onCreate(sqlDB); } } } |
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
package com.newthinktank.derekbanas.contactprovider; import android.app.Activity; import android.content.ContentValues; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends Activity { EditText contactNameEditText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); contactNameEditText = (EditText) findViewById(R.id.contactNameEditText); } public void addName(View view) { // Get the name supplied String name = contactNameEditText.getText().toString(); // Stores a key value pair ContentValues values = new ContentValues(); values.put(ContactProvider.name, name); // Provides access to other applications Content Providers Uri uri = getContentResolver().insert(ContactProvider.CONTENT_URL, values); Toast.makeText(getBaseContext(), "New Contact Added", Toast.LENGTH_LONG) .show(); } } |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<RelativeLayout 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" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/contactNameEditText" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:hint="Add Name" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/addContactButton" android:text="Add Name" android:onClick="addName" android:layout_below="@+id/contactNameEditText" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" /> </RelativeLayout> |
Get Contacts Code
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
package com.newthinktank.derekbanas.getcontacts; import android.app.Activity; import android.content.ContentResolver; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.support.v4.content.CursorLoader; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity { // The URL used to target the content provider static final Uri CONTENT_URL = Uri.parse("content://com.newthinktank.derekbanas.contactprovider.ContactProvider/cpcontacts"); TextView contactsTextView = null; EditText deleteIDEditText, idLookupEditText, addNameEditText; CursorLoader cursorLoader; // Provides access to other applications Content Providers ContentResolver resolver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); resolver = getContentResolver(); contactsTextView = (TextView) findViewById(R.id.contactsTextView); deleteIDEditText = (EditText) findViewById(R.id.deleteIDEditText); idLookupEditText = (EditText) findViewById(R.id.idLookupEditText); addNameEditText = (EditText) findViewById(R.id.addNameEditText); getContacts(); } public void getContacts(){ // Projection contains the columns we want String[] projection = new String[]{"id", "name"}; // Pass the URL, projection and I'll cover the other options below Cursor cursor = resolver.query(CONTENT_URL, projection, null, null, null); String contactList = ""; // Cycle through and display every row of data if(cursor.moveToFirst()){ do{ String id = cursor.getString(cursor.getColumnIndex("id")); String name = cursor.getString(cursor.getColumnIndex("name")); contactList = contactList + id + " : " + name + "\n"; }while (cursor.moveToNext()); } contactsTextView.setText(contactList); } public void deleteContact(View view) { String idToDelete = deleteIDEditText.getText().toString(); // Use the resolver to delete ids by passing the content provider url // what you are targeting with the where and the string that replaces // the ? in the where clause long idDeleted = resolver.delete(CONTENT_URL, "id = ? ", new String[]{idToDelete}); getContacts(); } public void lookupContact(View view) { // The id we want to search for String idToFind = idLookupEditText.getText().toString(); // Holds the column data we want to retrieve String[] projection = new String[]{"id", "name"}; // Pass the URL for Content Provider, the projection, // the where clause followed by the matches in an array for the ? // null is for sort order Cursor cursor = resolver.query(CONTENT_URL, projection, "id = ? ", new String[]{idToFind}, null); String contact = ""; // Cycle through our one result or print error if(cursor.moveToFirst()){ String id = cursor.getString(cursor.getColumnIndex("id")); String name = cursor.getString(cursor.getColumnIndex("name")); contact = contact + id + " : " + name + "\n"; } else { Toast.makeText(this, "Contact Not Found", Toast.LENGTH_SHORT).show(); } contactsTextView.setText(contact); } public void showContacts(View view) { getContacts(); } public void addContact(View view) { // Get the name to add String nameToAdd = addNameEditText.getText().toString(); // Put in the column name and the value ContentValues values = new ContentValues(); values.put("name", nameToAdd); // Insert the value into the Content Provider resolver.insert(CONTENT_URL, values); getContacts(); } } |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
<RelativeLayout 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" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Show Contacts" android:id="@+id/btnRetrieve" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:onClick="showContacts"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Contacts" android:id="@+id/contactsTextView" android:ems="10" android:layout_centerVertical="true" android:layout_alignRight="@+id/findContactButton" android:layout_alignEnd="@+id/findContactButton" /> <EditText android:layout_width="150dp" android:layout_height="wrap_content" android:inputType="number" android:ems="10" android:id="@+id/deleteIDEditText" android:layout_below="@+id/btnRetrieve" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:hint="ID to Delete" android:layout_marginTop="10dp"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Delete ID" android:id="@+id/deleteIDButton" android:layout_below="@+id/btnRetrieve" android:layout_toRightOf="@+id/deleteIDEditText" android:layout_toEndOf="@+id/deleteIDEditText" android:layout_marginLeft="30dp" android:layout_marginStart="30dp" android:onClick="deleteContact"/> <EditText android:layout_width="150dp" android:layout_height="wrap_content" android:inputType="number" android:ems="10" android:id="@+id/idLookupEditText" android:layout_below="@+id/deleteIDEditText" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:hint="ID to Find" android:layout_marginTop="10dp"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Find Contact" android:id="@+id/findContactButton" android:layout_below="@+id/deleteIDButton" android:layout_toRightOf="@+id/idLookupEditText" android:layout_toEndOf="@+id/idLookupEditText" android:layout_marginLeft="30dp" android:layout_marginStart="30dp" android:onClick="lookupContact"/> <EditText android:layout_width="150dp" android:layout_height="wrap_content" android:inputType="textPersonName" android:ems="10" android:id="@+id/addNameEditText" android:layout_below="@+id/idLookupEditText" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:hint="Name to Add" android:layout_marginTop="10dp"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Add Contact" android:id="@+id/addContactButton" android:layout_below="@+id/findContactButton" android:layout_alignTop="@+id/addNameEditText" android:layout_toRightOf="@+id/addNameEditText" android:layout_toEndOf="@+id/addNameEditText" android:layout_marginLeft="30dp" android:layout_marginStart="30dp" android:onClick="addContact"/> </RelativeLayout> |
Are you still considering a Unity series ?
Yes I’ll start with Open GL and libgdx first
Dude ur a very great guy.. Please make live wallpaper for android please teach us.. Others are asking money for softwares please help! God bless u
Thank you 🙂 I’ll make a wallpaper very soon. May God bless you as well.
I get the libGDX but why not Unity and what IDE would you use?
Actually I’ll first show how to create a framework for games so that they are completely understandable. I’ll then work my way up through the other frameworks.