Android content provider example
Add the following in application tag in the manifest file, adjust the package name accordingly.
activity_content_provider.xml, layout file for the content provider main screen
fragment_content_provider.xml, layout file for the content provider fragment
fragment_version_detail.xml, layout file for the version detail screen.
version_item.xml, layout file for the version item in the list view.
Version.java, the model/pojo class for holding the Android version information.
public class Version { private String versionName; private String versionCode; private String apiLevel; private String description; public Version(String name, String version, String apiLevel, String description){ this.versionName = name; this.versionCode = version; this.apiLevel = apiLevel; this.description = description; } public String getVersionName() { return versionName; } public String getVersionCode() { return versionCode; } public String getApiLevel() { return apiLevel; } public String getDescription() { return description; } }
VersionsContract.java, the contract for database table and content provider.
public class VersionsContract { public static final String CONTENT_AUTHORITY = "com.example.androidcomponents"; public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY); public static final class VersionEntry implements BaseColumns { // table name public static final String TABLE_VERSIONS = "versions"; // columns public static final String _ID = "_id"; public static final String COLUMN_DESCRIPTION = "description"; public static final String COLUMN_VERSION_NAME = "version_name"; public static final String COLUMN_VERSION_CODE = "version_code"; public static final String COLUMN_API_LEVEL = "api_level"; // content uri public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(TABLE_VERSIONS).build(); // cursor of base type directory for multiple entries public static final String CONTENT_DIR_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + TABLE_VERSIONS; // cursor of base type item for single entry public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE +"/" + CONTENT_AUTHORITY + "/" + TABLE_VERSIONS; // insertion URIs public static Uri buildVersionsUri(long id){ return ContentUris.withAppendedId(CONTENT_URI, id); } } }
VersionsDBHelper.java, the sqlite database helper class.
public class VersionsDBHelper extends SQLiteOpenHelper { public static final String LOG_TAG = VersionsDBHelper.class.getSimpleName(); private static final String DATABASE_NAME = "android_versions.db"; private static final int DATABASE_VERSION = 2; public VersionsDBHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase sqLiteDatabase) { final String SQL_CREATE_MOVIE_TABLE = "CREATE TABLE " + VersionsContract.VersionEntry.TABLE_VERSIONS + "(" + VersionsContract.VersionEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + VersionsContract.VersionEntry.COLUMN_VERSION_NAME + " TEXT NOT NULL, " + VersionsContract.VersionEntry.COLUMN_VERSION_CODE + " TEXT NOT NULL, " + VersionsContract.VersionEntry.COLUMN_API_LEVEL + " TEXT NOT NULL, " + VersionsContract.VersionEntry.COLUMN_DESCRIPTION + " TEXT NOT NULL);"; sqLiteDatabase.execSQL(SQL_CREATE_MOVIE_TABLE); } // Upgrade database when version is changed. @Override public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) { Log.w(LOG_TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ". OLD DATA WILL BE DESTROYED"); // Drop the table sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + VersionsContract.VersionEntry.TABLE_VERSIONS); sqLiteDatabase.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" + VersionsContract.VersionEntry.TABLE_VERSIONS + "'"); // re-create database onCreate(sqLiteDatabase); } }
VersionsProvider.java, finally the content provider class for providing the version information.
public class VersionsProvider extends ContentProvider { private static final String LOG_TAG = VersionsProvider.class.getSimpleName(); private static final UriMatcher sUriMatcher = buildUriMatcher(); private VersionsDBHelper mOpenHelper; // Codes for the UriMatcher private static final int VERSION = 100; private static final int VERSION_WITH_ID = 200; private static UriMatcher buildUriMatcher() { // Build a UriMatcher by adding a specific code to return based on a match final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); final String authority = VersionsContract.CONTENT_AUTHORITY; // add a code for each type of URI you want matcher.addURI(authority, VersionsContract.VersionEntry.TABLE_VERSIONS, VERSION); matcher.addURI(authority, VersionsContract.VersionEntry.TABLE_VERSIONS + "/#", VERSION_WITH_ID); return matcher; } @Override public boolean onCreate() { mOpenHelper = new VersionsDBHelper(getContext()); return true; } @Override public String getType(Uri uri) { final int match = sUriMatcher.match(uri); switch (match) { case VERSION: { return VersionsContract.VersionEntry.CONTENT_DIR_TYPE; } case VERSION_WITH_ID: { return VersionsContract.VersionEntry.CONTENT_ITEM_TYPE; } default: { throw new UnsupportedOperationException("Unknown uri: " + uri); } } } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Cursor retCursor; switch (sUriMatcher.match(uri)) { // All versions selected case VERSION: { retCursor = mOpenHelper.getReadableDatabase().query( VersionsContract.VersionEntry.TABLE_VERSIONS, projection, selection, selectionArgs, null, null, sortOrder); return retCursor; } // Individual version based on Id selected case VERSION_WITH_ID: { retCursor = mOpenHelper.getReadableDatabase().query( VersionsContract.VersionEntry.TABLE_VERSIONS, projection, VersionsContract.VersionEntry._ID + " = ?", new String[]{String.valueOf(ContentUris.parseId(uri))}, null, null, sortOrder); return retCursor; } default: { // By default, we assume a bad URI throw new UnsupportedOperationException("Unknown uri: " + uri); } } } @Override public Uri insert(Uri uri, ContentValues values) { final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); Uri returnUri; switch (sUriMatcher.match(uri)) { case VERSION: { long _id = db.insert(VersionsContract.VersionEntry.TABLE_VERSIONS, null, values); // insert unless it is already contained in the database if (_id > 0) { returnUri = VersionsContract.VersionEntry.buildVersionsUri(_id); } else { throw new android.database.SQLException("Failed to insert row into: " + uri); } break; } default: { throw new UnsupportedOperationException("Unknown uri: " + uri); } } getContext().getContentResolver().notifyChange(uri, null); return returnUri; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); final int match = sUriMatcher.match(uri); int numDeleted; switch (match) { case VERSION: numDeleted = db.delete(VersionsContract.VersionEntry.TABLE_VERSIONS, selection, selectionArgs); // reset _ID db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" + VersionsContract.VersionEntry.TABLE_VERSIONS + "'"); break; case VERSION_WITH_ID: numDeleted = db.delete(VersionsContract.VersionEntry.TABLE_VERSIONS, VersionsContract.VersionEntry._ID + " = ?", new String[]{String.valueOf(ContentUris.parseId(uri))}); // reset _ID db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" + VersionsContract.VersionEntry.TABLE_VERSIONS + "'"); break; default: throw new UnsupportedOperationException("Unknown uri: " + uri); } return numDeleted; } @Override public int bulkInsert(Uri uri, ContentValues[] values) { final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); final int match = sUriMatcher.match(uri); switch (match) { case VERSION: // allows for multiple transactions db.beginTransaction(); // keep track of successful inserts int numInserted = 0; try { for (ContentValues value : values) { if (value == null) { throw new IllegalArgumentException("Cannot have null content values"); } long _id = -1; try { _id = db.insertOrThrow(VersionsContract.VersionEntry.TABLE_VERSIONS, null, value); } catch (SQLiteConstraintException e) { Log.w(LOG_TAG, e.toString()); } if (_id != -1) { numInserted++; } } if (numInserted > 0) { // If no errors, declare a successful transaction. // database will not populate if this is not called db.setTransactionSuccessful(); } } finally { // all transactions occur at once db.endTransaction(); } if (numInserted > 0) { // if there was successful insertion, notify the content resolver that there was a change getContext().getContentResolver().notifyChange(uri, null); } return numInserted; default: return super.bulkInsert(uri, values); } } @Override public int update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs) { final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int numUpdated = 0; if (contentValues == null) { throw new IllegalArgumentException("Cannot have null content values"); } switch (sUriMatcher.match(uri)) { case VERSION: { numUpdated = db.update(VersionsContract.VersionEntry.TABLE_VERSIONS, contentValues, selection, selectionArgs); break; } case VERSION_WITH_ID: { numUpdated = db.update(VersionsContract.VersionEntry.TABLE_VERSIONS, contentValues, VersionsContract.VersionEntry._ID + " = ?", new String[]{String.valueOf(ContentUris.parseId(uri))}); break; } default: { throw new UnsupportedOperationException("Unknown uri: " + uri); } } if (numUpdated > 0) { getContext().getContentResolver().notifyChange(uri, null); } return numUpdated; } }
ContentProviderActivity.java, the main activity for show casing the content provider example.
public class ContentProviderActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_content_provider); getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new FragmentContentProvider()).commit(); } }
FragmentContentProvider.java, the main fragment for show casing the content provider example.
public class FragmentContentProvider extends Fragment implements LoaderManager.LoaderCallbacks{ private static final String LOG_TAG = FragmentContentProvider.class.getSimpleName(); private VersionAdapter mVersionAdapter; private ListView lvVersions; private static final int CURSOR_LOADER_ID = 0; Version[] versions = { new Version("Cupcake", "1.5", "3", "The first release of Android"), new Version("Donut", "1.6", "4", "The world's information is at your fingertips – search the web, get driving directions... or just watch cat videos."), new Version("Eclair", "2.0-2.1", "5-7", "Make your home screen just how you want it. Arrange apps and widgets across multiple screens and in folders. Stunning live wallpapers " + "respond to your touch."), new Version("Froyo", "2.2-2.2.3", "8", "Voice Typing lets you input text, and Voice Actions let you control your phone, just by speaking."), new Version("GingerBread", "2.3-2.3.7", "9-10", "New sensors make Android great for gaming - so you can touch, tap, tilt, and play away."), new Version("Honeycomb", "3.0-3.2.6", "11-13", "Optimized for tablets, this release opens up new horizons wherever you are."), new Version("Ice Cream Sandwich", "4.0-4.0.4", "14-15", "Android comes of age with a new, refined design. Simple, beautiful and beyond smart."), new Version("Jelly Bean", "4.1-4.3.1", "16-18", "Android is fast and smooth with buttery graphics. With Google Now, you get just the right information at the right time."), new Version("KitKat", "4.4-4.4.4", "19-20", "Smart, simple, and truly yours. A more polished design, improved performance, and new features."), new Version("Lollipop", "5.0-5.1.1", "21-22", "A sweet new take on Android. Get the smarts of Android on screens big and small – with the right information at the right moment."), new Version("Marshmallow", "6.0–6.0.1", "23", "Now on Tap anticipates what you need in the moment. With a simple tap, you can get cards with useful information and apps that feed your need to know."), new Version("Nougat", "7.0–7.1.2", "24–25", "With more ways to make Android your own, Android Nougat is our sweetest release yet.") }; public FragmentContentProvider() { } @Override public void onActivityCreated(Bundle savedInstanceState){ Cursor c = getActivity().getContentResolver().query(VersionsContract.VersionEntry.CONTENT_URI, new String[]{VersionsContract.VersionEntry._ID}, null, null, null); if (c.getCount() == 0) { insertData(); } // initialize loader getLoaderManager().initLoader(CURSOR_LOADER_ID, null, this); super.onActivityCreated(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // inflate fragment_main layout final View rootView = inflater.inflate(R.layout.fragment_content_provider, container, false); // initialize our VersionAdapter mVersionAdapter = new VersionAdapter(getActivity(), null, 0); lvVersions = (ListView) rootView.findViewById(R.id.lv_versions); lvVersions.setAdapter(mVersionAdapter); lvVersions.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView> parent, View view, int position, long id) { // increment the position to match Database Ids indexed starting at 1 int uriId = position + 1; Uri uri = ContentUris.withAppendedId(VersionsContract.VersionEntry.CONTENT_URI, uriId); FragmentVersionDetail detailFragment = FragmentVersionDetail.newInstance(uriId, uri); getActivity().getSupportFragmentManager().beginTransaction() .replace(R.id.fragment_container, detailFragment) .addToBackStack(null).commit(); } }); return rootView; } // insert data into database public void insertData(){ ContentValues[] versionValuesArr = new ContentValues[versions.length]; for(int i = 0; i < versions.length; i++){ versionValuesArr[i] = new ContentValues(); versionValuesArr[i].put(VersionsContract.VersionEntry.COLUMN_VERSION_NAME, versions[i].getVersionName()); versionValuesArr[i].put(VersionsContract.VersionEntry.COLUMN_VERSION_CODE, versions[i].getVersionCode()); versionValuesArr[i].put(VersionsContract.VersionEntry.COLUMN_API_LEVEL, versions[i].getApiLevel()); versionValuesArr[i].put(VersionsContract.VersionEntry.COLUMN_DESCRIPTION, versions[i].getDescription()); } // bulkInsert our ContentValues array getActivity().getContentResolver().bulkInsert(VersionsContract.VersionEntry.CONTENT_URI, versionValuesArr); } // Attach loader to our versions database query, run when loader is initialized @Override public Loader onCreateLoader(int id, Bundle args){ return new CursorLoader(getActivity(), VersionsContract.VersionEntry.CONTENT_URI, null, null, null, null); } @Override public void onViewCreated(View view, Bundle savedInstanceState){ super.onViewCreated(view, savedInstanceState); } // Set the cursor in our CursorAdapter once the Cursor is loaded @Override public void onLoadFinished(Loader loader, Cursor data) { mVersionAdapter.swapCursor(data); } // reset CursorAdapter on Loader Reset @Override public void onLoaderReset(Loader loader){ mVersionAdapter.swapCursor(null); } }
VersionAdapter.java, the adapter for showing the version as a list in the ListView.
public class VersionAdapter extends CursorAdapter { public VersionAdapter(Context context, Cursor c, int flags) { super(context, c, flags); mContext = context; } @Override public View newView(Context context, Cursor cursor, ViewGroup parent){ int layoutId = R.layout.version_item; View view = LayoutInflater.from(context).inflate(layoutId, parent, false); ViewHolder viewHolder = new ViewHolder(view); view.setTag(viewHolder); return view; } @Override public void bindView(View view, Context context, Cursor cursor){ ViewHolder viewHolder = (ViewHolder) view.getTag(); int versionNameIndex = cursor.getColumnIndex(VersionsContract.VersionEntry.COLUMN_VERSION_NAME); int versionCodeIndex = cursor.getColumnIndex(VersionsContract.VersionEntry.COLUMN_VERSION_CODE); int apiLevelIndex = cursor.getColumnIndex(VersionsContract.VersionEntry.COLUMN_API_LEVEL); viewHolder.tvVersionName.setText(cursor.getString(versionNameIndex)); viewHolder.tvVersionCode.setText(cursor.getString(versionCodeIndex)); viewHolder.tvApiLevel.setText(cursor.getString(apiLevelIndex)); } public static class ViewHolder { public final TextView tvVersionName, tvVersionCode, tvApiLevel; public ViewHolder(View view){ tvVersionName = (TextView) view.findViewById(R.id.tv_version_name); tvVersionCode = (TextView) view.findViewById(R.id.tv_version_code); tvApiLevel = (TextView) view.findViewById(R.id.tv_api_level); } } }
FragmentVersionDetail.java, the fragment for showing a single version information.
public class FragmentVersionDetail extends Fragment implements LoaderManager.LoaderCallbacks{ private Cursor mDetailCursor; private int mPosition; private TextView tvVersionName, tvVersionCode, tvApiLevel, tvUri, tvVersionDescription; private Uri mUri; private static final int CURSOR_LOADER_ID = 0; public static FragmentVersionDetail newInstance(int position, Uri uri) { FragmentVersionDetail fragment = new FragmentVersionDetail(); Bundle args = new Bundle(); fragment.mPosition = position; fragment.mUri = uri; args.putInt("id", position); fragment.setArguments(args); return fragment; } public FragmentVersionDetail() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_version_detail, container, false); tvVersionName = (TextView) rootView.findViewById(R.id.tv_version_name); tvVersionCode = (TextView) rootView.findViewById(R.id.tv_version_code); tvApiLevel = (TextView) rootView.findViewById(R.id.tv_api_level); tvUri = (TextView) rootView.findViewById(R.id.tv_uri); tvVersionDescription = (TextView) rootView.findViewById(R.id.tv_version_description); Bundle args = this.getArguments(); getLoaderManager().initLoader(CURSOR_LOADER_ID, args, FragmentVersionDetail.this); return rootView; } @Override public void onDetach() { super.onDetach(); } @Override public Loader onCreateLoader(int id, Bundle args){ String selection = null; String[] selectionArgs = null; if (args != null) { selection = VersionsContract.VersionEntry._ID; selectionArgs = new String[]{String.valueOf(mPosition)}; } return new CursorLoader(getActivity(), mUri, null, selection, selectionArgs, null); } @Override public void onViewCreated(View view, Bundle savedInstanceState){ super.onViewCreated(view, savedInstanceState); } // Set the cursor in our CursorAdapter once the Cursor is loaded @Override public void onLoadFinished(Loader loader, Cursor data) { mDetailCursor = data; mDetailCursor.moveToFirst(); DatabaseUtils.dumpCursor(data); tvVersionName.setText(mDetailCursor.getString(1)); tvVersionCode.setText(mDetailCursor.getString(2)); tvApiLevel.setText(mDetailCursor.getString(3)); tvVersionDescription.setText(mDetailCursor.getString(4)); tvUri.setText(mUri.toString()); } // reset CursorAdapter on Loader Reset @Override public void onLoaderReset(Loader loader){ mDetailCursor = null; } }
Search within Codexpedia
Search the entire web