I am new in Android and am implementing a content provider for 5 tables.
My Questions Are:
Should I have a Content Provider for each table or multiple tables in a single
Content provider? Since the Content Provider has a single insert, update, query, delete methods.
How can I include only one Content Provider in my application? I have searched and in Most of the examples, I only find a single table apps.
Where do I have to use switch conditions to support multiple tables with the same Content Provider?
please give me some idea.
You can use the URI parameter:
List<String> android.net.Uri.getPathSegments()
If your URI is, for example:
content://com.mypackage.MyContentProvider/MyTable
MyTable will be in the list returned by getPathSegments();.
Then you have to specify your table in the URI and in insert, update, query, delete methods in provider build a query depending on the URI parameter.
To avoid testing on URI you can add to you provider an Abstract method called getTableName() witch will return your tableName as String.
Then extend your provider to 5 classes Table1Provider, Table2Provider etc. and implement method
Class abstract MyProvider extends ContentProvider{
public abstract String getTableName();
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
///...
// Set the table
queryBuilder.setTables(getTableName());
//...
return cursor;
}
}
class Table1Provider extend MyProvider{
public String getTableName(){
return "Table1";
}
Then instantiate the Table1Provider instead of the abstract provider.
Make one provider. Use the URIMatcher class provided by Android to match content URIs with different tables.
Read here: http://developer.android.com/guide/topics/providers/content-provider-creating.html#ContentURI
Related
I am a new programmer in Objective-C. I have created an Android app and I've integrated SQLite. I want to build the same app in iOS. In Android for SQLite manipulation I've created a class that extends from Content Provider:
public class MyCProvider extends ContentProvider {
...
...
}
I've also overrided this methods:
the boolean onCreate() method:
#Override
public boolean onCreate() {
dbHelper = new MySQLiteOpenHelper(getContext(), MySQLiteOpenHelper.DATABASE_NAME, null, MySQLiteOpenHelper.DATABASE_VERSION);
return dbHelper != null;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
...
}
#Override
public String getType(Uri uri) {
...
}
#Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
String nullColumnHack = null;
long id = -1;
Uri contentURI = null;
switch (uriMatcher.match(uri)) {
case GROUP_ALL_ROWS:
contentURI = GROUP_CONTENT_URI;
id = db.insert(USEFUL_NUMBER_GROUP_TABLE_NAME, nullColumnHack, values);
break;
...
...
}
I wanted to know this methods equivalences in Objective- C.
Any idea about this?
SQLite is provided directly with iOS and you'd just use its native C API. Apple doesn't provide any sort of wrapping.
The attitude seems to be that you can use SQLite directly or you can use Core Data, which is really quite a different thing — it's a queriable object graph which implicitly relies on an opaque storage method that can be a SQLite-based relational database if you like but Core Data is explicitly not a relational database. You can and should optimise for the SQL store underneath if that's the storage you pick but the database itself has a private schema and is not queried directly.
As such there's no equivalent to SQLiteOpenHelper. If you want to use SQLite then you need to do the work of opening, creating, migrating, etc for yourself.
iOS also doesn't have an equivalent to ContentProvider because that's a formalised model structure to allow sharing of data between applications but iOS doesn't really do sharing of data between applications in that sense. Applications from the same developer can share disk storage, all applications can open each other by URL schema, etc, but you can't write code that different applications can all interact with. So you'd just build whatever sort of model object you think most appropriate and its lifetime and interface would be whatever you explicitly decide.
I know I can use Cursor c=managedQuery(Contacts.CONTENT_URI,null,null,null,Contacts.DISPLAY_NAME+" ASC") to get a Cursor.
Now I hope to get a Cursor from myMRuleList, how can I do? Thanks!
lv = getListView();
Cursor c=managedQuery(Contacts.CONTENT_URI,null,null,null,Contacts.DISPLAY_NAME+" ASC");
String[] cols=new String[] {Contacts.DISPLAY_NAME};
int[] views=new int[]{android.R.id.text1};
SimpleCursorAdapter myAdapter=new SimpleCursorAdapter(this,android.R.layout.simple_list_item_1,c,cols,views);
this.setListAdapter(myAdapter);
List<MRule> myMRuleList=new ArrayList<MRule>;
MRule aMRule=new MRule();
aMRule.ruleID=1;
aMRule.name="a";
aMRule.enabled=false;
MRule bMRule=new MRule();
bMRule.ruleID=1;
bMRule.name="b";
bMRule.enabled=false;
myMRuleList.add(aMRule);
myMRuleList.add(bMRule);
public class MRule {
public int ruleID;
public String name;
public Boolean enabled;
}
You shouldn't create a Cursor from a List. If you want to insert/update the data on permanent storage you should use the insert() and update() provided by ContentResolver.insert()/update() or SQLiteOpenHelper.insert()/update() if dealing with ContentProviders or SQLite databases respectively
Cursors are typically used with table-like structures (ContentProviders/Databases) not Lists.
As zapl recommended you should avoid managedQuery() and use the Loader framework. By doing so, your queries will be done on a separate Thread.
Why would you do that? Is it to update your database or what do you want to achieve?
Here is the link to google's reference for the Cursor class:
http://developer.android.com/reference/android/database/Cursor.html
If you just want to update your database read this SO question:
How to properly insert values into the SQLite database using ContentProvider's insert() method through a CursorLoader?
android.database.MatrixCursor, is this what you want?
Is there any way to get Cursor for a query, which I am processing with ORMLite Dao object?
ORMLite now supports next(), previous(), moveRelative(offset), ... methods on the CloseableIterator class. This should allow you to move the underlying Cursor object around at will.
It also supports the following DAO Cursor methods:
dao.mapSelectStarRow(databaseResults) Return the latest row from the database results from a query to select *. With this you can change the cursor location (for example) and then get the current object.
dao.getSelectStarRowMapper() Provides a mapper that you can use to map the object outside of the Dao.
When you are building your own query with ORMLite, you use the QueryBuilder object. queryBuilder.prepare() returns a PreparedQuery which is used by various methods in the DAO. You can call dao.iterator(preparedQuery) which will return a CloseableIterator which is used to iterate through the results. There is a iterator.getRawResults() to get access to the DatabaseResults class. Under Android, this can be cast to an AndroidDatabaseResults which has a getCursor() method on it to return the Android Cursor.
Something like the following code:
// build your query
QueryBuilder<Foo, String> qb = fooDao.queryBuilder();
qb.where()...;
// when you are done, prepare your query and build an iterator
CloseableIterator<Foo> iterator = dao.iterator(qb.prepare());
try {
// get the raw results which can be cast under Android
AndroidDatabaseResults results =
(AndroidDatabaseResults)iterator.getRawResults();
Cursor cursor = results.getRawCursor();
...
} finally {
iterator.closeQuietly();
}
This is a bit complicated but you are definitely having to peer behind the vale to get to this object which is hidden by the database abstraction classes.
Did you try some of Gray's advice from this post? He explains how you can select a column as another name, such as, select id as _id.
If you're in an Activity and don't want to mess around with the QueryBuilder give the following a go, which is just as effective.
Cursor cursor = getHelper().getReadableDatabase().query(tableName, projection, selection, selectionArgs, groupBy, having, sortOrder)
If you mean the getHelper() method to reach the dao methods create etc. you only have to inherit from the OrmLiteBaseActivity<YourDBHelper> and you can call it. It will look sth like this:
public class YourClass extends OrmLiteBaseActivity<YourDBHelper> {
#Override
protected void onCreate(Bundle savedInstanceState) {
...
getHelper().getDao().queryForAll();
...
}
}
If you mean the cursor to handle database operation: I don't think that you can reach it! But I don't understand why you should need it. ORMLite has nearly all functions of the cursor. So what do you need it for?
I want to know the context in which getContentResolver() is called?
I have a scenario like this:
I have an activity A that calls a method myFunc() of class B which is not an activity.
So, in class B I have to use getContentResolver(). I directly called getContentResolver(). It was showing error. Then I called myFunc(Acitivy act) from the activity and called act.getContentResolver() which solved my problem. Is this the only way to call getContentResolver(), which means it can be used in context with activity or can be used alone.
getContentResolver() is method of class android.content.Context, so to call it you definitely need an instance
of Context ( Activity or Service for example).
You can use like this:
getApplicationContext().getContentResolver()
with the proper context.
The getContentResolver()method is also used when you query a Contact, using a Cursor object. I have used getContentResolver() to query the Android phone Contacts app, looking for contact info from a person's phone number, to include in my app. The different elements in a query (as shown below) represent what kind of contact details you want, and if they should be ordered, etc. Here is another example.
From the Content Provider Basics page from Android docs.
// Queries the user dictionary and returns results
mCursor = getContentResolver().query(
UserDictionary.Words.CONTENT_URI, // The content URI of the words table
mProjection, // The columns to return for each row
mSelectionClause // Selection criteria
mSelectionArgs, // Selection criteria
mSortOrder); // The sort order for the returned rows
import android.content.Context;
import android.content.ContentResolver;
context = (Context)this;
ContentResolver result = (ContentResolver)context.getContentResolver();
//create activity object to get activity from Activity class for use to content resolver
private final Activity ActivityObj;
//create constructor with ActivityObj to get activity from Activity class
public RecyclerViewAdapterClass(Activity activityObj) {
this.ActivityObj = activityObj;
}
ActivityObj.getContentResolver(),.....,.....,null);
Access contentResolver in Kotlin , inside activities, Object classes &... :
Application().contentResolver
This one worked for me
getBaseContext();
A solution would be to get the ContentResolver from the context
ContentResolver contentResolver = getContext().getContentResolver();
Link to the documentation : ContentResolver
Right now, I'm running into issues trying to implement a FilterQueryProvider in my custom SimpleCursorAdapter, since I'm unsure of what to do in the FilterQueryProvider's runQuery function.
In other words, since the query that comprises my ListView basically gets the rowID, name, and a third column from my databases's table, I want to be able to filter the cursor based on the partial value of the name column.
However, I am uncertain of whether I can do this directly from runQuery without expanding my DB class since I want to filter the existing cursor, or will I have to create a new query function in my DB class that partially searches my name column, and if so, how would I go about creating the query statement while using the CharSequence constraint argument in runQuery?
I am also concerned about the performance issues associated with trying to run multiple queries based on partial text since the DB table in question has about 1300-1400 rows. In other words, would I run into a bottleneck trying to filter the cursor?
You need to run a query that will return a new filtered cursor:
public class MyActivity extends ListActivity implements FilterQueryProvider {
private Cursor cursor;
#Override
public Cursor runQuery(CharSequence constraint) {
if(cursor != null) {
cursor.close();
}
cursor = somehowGetAFilteredCursorFor(constraint);
startManagingCursor(cursor);
return cursor;
}
}