Wednesday 10 September 2008

Android Developers Google Group - A focus on ContentProvider

As requested here, I'm posting some example code for implementing a ContentProvider on which is possible to call openOutputStream and openInputStream.
My only question is: why must I store file path in a database field called '_data', if openFile implementation is programmer's burden?

ElementProvider.java

/*
Copyright (C) 2008 Luca Belluccini

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see
.
*/

package polito.mailandroid;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;

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.net.Uri;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.os.ParcelFileDescriptor;
import android.text.TextUtils;

public class ElementProvider extends ContentProvider {
private static final String DATABASE_NAME = "poli";
private static final String DATABASE_TABLE = "elements";
private static final int DATABASE_VERSION = 1;
public static final String KEY_ID = "_id";
public static final String KEY_DATA = "_data";
public static final String KEY_MIMETYPE = "mimetype";

private DatabaseHelper mDbH;

private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
}

public void onCreate(SQLiteDatabase db) {
db.execSQL("create table " + DATABASE_TABLE + " (" +
KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
KEY_MIMETYPE + " TEXT, " +
KEY_DATA + " TEXT" +
" );");
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
onCreate(db);
}
}



public static final int ELEMENTS = 1;
public static final int ELEMENT_ID = 2;
public static final Uri CONTENT_URI = Uri.parse("content://polito.mailandroid/elements");
private static final UriMatcher URI_MATCHER;
private static HashMap
ELEMENTS_LIST_PROJECTION_MAP;
static {
URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
URI_MATCHER.addURI("polito.mailandroid", "elements", ELEMENTS);
URI_MATCHER.addURI("polito.mailandroid", "elements/#", ELEMENT_ID);

ELEMENTS_LIST_PROJECTION_MAP = new HashMap
();
ELEMENTS_LIST_PROJECTION_MAP.put(KEY_ID, KEY_ID);
ELEMENTS_LIST_PROJECTION_MAP.put(KEY_DATA, KEY_DATA);
ELEMENTS_LIST_PROJECTION_MAP.put(KEY_MIMETYPE, KEY_MIMETYPE);
}

public boolean onCreate() {
mDbH = new DatabaseHelper(getContext());
return true;
}

public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
String[] projection = new String[] {
ElementProvider.KEY_DATA
};
Cursor c = query(uri,projection,null,null,null);
c.moveToFirst();
String file = c.getString(c.getColumnIndexOrThrow(ElementProvider.KEY_DATA));
c.close();
File f = new File(file);
int m = ParcelFileDescriptor.MODE_READ_ONLY;
if (mode.equalsIgnoreCase("rw"))
m = ParcelFileDescriptor.MODE_READ_WRITE;
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(f,m);
return pfd;
}

public Uri insert(Uri uri, ContentValues initialValues) {
if (URI_MATCHER.match(uri) != ELEMENTS) {
// !!!
}
ContentValues values;
if (initialValues != null) {
values = new ContentValues(initialValues);
} else {
values = new ContentValues();
}

if (!values.containsKey(KEY_MIMETYPE))
values.put(KEY_MIMETYPE, "plain/text");

SQLiteDatabase mDb = mDbH.getWritableDatabase();
long rowID = mDb.insert(DATABASE_TABLE, "notnull", values);
if (rowID > 0) {
if (!values.containsKey(KEY_DATA)){
try {
String filename = rowID + "";
getContext().openFileOutput(filename, Context.MODE_PRIVATE).close();
String path = getContext().getFileStreamPath(filename).getAbsolutePath();
values.put(KEY_DATA, path);
update(uri,values,KEY_ID + "=" + rowID, null);
} catch (Exception e) {
// !!!
}
}
Uri newUri = ContentUris.withAppendedId(ElementProvider.CONTENT_URI, rowID);
getContext().getContentResolver().notifyChange(newUri, null);
return newUri;
}
// !!!
return null;
}

public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
switch (URI_MATCHER.match(uri)) {
case ELEMENTS:
qb.setTables(DATABASE_TABLE);
qb.setProjectionMap(ELEMENTS_LIST_PROJECTION_MAP);
break;
case ELEMENT_ID:
qb.setTables(DATABASE_TABLE);
qb.appendWhere(KEY_ID + "=" + uri.getPathSegments().get(1));
break;
default:
throw new IllegalArgumentException("Unknown URL " + uri);
}
SQLiteDatabase mDb = mDbH.getReadableDatabase();
Cursor c = qb.query(mDb, projection, selection, selectionArgs, null, null, "_id DESC");
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}

public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int code = URI_MATCHER.match(uri);
int count = 0;
SQLiteDatabase mDb = mDbH.getWritableDatabase();
switch (code) {
case ELEMENTS:
count = mDb.update(DATABASE_TABLE, values, selection, selectionArgs);
break;
case ELEMENT_ID:
String id = uri.getPathSegments().get(1);
count =
mDb.update(DATABASE_TABLE, values, KEY_ID + "=" + id
+ (!TextUtils.isEmpty(selection) ? " AND ("
+ selection + ')' : ""), selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URL " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}

public int delete(Uri uri, String where, String[] whereArgs) {
int code = URI_MATCHER.match(uri);
int count = 0;
SQLiteDatabase mDb = mDbH.getWritableDatabase();
switch (code) {
case ELEMENTS:
// !!! REMOVE ALL FILES
count = mDb.delete(DATABASE_TABLE, where, whereArgs);
break;
case ELEMENT_ID:
String id = uri.getPathSegments().get(1);
// !!! REMOVE ASSOCIATED FILE
count =
mDb.delete(DATABASE_TABLE, KEY_ID + "=" + id
+ (!TextUtils.isEmpty(where) ? " AND (" + where
+ ')' : ""), whereArgs);
break;
default:
// !!!
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}

public String getType(Uri uri) {
String[] projection = new String[] {
ElementProvider.KEY_MIMETYPE
};
Cursor c = query(uri,projection,null,null,null);
c.moveToFirst();
String mimetype = c.getString(c.getColumnIndexOrThrow(ElementProvider.KEY_MIMETYPE));
c.close();
return mimetype;
}

}

1 comment:

Android app development said...

This is one of the Important document about android.Android is one of the popular mobile application.Your blog has very good effort.Android app developers