I'm trying to make an app that involves a database. I'm using a ContentProvider and it's crashing in the query method when it tries to getWritableDatabase.
It returns a NullPointerException. I know for a fact that the Context isn't null, since that seems to be the main cause of this kind of problem.
Here's the ContentProvider code:
package com.corvus.corvusenterprises.digimonapp;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import java.util.Arrays;
import java.util.HashSet;
import static com.corvus.corvusenterprises.digimonapp.DBHelper.presentDigimon;
/**
* Created by Jack on 01/05/2017.
*/
public class DigimonContentProvider extends ContentProvider {
private static DigimonContentProvider instance;
private DBHelper dbHelper;
private SQLiteDatabase db;
private static final int DIGIMON = 10;
private static final int DIGIMON_ID = 20;
private static final int ATTACKS = 30;
private static final int ATTACKS_ID = 40;
private static final int EVOLUTIONS = 50;
private static final int EVOLUTIONS_ID = 60;
private static final String AUTHORITY = "com.corvus.corvusenterprises.digimonapp";
private static final String BASE_PATH_DIGIMON = "digimon";
private static final String BASE_PATH_ATTACKS = "attacks";
private static final String BASE_PATH_EVOLUTIONS = "evolutions";
public static final Uri CONTENT_URI_DIGIMON = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH_DIGIMON);
public static final Uri CONTENT_URI_ATTACKS = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH_ATTACKS);
public static final Uri CONTENT_URI_EVOLUTIONS = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH_EVOLUTIONS);
public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/digimon";
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/digimon";
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(AUTHORITY, BASE_PATH_DIGIMON, DIGIMON);
sURIMatcher.addURI(AUTHORITY, BASE_PATH_DIGIMON + "/#", DIGIMON_ID);
sURIMatcher.addURI(AUTHORITY, BASE_PATH_ATTACKS, ATTACKS);
sURIMatcher.addURI(AUTHORITY, BASE_PATH_ATTACKS + "/#", ATTACKS_ID);
sURIMatcher.addURI(AUTHORITY, BASE_PATH_EVOLUTIONS, EVOLUTIONS);
sURIMatcher.addURI(AUTHORITY, BASE_PATH_EVOLUTIONS + "/#", EVOLUTIONS_ID);
}
private DigimonContentProvider()
{
}
public static DigimonContentProvider getInstance() {
if (instance == null)
instance = new DigimonContentProvider();
return instance;
}
#Override
public boolean onCreate() {
Context ctx = MyApp.getContext();
dbHelper = DBHelper.getInstance(ctx);
dbHelper.insertDigimon("Guilmon", "Guilmon", "Child/Rookie", "Virus", "Dinosaur", "TRUE","R.mipmap.guilmon.jpg");
dbHelper.insertDigimon("Growmon", "Growlmon", "Adult/Champion", "Virus", "Bigger Dinosaur", "FALSE","R.mipmap.growmon.jpg");
dbHelper.insertDigimon("Terriermon", "terriermon", "Child/Rookie", "Vaccine", "Dogbunny", "FALSE","R.mipmap.terriermon.jpg");
dbHelper.insertDigimon("Galgomon", "Gargomon", "Adult/Champion", "Vaccine", "Gunbunny", "FALSE","R.mipmap.galgomon.jpg");
dbHelper.insertDigimon("Kyubimon", "Kyubimon", "Adult/Champion", "Data", "9-Tailed Fox", "FALSE","R.mipmap.kyubimon.jpg");
dbHelper.insertDigimon("Taomon", "Taomon", "Perfect/Ultimate", "Data", "Kitsune Miko", "FALSE","R.mipmap.taomon.jpg");
dbHelper.insertDigimon("Impmon", "Impmon", "Child/Rookie", "Virus", "Kid in a purple onesie", "FALSE","R.mipmap.impmon.jpg");
dbHelper.insertDigimon("Beelzebumon", "Beelzemon", "Ultimate/Mega", "Virus", "Demon Lord of Gluttony", "FALSE","R.mipmap.beelzebumon.jpg");
presentDigimon[460] = true; presentDigimon[454] = true;
presentDigimon[1019] = true; presentDigimon[374] = true;
presentDigimon[572] = true; presentDigimon[1013] = true;
presentDigimon[507] = true; presentDigimon[100] = true;
dbHelper.insertEvolution("Guilmon", "Growmon", "");
dbHelper.insertEvolution("Terriermon", "Galgomon","");
dbHelper.insertEvolution("Kyubimon", "Taomon","");
dbHelper.insertEvolution("Impmon", "Beelzebumon", "(Warp Evolution)");
dbHelper.insertAttack("Fireball", "Pyro Sphere", "Guilmon", "Explosive Fireball");
dbHelper.insertAttack("Rock Breaker", "Rock Breaker", "Guilmon", "Claw Swipe");
dbHelper.insertAttack("Exhaust Flame", "Pyro Blaster", "Growmon", "Fire Laser");
dbHelper.insertAttack("Plasma Blade", "Dragon Slash", "Growmon", "Forearm Blades");
dbHelper.insertAttack("Blazing Fire", "Bunny Blast", "Terriermon", "Energy Blast");
dbHelper.insertAttack("Petit Twister", "Terrier Tornado", "Terriermon", "Throws Tornado");
dbHelper.insertAttack("Gatling Arm", "Gargo Laser", "Galgomon", "Fires Guns");
dbHelper.insertAttack("Dum Dum Upper", "Bunny Pummel", "Galgomon", "Fires Guns While Punching");
dbHelper.insertAttack("Koenryu", "Dragon Wheel", "Kyubimon", "Fire Dragon");
dbHelper.insertAttack("Onibidama", "Fox-Tail Inferno", "Kyubimon", "Fireballs from the tails");
dbHelper.insertAttack("Bonhitsusen", "Talisman of Light", "Taomon", "Energy Seal Laser");
dbHelper.insertAttack("Oṃ", "Talisman Spell", "Taomon", "Makes a dome shield");
dbHelper.insertAttack("Night of Fire", "Badaboom", "Impmon", "Mini-Fireballs");
dbHelper.insertAttack("Pillar of Fire", "", "Impmon", "Wall of Flames");
dbHelper.insertAttack("Double Impact", "Double Impact", "Beelzebumon", "Fires two bullets");
dbHelper.insertAttack("Darkness Claw", "", "Beelzebumon", "Kills Leomon");
db = dbHelper.getWritableDatabase();
return false;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
Uri _uri = null;
switch (sURIMatcher.match(uri)) {
case DIGIMON:
long _ID1 = db.insert(DigimonTable.DIGIMON_TABLE_NAME, "", values);
if (_ID1 > 0) {
_uri = ContentUris.withAppendedId(CONTENT_URI_DIGIMON, _ID1);
MyApp.getContext().getContentResolver().notifyChange(_uri, null);
}
break;
case ATTACKS:
long _ID2 = db.insert(AttacksTable.ATTACKS_TABLE_NAME, "", values);
if (_ID2 > 0) {
_uri = ContentUris.withAppendedId(CONTENT_URI_ATTACKS, _ID2);
MyApp.getContext().getContentResolver().notifyChange(_uri, null);
}
break;
case EVOLUTIONS:
long _ID3 = db.insert(EvolutionsTable.EVOLUTIONS_TABLE_NAME, "", values);
if (_ID3 > 0) {
_uri = ContentUris.withAppendedId(CONTENT_URI_EVOLUTIONS, _ID3);
MyApp.getContext().getContentResolver().notifyChange(_uri, null);
}
break;
default:
throw new SQLException("Failed to insert row into " + uri);
}
MyApp.getContext().getContentResolver().notifyChange(uri, null);
return _uri;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
int uriType = sURIMatcher.match(uri);
checkColumns(projection, uriType);
queryBuilder.setTables(DigimonTable.DIGIMON_TABLE_NAME + ", " + EvolutionsTable.EVOLUTIONS_TABLE_NAME + ", " + AttacksTable.ATTACKS_TABLE_NAME);
switch (uriType) {
case DIGIMON:
break;
case DIGIMON_ID:
queryBuilder.appendWhere(DigimonTable.DIGIMON_COLUMN_ID+"="+uri.getLastPathSegment());
case ATTACKS:
break;
case ATTACKS_ID:
queryBuilder.appendWhere(AttacksTable.ATTACKS_COLUMN_ID+"="+uri.getLastPathSegment());
case EVOLUTIONS:
break;
case EVOLUTIONS_ID:
queryBuilder.appendWhere(EvolutionsTable.EVOLUTIONS_COLUMN_ID+"="+uri.getLastPathSegment());
default:
throw new IllegalArgumentException("Unknown URI: "+ uri);
}
Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(MyApp.getContext().getContentResolver(), uri);
return cursor;
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
int rowsDeleted = 0;
switch (uriType) {
case DIGIMON:
rowsDeleted = db.delete(DigimonTable.DIGIMON_TABLE_NAME, selection, selectionArgs);
break;
case DIGIMON_ID:
String id1 = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = db.delete(
DigimonTable.DIGIMON_TABLE_NAME,
DigimonTable.DIGIMON_COLUMN_ID + "=" + id1,
null);
} else {
rowsDeleted = db.delete(
DigimonTable.DIGIMON_TABLE_NAME,
DigimonTable.DIGIMON_COLUMN_ID + "=" + id1
+ " and " + selection,
selectionArgs);
}
break;
case ATTACKS:
rowsDeleted = db.delete(AttacksTable.ATTACKS_TABLE_NAME, selection, selectionArgs);
break;
case ATTACKS_ID:
String id2 = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = db.delete(
AttacksTable.ATTACKS_TABLE_NAME,
AttacksTable.ATTACKS_COLUMN_ID + "=" + id2,
null);
} else {
rowsDeleted = db.delete(
AttacksTable.ATTACKS_TABLE_NAME,
AttacksTable.ATTACKS_COLUMN_ID + "=" + id2
+ " and " + selection,
selectionArgs);
}
break;
case EVOLUTIONS:
rowsDeleted = db.delete(EvolutionsTable.EVOLUTIONS_TABLE_NAME, selection, selectionArgs);
break;
case EVOLUTIONS_ID:
String id3 = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = db.delete(
EvolutionsTable.EVOLUTIONS_TABLE_NAME,
EvolutionsTable.EVOLUTIONS_COLUMN_ID + "=" + id3,
null);
} else {
rowsDeleted = db.delete(
EvolutionsTable.EVOLUTIONS_TABLE_NAME,
EvolutionsTable.EVOLUTIONS_COLUMN_ID + "=" + id3
+ " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
MyApp.getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
#Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
int rowsUpdated = 0;
switch (uriType) {
case DIGIMON:
rowsUpdated = db.update(DigimonTable.DIGIMON_TABLE_NAME,
values,
selection,
selectionArgs);
break;
case DIGIMON_ID:
String id1 = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = db.update(DigimonTable.DIGIMON_TABLE_NAME,
values,
DigimonTable.DIGIMON_COLUMN_ID + "=" + id1,
null);
} else {
rowsUpdated = db.update(DigimonTable.DIGIMON_TABLE_NAME,
values,
DigimonTable.DIGIMON_COLUMN_ID + "=" + id1
+ " and "
+ selection,
selectionArgs);
}
break;
case ATTACKS:
rowsUpdated = db.update(AttacksTable.ATTACKS_TABLE_NAME,
values,
selection,
selectionArgs);
break;
case ATTACKS_ID:
String id2 = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = db.update(AttacksTable.ATTACKS_TABLE_NAME,
values,
AttacksTable.ATTACKS_COLUMN_ID + "=" + id2,
null);
} else {
rowsUpdated = db.update(AttacksTable.ATTACKS_TABLE_NAME,
values,
AttacksTable.ATTACKS_COLUMN_ID + "=" + id2
+ " and "
+ selection,
selectionArgs);
}
break;
case EVOLUTIONS:
rowsUpdated = db.update(EvolutionsTable.EVOLUTIONS_TABLE_NAME,
values,
selection,
selectionArgs);
break;
case EVOLUTIONS_ID:
String id3 = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = db.update(EvolutionsTable.EVOLUTIONS_TABLE_NAME,
values,
EvolutionsTable.EVOLUTIONS_COLUMN_ID + "=" + id3,
null);
} else {
rowsUpdated = db.update(EvolutionsTable.EVOLUTIONS_TABLE_NAME,
values,
EvolutionsTable.EVOLUTIONS_COLUMN_ID + "=" + id3
+ " and "
+ selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
MyApp.getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
private void checkColumns(String[] projection, int uri) {
HashSet<String> availableColumns;
String[] availableDigimon = { DigimonTable.DIGIMON_COLUMN_ID,
DigimonTable.DIGIMON_COLUMN_NAME, DigimonTable.DIGIMON_COLUMN_DUB_NAME,
DigimonTable.DIGIMON_COLUMN_LEVEL, DigimonTable.DIGIMON_COLUMN_ATTRIBUTE,
DigimonTable.DIGIMON_COLUMN_DESCRIPTION, DigimonTable.DIGIMON_COLUMN_FAVOURITE,
DigimonTable.DIGIMON_COLUMN_PATH};
String[] availableAttacks = {AttacksTable.ATTACKS_COLUMN_ID, AttacksTable.ATTACKS_COLUMN_NAME,
AttacksTable.ATTACKS_COLUMN_DUB_NAME, AttacksTable.ATTACKS_COLUMN_DIGIMON,
AttacksTable.ATTACKS_COLUMN_DESCRIPTION};
String[] availableEvolutions = {EvolutionsTable.EVOLUTIONS_COLUMN_ID,EvolutionsTable.EVOLUTIONS_COLUMN_FROM,
EvolutionsTable.EVOLUTIONS_COLUMN_TO, EvolutionsTable.EVOLUTIONS_COLUMN_CONDITIONS};
if (projection != null) {
HashSet<String> requestedColumns = new HashSet<String>(
Arrays.asList(projection));
switch(uri){
case DIGIMON:
case DIGIMON_ID: availableColumns = new HashSet<String>(Arrays.asList(availableDigimon));
break;
case ATTACKS:
case ATTACKS_ID: availableColumns = new HashSet<String>(Arrays.asList(availableAttacks));
break;
case EVOLUTIONS:
case EVOLUTIONS_ID: availableColumns = new HashSet<String>(Arrays.asList(availableEvolutions));
break;
default: availableColumns = new HashSet<String>(Arrays.asList(availableDigimon));
}
// check if all columns which are requested are available
if (!availableColumns.containsAll(requestedColumns)) {
throw new IllegalArgumentException(
"Unknown columns in projection");
}
}
}
public Cursor defaultMainMenu()
{
Cursor cursor = MyApp.getContext().getContentResolver().query(CONTENT_URI_DIGIMON, new String[]{DigimonTable.DIGIMON_COLUMN_NAME, DigimonTable.DIGIMON_COLUMN_FAVOURITE}, null, null, DigimonTable.DIGIMON_COLUMN_NAME + " ASC");
int dummy = cursor.getCount();
return cursor;
}
public Cursor searchMenuQuery(String search)
{
Cursor cursor = MyApp.getContext().getContentResolver().query(CONTENT_URI_DIGIMON,new String[] {DigimonTable.DIGIMON_COLUMN_NAME,DigimonTable.DIGIMON_COLUMN_FAVOURITE},DigimonTable.DIGIMON_COLUMN_NAME+" = '?'",new String[]{search},DigimonTable.DIGIMON_COLUMN_NAME+" ASC");
int dummy = cursor.getCount();
return cursor;
}
public Cursor favouritesMenuQuery()
{
Cursor cursor = MyApp.getContext().getContentResolver().query(CONTENT_URI_DIGIMON,new String[] {DigimonTable.DIGIMON_COLUMN_NAME},DigimonTable.DIGIMON_COLUMN_FAVOURITE+" = true",null,DigimonTable.DIGIMON_COLUMN_NAME+" ASC");
int dummy = cursor.getCount();
return cursor;
}
public Cursor digimonProfileQuery(String name)
{
Cursor cursor = MyApp.getContext().getContentResolver().query(CONTENT_URI_DIGIMON,null,DigimonTable.DIGIMON_COLUMN_NAME+" = '?'",new String[]{name},null);
int dummy = cursor.getCount();
return cursor;
}
public Cursor digimonAttacksQuery(String name)
{
Cursor cursor = MyApp.getContext().getContentResolver().query(CONTENT_URI_ATTACKS,null,AttacksTable.ATTACKS_COLUMN_DIGIMON+" = '?'",new String[]{name},null);
int dummy = cursor.getCount();
return cursor;
}
public Cursor digimonEvolutionFromQuery(String name)
{
Cursor cursor = MyApp.getContext().getContentResolver().query(CONTENT_URI_EVOLUTIONS,null,EvolutionsTable.EVOLUTIONS_COLUMN_FROM+" = '?'",new String[]{name},null);
int dummy = cursor.getCount();
return cursor;
}
public Cursor digimonEvolutionToQuery(String name)
{
Cursor cursor = MyApp.getContext().getContentResolver().query(CONTENT_URI_EVOLUTIONS,null,EvolutionsTable.EVOLUTIONS_COLUMN_TO+" = '?'",new String[]{name},null);
int dummy = cursor.getCount();
return cursor;
}
}
And here's the Logcat results:
Process: com.corvus.corvusenterprises.digimonapp, PID: 12198
java.lang.RuntimeException: Unable to get provider com.corvus.corvusenterprises.digimonapp.DigimonContentProvider: java.lang.NullPointerException
at android.app.ActivityThread.installProvider(ActivityThread.java:5084)
at android.app.ActivityThread.installContentProviders(ActivityThread.java:4673)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4613)
at android.app.ActivityThread.access$1800(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1298)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5333)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:895)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:711)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:224)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
at com.corvus.corvusenterprises.digimonapp.DigimonContentProvider.onCreate(DigimonContentProvider.java:62)
at android.content.ContentProvider.attachInfo(ContentProvider.java:1616)
at android.content.ContentProvider.attachInfo(ContentProvider.java:1587)
at android.app.ActivityThread.installProvider(ActivityThread.java:5081)
at android.app.ActivityThread.installContentProviders(ActivityThread.java:4673)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4613)
at android.app.ActivityThread.access$1800(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1298)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5333)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:895)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:711)
at dalvik.system.NativeStart.main(Native Method)
Here's the DBHelper code, in case it helps:
package com.corvus.corvusenterprises.digimonapp;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import static com.corvus.corvusenterprises.digimonapp.DigimonContentProvider.CONTENT_URI_ATTACKS;
import static com.corvus.corvusenterprises.digimonapp.DigimonContentProvider.CONTENT_URI_DIGIMON;
import static com.corvus.corvusenterprises.digimonapp.DigimonContentProvider.CONTENT_URI_EVOLUTIONS;
/**
* Created by Jack on 01/05/2017.
*/
public class DBHelper extends SQLiteOpenHelper {
public static final String[]digimonArray = {
"Gigantic array of names"};
private static final String DATABASE_NAME = "DigimonDatabase.db";
private static final int version = 1;
private static DBHelper instance;
public static boolean[]presentDigimon = new boolean[digimonArray.length];
private DBHelper(Context context) {
super(context, DATABASE_NAME, null, version);
}
public static DBHelper getInstance(Context ctx) {
if (instance == null)
instance = new DBHelper(ctx);
return instance;
}
#Override
public void onCreate(SQLiteDatabase db) {
DigimonTable.onCreate(db);
AttacksTable.onCreate(db);
EvolutionsTable.onCreate(db);
}
public void onUpgrade(SQLiteDatabase db, int oldver, int newVer)
{
DigimonTable.onUpgrade(db,oldver,newVer);
AttacksTable.onUpgrade(db,oldver,newVer);
EvolutionsTable.onUpgrade(db,oldver,newVer);
}
public void insertDigimon(String name, String dub_name, String level, String attribute, String description, String favourite, String path)
{
DigimonContentProvider dcp = DigimonContentProvider.getInstance();
ContentValues values = new ContentValues();
values.put(DigimonTable.DIGIMON_COLUMN_NAME,name);
values.put(DigimonTable.DIGIMON_COLUMN_DUB_NAME,dub_name);
values.put(DigimonTable.DIGIMON_COLUMN_LEVEL,level);
values.put(DigimonTable.DIGIMON_COLUMN_ATTRIBUTE,attribute);
values.put(DigimonTable.DIGIMON_COLUMN_DESCRIPTION,description);
values.put(DigimonTable.DIGIMON_COLUMN_FAVOURITE, favourite);
values.put(DigimonTable.DIGIMON_COLUMN_PATH,path);
dcp.insert(CONTENT_URI_DIGIMON, values);
}
public void insertAttack(String name, String dub_name, String digimon, String description)
{
DigimonContentProvider dcp = DigimonContentProvider.getInstance();
ContentValues values = new ContentValues();
values.put(AttacksTable.ATTACKS_COLUMN_NAME, name);
values.put(AttacksTable.ATTACKS_COLUMN_DUB_NAME,dub_name);
values.put(AttacksTable.ATTACKS_COLUMN_DIGIMON, digimon);
values.put(AttacksTable.ATTACKS_COLUMN_DESCRIPTION, description);
dcp.insert(CONTENT_URI_ATTACKS, values);
}
public void insertEvolution(String from, String to, String conditions)
{
DigimonContentProvider dcp = DigimonContentProvider.getInstance();
ContentValues values = new ContentValues();
values.put(EvolutionsTable.EVOLUTIONS_COLUMN_TO,to);
values.put(EvolutionsTable.EVOLUTIONS_COLUMN_FROM,from);
values.put(EvolutionsTable.EVOLUTIONS_COLUMN_CONDITIONS,conditions);
dcp.insert(CONTENT_URI_EVOLUTIONS, values);
}
}
Any and all help appreciated. If you need more information, just let me know.
(EDITED): New version being worked on. Code updated.
(EDITED 2): Fixed a possible issue with recursive calls.
I know for a fact that the Context isn't null
How do you know that? MyApp.getContext() looks strange to me.
Try giving the Context to the ContentProvider
private Context mContext;
private DigimonContentProvider(Context context)
{
this.mContext = context;
}
private DigimonContentProvider() { }
public static DigimonContentProvider getInstance(Context context) {
if (instance == null)
instance = new DigimonContentProvider(context);
return instance;
}
#Override
public boolean onCreate() {
dbHelper = DBHelper.getInstance(this.mContext);
However, you don't need a ContentProvider to have a database, so try getting the database working without it.
It is throwing a NullPointerException because you are trying to access your ContentProvider methods directly instead of using a ContentResolver for the same.
You can abstract the code you have written in the ContentProvider to access it in an another class. And this time use a ContentResolver instance for the same.
Edit:
Maybe your problem is that your dbHelper is not singleton and you are creating an another instances of it through dbHelper.getInstance(getContext) in insert() method.
Try getting a new instance of dbHelper only in onCreate() method and not in other methods.
You can use this example: MoviesContentProvider.java
Related
I began to study the mechanism ContentProvider I decided to write a simple example, when one application uses the data of another. My goal is to implement update, delete, and insert requests to the database.
I wrote the provider and the provider's client, insert is working, but update and delete requests applies to the entire table, rather than to a specific record.
I can't understand, what am I doing wrong?
Here is my provider:
public class MyProvider extends ContentProvider {
final String LOG_TAG = "myLogs";
static final String DB_NAME = "mydb";
static final int DB_VERSION = 1;
static final String CONTACT_TABLE = "_id";
static final String CONTACT_id = "_id";
static final String CONTACT_NAME = "name";
static final String CONTACT_EMAIL = "email";
static final String DB_CREATE = "create table "+CONTACT_TABLE+"("+
CONTACT_id+" integer primary key autoincrement,"+
CONTACT_NAME+ " text,"+
CONTACT_EMAIL+" text);";
static final String AUTHORITY = "com.dandewine.user.contentprovider.AddressBook";
static final String CONTACT_PATH = "contacts";
public static final Uri CONTACT_CONTENT_URI = Uri.parse("content://"+AUTHORITY+"/"+CONTACT_PATH);
static final String CONTACT_CONTENT_TYPE = "vnd.android.cursor.item/vnd."+AUTHORITY+"."+CONTACT_PATH;
static final int URI_CONTACT = 1;
static final int URI_CONTACT_ID = 2;
private static final UriMatcher uriMatcher;
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, CONTACT_PATH, URI_CONTACT);
uriMatcher.addURI(AUTHORITY, CONTACT_PATH + "/#", URI_CONTACT);
}
DBHelper helper;
SQLiteDatabase db;
#Override
public boolean onCreate(){
Log.d(LOG_TAG,"onCreate");
helper = new DBHelper(getContext());
return true;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Log.d(LOG_TAG,"query, "+uri.toString());
switch (uriMatcher.match(uri)){
case URI_CONTACT:
Log.d(LOG_TAG,"URI_CONTACTS");
if(TextUtils.isEmpty(sortOrder))
sortOrder=CONTACT_NAME+" ASC";
break;
case URI_CONTACT_ID:
String id = uri.getLastPathSegment();
Log.d(LOG_TAG,"URI_CONTACTS_ID,"+id);
if(TextUtils.isEmpty(selection))
selection=CONTACT_id+" = "+id;
else
selection=selection+" AND "+CONTACT_id+" = "+id;
break;
default:throw new IllegalArgumentException("Wrong URI: "+uri);
}
db = helper.getWritableDatabase();
Cursor cursor = db.query(CONTACT_TABLE,projection,selection,selectionArgs,null,null,sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(),CONTACT_CONTENT_URI);
return cursor;
}
#Override
public String getType(Uri uri) {
Log.d(LOG_TAG, "getType, " + uri.toString());
switch (uriMatcher.match(uri)) {
case URI_CONTACT:
return CONTACT_CONTENT_TYPE;
case URI_CONTACT_ID:
return CONTACT_CONTENT_TYPE;
}
return null;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
Log.d(LOG_TAG,"insert, "+uri.toString());
if(uriMatcher.match(uri)!=URI_CONTACT)
throw new IllegalArgumentException("Wrong URI: "+uri);
db = helper.getWritableDatabase();
long rowID = db.insert(CONTACT_TABLE,null,values);
Uri resultURI = ContentUris.withAppendedId(CONTACT_CONTENT_URI,rowID);
getContext().getContentResolver().notifyChange(resultURI,null);
return resultURI;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
Log.d(LOG_TAG,"delete, "+uri.toString());
switch(uriMatcher.match(uri)){
case URI_CONTACT:
Log.d(LOG_TAG,"URI_CONTACT");
break;
case URI_CONTACT_ID:
String id = uri.getLastPathSegment();
Log.d(LOG_TAG,"URI_CONTACTS_ID, "+id);
if(TextUtils.isEmpty(selection))
selection=CONTACT_id+" = "+id;
else
selection = selection + " AND "+CONTACT_id+" = "+id;
break;
default:throw new IllegalArgumentException("Wrong URI: "+uri);
}
db = helper.getWritableDatabase();
int cnt = db.delete(CONTACT_TABLE,selection,selectionArgs);
getContext().getContentResolver().notifyChange(uri,null);
return cnt;
}
#Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
Log.d(LOG_TAG, "update, " + uri.toString());
switch (uriMatcher.match(uri)) {
case URI_CONTACT:
Log.d(LOG_TAG, "URI_CONTACTS");
break;
case URI_CONTACT_ID:
String id = uri.getLastPathSegment();
Log.d(LOG_TAG, "URI_CONTACTS_ID, " + id);
if (TextUtils.isEmpty(selection)) {
selection = CONTACT_id + " = " + id;
} else {
selection = selection + " AND " + CONTACT_id + " = " + id;
}
break;
default:
throw new IllegalArgumentException("Wrong URI: " + uri);
}
db = helper.getWritableDatabase();
int cnt = db.update(CONTACT_TABLE, values, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return cnt;
}
private class DBHelper extends SQLiteOpenHelper{
public DBHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DB_CREATE);
ContentValues cv = new ContentValues();
for (int i = 0; i <=3 ; i++) {
cv.put(CONTACT_NAME,"name "+i);
cv.put(CONTACT_EMAIL,"email "+i);
db.insert(CONTACT_TABLE,null,cv);
}
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
Here is client app:
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>,
View.OnClickListener {
final String LOG_TAG = "myLogs";
static final Uri CONTACT_URI = Uri.parse("content://com.dandewine.user.contentprovider.AddressBook/contacts");
SimpleCursorAdapter adapter;
final String CONTACT_NAME = "name";
final String CONTACT_EMAIL = "email";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String from[] = {"name","email"};
int to[] = {android.R.id.text1,android.R.id.text2};
adapter =new SimpleCursorAdapter(this,android.R.layout.simple_list_item_2,null,from,to,0);
ListView lvContact = (ListView)findViewById(R.id.lvContact);
lvContact.setAdapter(adapter);
getSupportLoaderManager().initLoader(0,null,this);
}
#Override
public void onClick(View v) {
Log.d(LOG_TAG,"onClick");
ContentValues cv = new ContentValues();
Uri uri;
int count;
switch (v.getId()){
case R.id.btnInsert:
cv.put(CONTACT_EMAIL,"email 4");
cv.put(CONTACT_NAME,"name 4");
uri = getContentResolver().insert(CONTACT_URI,cv);
Log.d(LOG_TAG,"insert, result Uri: "+uri.toString());
Toast.makeText(this,"Insert",Toast.LENGTH_SHORT).show();
break;
case R.id.btnDelete:
uri = ContentUris.withAppendedId(CONTACT_URI,3);
count = getContentResolver().delete(uri,null,null);
Log.d(LOG_TAG,"delete, count = "+count);
Toast.makeText(this,"Delete",Toast.LENGTH_SHORT).show();
break;
case R.id.btnUpdate:
cv.put(CONTACT_NAME,"name 5");
cv.put(CONTACT_EMAIL,"email 5");
uri = ContentUris.withAppendedId(CONTACT_URI,2);
count = getContentResolver().update(uri,cv,null,null);
Log.d(LOG_TAG,"update, count ="+count);
Toast.makeText(this,"Update",Toast.LENGTH_SHORT).show();
break;
case R.id.btnError:
Toast.makeText(this,"Error",Toast.LENGTH_SHORT).show();
uri = Uri.parse("content://com.dandewine.user.contentprovider.AddressBook/phones");
try{
Cursor cursor = getContentResolver().query(uri,null,null,null,null);
}catch (Exception ex){
Log.d(LOG_TAG, "Error: " + ex.getClass() + ", " + ex.getMessage());
}
break;
}
getSupportLoaderManager().getLoader(0).forceLoad();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
return new MyLoader(this,CONTACT_URI);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
adapter.swapCursor(cursor);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
private static class MyLoader extends android.support.v4.content.CursorLoader{
Uri uri;
public MyLoader(Context context,Uri uri) {
super(context,uri,null, null, null, null);
this.uri=uri;
}
#Override
public Cursor loadInBackground() {
return getContext().getContentResolver().query(uri,null,null,null,null);
}
}
}
I am totally new in this and I am sure I screwed the code somehow, please help me fix it.
I have the following contentprovider for building a database to store favourite tags:
public class FTagsContentProvider extends ContentProvider {
static final String AUTHORITY = "ch.ethz.twimight.FTags";
private static final String BASE_PATH = "ftags";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ "/" + BASE_PATH);
// fields for the database
public static final String COL_ID = "id";
public static final String COL_TEXT = "text";
public static final String COL_COUNT = "count";
static final int FTAGS = 1;
static final int FTAGS_ID = 2;
DBHelper dbHelper;
private static HashMap<String, String> FTagsMap;
static final UriMatcher uriMatcher;
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, BASE_PATH, FTAGS);
uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", FTAGS_ID);
}
// database declarations
private SQLiteDatabase database;
static final String DATABASE_NAME = "ftagtable.db";
static final String TABLE_FTAGS = "FTags";
static final int DATABASE_VERSION = 1;
private static final String TABLE_FTAGS_CREATE = "create table "
+ TABLE_FTAGS
+ "("
+ COL_ID + " integer primary key autoincrement, "
+ COL_TEXT + " text not null, "
+ COL_COUNT + " integer"
+ ");";
private static class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
// TODO Auto-generated constructor stub
}
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL(TABLE_FTAGS_CREATE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
Log.w(DBHelper.class.getName(),
"Upgrading database from version " + oldVersion + " to "
+ newVersion + ". Old data will be destroyed");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_FTAGS);
onCreate(db);
}
}
#Override
public boolean onCreate() {
// TODO Auto-generated method stub
Context context = getContext();
dbHelper = new DBHelper(context);
database = dbHelper.getWritableDatabase();
if(database == null)
return false;
else
return true;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables(TABLE_FTAGS);
switch (uriMatcher.match(uri)) {
case FTAGS:
queryBuilder.setProjectionMap(FTagsMap);
break;
case FTAGS_ID:
queryBuilder.appendWhere( COL_ID + "=" + uri.getLastPathSegment());
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (sortOrder == null || sortOrder == ""){
sortOrder = COL_TEXT;
}
Cursor cursor = queryBuilder.query(database, projection, selection,
selectionArgs, null, null, sortOrder);
/**
* register to watch a content URI for changes
*/
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
long row = database.insert(TABLE_FTAGS, "", values);
if(row > 0) {
Uri newUri = ContentUris.withAppendedId(CONTENT_URI, row);
getContext().getContentResolver().notifyChange(newUri, null);
return newUri;
}
throw new SQLException("Fail to add a new record into " + uri);
}
#Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
int rowsUpdated = 0;
switch (uriMatcher.match(uri)){
case FTAGS:
rowsUpdated = database.update(TABLE_FTAGS, values, selection, selectionArgs);
break;
case FTAGS_ID:
rowsUpdated = database.update(TABLE_FTAGS, values, COL_ID +
" = " + uri.getLastPathSegment() +
(!TextUtils.isEmpty(selection) ? " AND (" +
selection + ')' : ""), selectionArgs);
break;
default:
throw new IllegalArgumentException("Unsupported URI " + uri );
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
int count = 0;
switch (uriMatcher.match(uri)){
case FTAGS:
count = database.delete(TABLE_FTAGS, selection, selectionArgs);
break;
case FTAGS_ID:
String id = uri.getLastPathSegment(); //gets the id
count = database.delete( TABLE_FTAGS, COL_ID + " = " + id +
(!TextUtils.isEmpty(selection) ? " AND (" +
selection + ')' : ""), selectionArgs);
break;
default:
throw new IllegalArgumentException("Unsupported URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
#Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
}
I want to set the COL_COUNT as a value of keeping count the times that a tag has been inserted into the database, originally it should be 1 for each tag, and I want it to update only the count like from 1 to 2 and so on every time an existing tag is input.
Here is the Activity:
public class TestActivity extends Activity {
private EditText mText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
}
public boolean check(String s){
boolean t = false;
ContentResolver contentResolver = this.getContentResolver();
Cursor cursor = contentResolver.query(FTagsContentProvider.CONTENT_URI,
new String []{FTagsContentProvider.COL_TEXT}, FTagsContentProvider.COL_TEXT + "=?", new String[]{s}, null);
if(cursor.getCount > 0){
t = true;
}
else{
t = false;
}
cursor.close();
return t;
}
public void addFTag(View view) {
// Add a new tag
ContentValues values = new ContentValues();
mText = (EditText)findViewById(R.id.name);
String mFtag = mText.getText().toString();
boolean exist = check(mFtag);
if(exist == false){
values.put(FTagsContentProvider.COL_TEXT,
mFtag);
Uri uri = getContentResolver().insert(
FTagsContentProvider.CONTENT_URI, values);
Toast.makeText(getBaseContext(),
"Record inserted!", Toast.LENGTH_LONG).show();
}
else{
// code for only updating the COL_COUNT somehow
Toast.makeText(this, "Some tag meet you again :)",
Toast.LENGTH_LONG).show();
}}
public void showAllTags(View view) {
Cursor c = getContentResolver().query(FTagsContentProvider.CONTENT_URI, null, null, null, null);
String result = "Results:";
if (!c.moveToFirst()) {
Toast.makeText(this, result+" no content yet!", Toast.LENGTH_LONG).show();
}else{
do{
result = result + "\n" + c.getString(c.getColumnIndex(FTagsContentProvider.COL_TEXT)) +
" with id " + c.getString(c.getColumnIndex(FTagsContentProvider.COL_ID)) +
" has count: " + c.getString(c.getColumnIndex(FTagsContentProvider.COL_COUNT));
} while (c.moveToNext());
Toast.makeText(this, result, Toast.LENGTH_LONG).show();
}
}
}
Any help would be much appreciated :)
When trying to add information to my SQLite database which goes to my content provider. I get this error message on my Logcat.
10-21 12:37:48.045: E/SQLiteLog(25929): (1) near "TABLECows": syntax error
I have looked all over and can't seem to find the where the mistake is. When I use the debugger it doesn't give the location of error. Can you help me see what I am missing to correct this error?
My Database.java
package ag.access.cowsdb;
import ag.access.cowsdb.provider.Cows_Provider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
public class Cowsdatabase extends SQLiteOpenHelper {
private ContentResolver cowcr;
public Cowsdatabase(Context context, String name, CursorFactory factory,
int version) {
super(context,DATABASE_NAME, factory, DATABASE_VERSION);
cowcr = context.getContentResolver();
}
public static final String Key_id = "_id";
public static final String Key_Cow = "Cowid";
public static final String Key_Sire = "Sire";
public static final String Key_Dam = "Dam";
public static final String Key_DOBM = "Month";
public static final String Key_DOBD = "Date";
public static final String Key_DOBY = "Year";
private static final String DATABASE_NAME = "CowsDB";
public static final String DATABASE_TABLE = "Cows";
private static final int DATABASE_VERSION = 1;
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
String Create_Cows_Table = "CREATE TABLE" +
DATABASE_TABLE + "(" +
Key_id + "INTEGER PRIMARY KEY AUTOINCREMENT," +
Key_Cow + "INTEGER NOT NULL" +
Key_Sire + "TEXT NOT NULL," +
Key_Dam + "TEXT NOT NULL," +
Key_DOBM + "INTEGER NOT NULL," +
Key_DOBD + "INTEGER NOT NULL," +
Key_DOBY + "INTEGER NOT NULL," + ")";
db.execSQL(Create_Cows_Table);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
db.execSQL("DROP TABLE IF EXIST " + DATABASE_TABLE);
}
public void addcow(cow Cow) {
ContentValues values = new ContentValues();
values.put(Key_Cow, Cow.getCowid());
values.put(Key_Sire, Cow.getSire());
values.put(Key_Dam, Cow.getDam());
values.put(Key_DOBM, Cow.getMonth());
values.put(Key_DOBD, Cow.getDate());
values.put(Key_DOBY, Cow.getYear());
cowcr.insert(Cows_Provider.Content_Uri, values);
}
public cow findcow(int cowid) {
String[] projection = {Key_id, Key_Cow, Key_Sire, Key_Dam, Key_DOBM, Key_DOBD, Key_DOBY};
String selection = "cowid = \"" + cowid + "\"";
Cursor cursor = cowcr.query(Cows_Provider.Content_Uri, projection, selection, null, null);
cow cow = new cow();
if (cursor.moveToFirst()) {
cursor.moveToFirst();
cow.Setid(Integer.parseInt(cursor.getString(0)));
cow.SetCowid(Integer.parseInt(cursor.getString(1)));
cow.setSire(cursor.getString(2));
cow.setDam(cursor.getString(3));
cow.setMonth(Integer.parseInt(cursor.getString(4)));
cow.setDate(Integer.parseInt(cursor.getString(5)));
cow.setYear(Integer.parseInt(cursor.getString(6)));
cursor.close();
} else {
cow = null;
}
return cow;
}
public boolean deleteCow (int cowid) {
boolean result = false;
String selection = "cowid = \"" + cowid + "\"";
int rowsDeleted = cowcr.delete(Cows_Provider.Content_Uri, selection, null);
if (rowsDeleted > 0)
result = true;
return result;
}
}
My Content Provider.java
package ag.access.cowsdb.provider;
import ag.access.cowsdb.Cowsdatabase;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
public class Cows_Provider extends ContentProvider {
private Cowsdatabase cowsdbh;
private static final String Authority =
"ag.access.cowsdb.provider.Cows_Provider";
private static final String Cows = "Cows";
public static final Uri Content_Uri = Uri.parse("content://" + Authority + "/" + Cows);
public static final int COWS = 1;
public static final int COWS_ID = 2;
private static final UriMatcher cURIMatcher =
new UriMatcher(UriMatcher.NO_MATCH);
static {
cURIMatcher.addURI(Authority, Cows, COWS);
cURIMatcher.addURI(Authority, Cows + "/#", COWS_ID);
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriType = cURIMatcher.match(uri);
SQLiteDatabase mysqldb = cowsdbh.getWritableDatabase();
int rowsDeleted = 0;
switch (uriType) {
case COWS:
rowsDeleted = mysqldb.delete(Cowsdatabase.DATABASE_TABLE, selection, selectionArgs);
break;
case COWS_ID:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = mysqldb.delete(Cowsdatabase.DATABASE_TABLE, Cowsdatabase.Key_Cow + "=" + id, null);
} else {
rowsDeleted = mysqldb.delete(Cowsdatabase.DATABASE_TABLE, Cowsdatabase.Key_Cow + "=" + id + " and " + selection, selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknow URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
int uriType = cURIMatcher.match(uri);
SQLiteDatabase mydb = cowsdbh.getWritableDatabase();
long id = 0;
switch (uriType) {
case COWS:
id = mydb.insert(Cowsdatabase.DATABASE_TABLE, null, values);
break;
default:
throw new IllegalArgumentException("Unknow Uri: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(Cows + "/" + id);
}
#Override
public boolean onCreate() {
cowsdbh = new Cowsdatabase(getContext(), null, null, 1);
return false;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(Cowsdatabase.DATABASE_TABLE);
int uriType = cURIMatcher.match(uri);
switch (uriType) {
case COWS_ID:
qb.appendWhere(cowsdbh.Key_Cow + "=" + uri.getLastPathSegment());
break;
case COWS:
break;
default:
throw new IllegalArgumentException("Unknown URI");
}
Cursor cursor = qb.query(cowsdbh.getReadableDatabase(), projection, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int uriType = cURIMatcher.match(uri);
SQLiteDatabase mysqldb = cowsdbh.getWritableDatabase();
int rowsUpdated = 0;
switch (uriType) {
case COWS:
rowsUpdated = mysqldb.update(Cowsdatabase.DATABASE_TABLE, values, selection, selectionArgs);
break;
case COWS_ID:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated =
mysqldb.update(Cowsdatabase.DATABASE_TABLE, values, Cowsdatabase.Key_Cow + "=" + id, null);
} else {
rowsUpdated =
mysqldb.update(Cowsdatabase.DATABASE_TABLE, values, Cowsdatabase.Key_Cow + "=" + id + " and " + selection, selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI:" + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
#Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
}
How and where can i correct this error?
Thanks
On the first line of the onCreate method, add a space, so that it looks like this.
String Create_Cows_Table = "CREATE TABLE " +
I'm developing an app that (so far) pulls data from an API, inserts it to a local SQLite database & displays it on screen.
In order to make my life simpler, I wrote a master database adapter (MyDBAdapter) as well as adapters for each individual table, according to the top anser for this question.
While developing the app, I'm also teaching myself unit testing in JUnit (not sure if this is relevant, but I figured I'd throw it in there).
When trying to refresh the database I somehow dropped all the tables and now I can't get them back. When I increment the DB_VERSION value, onUpgrade() doesn't get called, and the app errors out because it's trying to access nonexistent tables.
What circumstances would cause onUpgrade() to not get called? I'm at my wits' end trying to figure this out.
MyDbAdapter:
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class MyDbAdapter {
public static final String TAG = "MyDbAdapter";
protected static final String DB_NAME = "mydb.db";
protected static final int DB_VERSION = 21;
private final Context context;
private DbHelper helper;
private SQLiteDatabase db;
private static final String CREATE_TABLE_CRUISE_LINES = "create table " + CruiseLineAdapter.TABLE + " (" + CruiseLineAdapter.C_ID + " integer primary key autoincrement, "
+ CruiseLineAdapter.C_NAME + " TEXT);";
private static final String CREATE_TABLE_SHIPS = "create table " + ShipAdapter.TABLE + " (" + ShipAdapter.C_ID + " integer primary key autoincrement, "
+ ShipAdapter.C_NAME + " TEXT, "
+ ShipAdapter.C_CRUISE_LINE + " integer);";
private static final String CREATE_TABLE_TABLE_UPDATES = "create table " + UpdateTimestampAdapter.TABLE + " (" + UpdateTimestampAdapter.C_ID + " integer primary key autoincrement, "
+ UpdateTimestampAdapter.C_TABLE_NAME + " TEXT, "
+ UpdateTimestampAdapter.C_LAST_UPDATE + " TEXT);";
private static final String DROP_TABLE = "drop table if exists %s";
private static final String DROP_TABLE_CRUISE_LINES = String.format(DROP_TABLE, CruiseLineAdapter.TABLE);
private static final String DROP_TABLE_SHIPS = String.format(DROP_TABLE, ShipAdapter.TABLE);
private static final String DROP_TABLE_TABLE_UPDATES = String.format(DROP_TABLE, UpdateTimestampAdapter.TABLE);
public MyDbAdapter (Context context) {
this.context = context;
helper = new DbHelper(this.context);
}
private static class DbHelper extends SQLiteOpenHelper {
DbHelper (Context context) {
super(context, DB_NAME, null, DB_VERSION);
Log.i(TAG, "initialized");
}
#Override
public void onCreate(SQLiteDatabase db) {
Log.i(TAG, "Database created: version " + DB_VERSION);
db.execSQL(CREATE_TABLE_CRUISE_LINES);
db.execSQL(CREATE_TABLE_SHIPS);
db.execSQL(CREATE_TABLE_TABLE_UPDATES);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i(TAG, "Database upgraded to " + DB_VERSION);
db.execSQL(DROP_TABLE_CRUISE_LINES);
db.execSQL(DROP_TABLE_SHIPS);
db.execSQL(DROP_TABLE_TABLE_UPDATES);
this.onCreate(db);
}
}
public MyDbAdapter open() throws SQLException {
db = helper.getWritableDatabase();
return this;
}
public void close() {
helper.close();
}
}
ShipAdapter:
import java.util.ArrayList;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
public class ShipAdapter {
public static final String TAG = "ShipAdapter";
public static final String TABLE = "ships";
public static final String C_ID = BaseColumns._ID;
public static final String C_NAME = "name";
public static final String C_CRUISE_LINE = "cruise_line";
private DbHelper dbHelper;
private SQLiteDatabase db;
private final Context context;
private static class DbHelper extends SQLiteOpenHelper {
DbHelper (Context context) {
super(context, MyDbAdapter.DB_NAME, null, MyDbAdapter.DB_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
public ShipAdapter(Context context) {
this.context = context;
}
public ShipAdapter open() throws SQLException {
dbHelper = new DbHelper(context);
db = dbHelper.getWritableDatabase();
return this;
}
public void close() {
dbHelper.close();
}
public long createShip(String name, long cruise_line_id) {
ContentValues initialValues = new ContentValues();
initialValues.put(C_NAME, name);
initialValues.put(C_CRUISE_LINE, cruise_line_id);
return db.insert(TABLE, null, initialValues);
}
public long createShip(long id, String name, long cruise_line_id) {
ContentValues initialValues = new ContentValues();
initialValues.put(C_ID, id);
initialValues.put(C_NAME, name);
initialValues.put(C_CRUISE_LINE, cruise_line_id);
return db.insert(TABLE, null, initialValues);
}
public long createShip(ShipModel ship) {
return createShip(ship.getName(), ship.getCruiseLineId());
}
public long insertOrIgnoreShip(long id, String name, long cruise_line_id) {
ContentValues initialValues = new ContentValues();
initialValues.put(C_ID, id);
initialValues.put(C_NAME, name);
initialValues.put(C_CRUISE_LINE, cruise_line_id);
return db.insertWithOnConflict(TABLE, null, initialValues, SQLiteDatabase.CONFLICT_IGNORE);
}
public long insertOrIgnoreShip(ShipModel ship) {
return insertOrIgnoreShip(ship.getId(), ship.getName(), ship.getCruiseLineId());
}
public List<ShipModel> getAllShips() {
List<ShipModel> ships = new ArrayList<ShipModel>();
Cursor cursor = getAllShipsCursor();
if (cursor.getCount() > 0) {
while(!cursor.isAfterLast()) {
ships.add(cursorToShip(cursor));
cursor.moveToNext();
}
}
return ships;
}
public Cursor getAllShipsCursor() {
Cursor cursor = db.query(TABLE, null, null, null, null, null, null);
if (cursor.getCount() > 0) {
cursor.moveToFirst();
}
return cursor;
}
public ShipModel getShip(long id) {
Cursor cursor = getShipCursor(id);
if (cursor.getCount() > 0) {
return cursorToShip(cursor);
}
return null;
}
public Cursor getShipCursor(long id) {
Cursor cursor = db.query(TABLE, null, C_ID + " = ?", new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor.getCount() > 0) {
cursor.moveToFirst();
}
return cursor;
}
public ShipModel getShip(String name) {
Cursor cursor = getShipCursor(name);
if (cursor.getCount() > 0) {
return cursorToShip(cursor);
}
return null;
}
public Cursor getShipCursor(String name) {
Cursor cursor = db.query(TABLE, null, C_NAME + " = ?", new String[] { name }, null, null, null, null);
if (cursor.getCount() > 0) {
cursor.moveToFirst();
}
return cursor;
}
public List<ShipModel> getShipsByCruiseLine(long cruise_line_id) {
List<ShipModel> ships = new ArrayList<ShipModel>();
Cursor cursor = getShipsCursorByCruiseLine(cruise_line_id);
if (cursor.getCount() > 0) {
while (!cursor.isAfterLast()) {
ships.add(cursorToShip(cursor));
cursor.moveToNext();
}
}
return ships;
}
public Cursor getShipsCursorByCruiseLine(long cruise_line_id) {
Cursor cursor = db.query(TABLE, null, C_CRUISE_LINE + " = ?", new String[] { String.valueOf(cruise_line_id) }, null, null, null, null);
if (cursor.getCount() > 0) {
cursor.moveToFirst();
}
return cursor;
}
public boolean updateShip(long id, String name, long cruise_line_id) {
ContentValues args = new ContentValues();
args.put(C_NAME, name);
args.put(C_CRUISE_LINE, cruise_line_id);
return db.update(TABLE, args, C_ID + " = ?", new String[] { String.valueOf(id) }) > 0;
}
public boolean updateShip(ShipModel ship) {
return updateShip(ship.getId(), ship.getName(), ship.getCruiseLineId());
}
public boolean deleteShip(long id) {
return db.delete(TABLE, C_ID + " = ?", new String[] { String.valueOf(id) }) > 0;
}
public boolean deleteShip(String name) {
return db.delete(TABLE, C_NAME + " = ?", new String[] { name }) > 0;
}
public boolean deleteShip(ShipModel ship) {
return deleteShip(ship.getName());
}
public boolean deleteAll() {
return db.delete(TABLE, null, null) > 0;
}
private ShipModel cursorToShip(Cursor cursor) {
long id = cursor.getLong(cursor.getColumnIndex(C_ID));
String name = cursor.getString(cursor.getColumnIndex(C_NAME));
long cruise_line_id = cursor.getLong(cursor.getColumnIndex(C_CRUISE_LINE));
return new ShipModel(id, name, cruise_line_id);
}
}
Communicator:
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.ConnectivityManager;
import android.util.Log;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NoHttpResponseException;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* Created by mcampo on 5/30/13.
*/
public class Communicator {
private static final String TAG = "Communicator";
private static final int CONNECTION_TIMEOUT = 10000;
protected String base_url = "http://[myapi]/mobileapi/";
protected Context context;
protected CruiseLineAdapter cruise_line_adapter;
protected ShipAdapter ship_adapter;
protected UpdateTimestampAdapter table_update_adapter;
protected String update_timestamps_json;
public Communicator() {
}
public Communicator (Context context) {
this.context = context;
this.cruise_line_adapter = new CruiseLineAdapter(this.context);
this.ship_adapter = new ShipAdapter(this.context);
this.table_update_adapter = new UpdateTimestampAdapter(this.context);
}
// begin defining getters / setters
/**
*
* #param context
*/
public void setContext(Context context) {
this.context = context;
this.cruise_line_adapter = new CruiseLineAdapter(this.context);
this.ship_adapter = new ShipAdapter(this.context);
this.table_update_adapter = new UpdateTimestampAdapter(this.context);
}
public Context getContext() {
return this.context;
}
// end getters / setters
private boolean isNetworkConnected() {
if (context == null) {
return false;
}
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo() != null;
}
private String makeApiCall(String api_extension) throws IOException {
if (!isNetworkConnected()) {
throw new IOException("Your device is not connected to the internet. Please enable your network connection and restart CabinGuru.");
}
Log.d(TAG, "Making HTTP request to " + this.base_url + api_extension);
HttpClient httpClient = new DefaultHttpClient();
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, CONNECTION_TIMEOUT);
HttpResponse response = httpClient.execute(new HttpGet(this.base_url + api_extension));
StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
response.getEntity().writeTo(out);
out.close();
Log.i(TAG, "HTTP Response: " + out.toString());
return out.toString();
} else {
response.getEntity().getContent().close();
throw new IOException(statusLine.getReasonPhrase());
}
}
private boolean tableIsUpToDate(String table) throws IOException {
try {
String api_timestamp = getApiUpdateTimestamp(table);
String device_timestamp = getDeviceUpdateTimestamp(table);
if (device_timestamp == null || device_timestamp.equals("")) {
throw new NullPointerException("device_timestamp is null");
}
Log.i(TAG, "API Timestamp: " + api_timestamp);
Log.i(TAG, "Device Timestamp: " + device_timestamp);
// compare device_timestamp to api_timestamp. If device_timestamp comes after api_timestamp, table is up-to-date.
DateTime api_datetime = this.strToDateTime(api_timestamp);
DateTime device_datetime = this.strToDateTime(device_timestamp);
return device_datetime.isAfter(api_datetime);
} catch (NullPointerException e) {
e.printStackTrace();
Log.e(TAG, "NullPointerException encountered in tableIsUpToDate(" + table + "): " + e.getMessage() + " " + e.getCause());
return false;
}
}
private String getDeviceUpdateTimestamp(String table) {
String return_string = "";
table_update_adapter.open();
UpdateTimestampModel timestamp = this.table_update_adapter.getUpdateTimestamp(table);
table_update_adapter.close();
try {
return_string = timestamp.getLastUpdate();
return return_string;
} catch (NullPointerException e) {
Log.e(TAG, "NullPointerException encountered in getDeviceUpdateTimestamp(" + table + "): " + e.getMessage());
return "";
}
}
private boolean updateLastUpdateTimestamp(String table) {
// set up current timestamp
DateTime timestamp = new DateTime(System.currentTimeMillis());
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
String now = formatter.print(timestamp);
// fetch ID of row to update
table_update_adapter.open();
table_update_adapter.updateOrCreateTimestamp(table, now);
table_update_adapter.close();
return true;
}
private void getApiUpdateTimestamps() throws IOException {
if (this.update_timestamps_json == null || this.update_timestamps_json.equals(""))
try {
this.update_timestamps_json = this.makeApiCall("get_update_timestamps");
} catch (NoHttpResponseException e) {
Log.e(TAG, "App was unable to connect to the servers.");
}
}
private String getApiUpdateTimestamp(String table) throws IOException {
this.getApiUpdateTimestamps();
try {
if (this.update_timestamps_json == null) {
throw new Exception("Could not fetch update timestamps. Check and make sure you are able to connect to " + this.base_url + ".");
}
JSONObject timestamps = new JSONObject(this.update_timestamps_json);
return timestamps.getString(table);
} catch (JSONException e) {
Log.e(TAG, "An error occurred when extracting update timestamps from the api: " + e.getMessage() + " | " + e.getCause());
return null;
} catch (Exception e) {
Log.e(TAG, e.getMessage());
return null;
}
}
public boolean updateCruiseLines() throws IOException {
// if the cruise lines from the API have been updated since the last update on the device, update the device.
if (!this.tableIsUpToDate(CruiseLineAdapter.TABLE)) {
Log.i(TAG, "Attempting API call for Cruise Lines.");
try {
String cruise_line_json = this.makeApiCall("cruise_lines");
JSONArray cruise_lines = new JSONArray(cruise_line_json);
// loop through cruise_lines, add to database
int array_size = cruise_lines.length();
cruise_line_adapter.open();
for (int i = 0; i < array_size; i++) {
JSONObject cruise_line = cruise_lines.getJSONObject(i);
int cruise_line_id = cruise_line.getInt("CruiseLineID");
String cruise_line_name = cruise_line.getString("Name");
// insert record into database.
this.cruise_line_adapter.insertOrIgnoreCruiseLine(cruise_line_id, cruise_line_name);
}
cruise_line_adapter.close();
this.updateLastUpdateTimestamp(CruiseLineAdapter.TABLE);
} catch (JSONException e) {
Log.e(TAG, "JSONException encountered in updateCruiseLines(): " + e.getMessage());
e.printStackTrace();
return false;
}
} else {
Log.i(TAG, "Cruise Line records exist. No API call necessary.");
}
return true;
}
public boolean updateShips() throws IOException {
// if the ships from the API have been updated since the last update on the device, update the device
if (!this.tableIsUpToDate(ShipAdapter.TABLE)) {
Log.i(TAG, "Attempting API call for Ships.");
try {
String ships_json = this.makeApiCall("ships");
JSONArray ships = new JSONArray(ships_json);
// loop through ships, add to database
int array_size = ships.length();
ship_adapter.open();
for (int i = 0; i < array_size; i++) {
JSONObject ship = ships.getJSONObject(i);
int id = ship.getInt("ShipID");
String name = ship.getString("ShipName");
int cruise_line_id = ship.getInt("CruiseLineID");
this.ship_adapter.insertOrIgnoreShip(id, name, cruise_line_id);
}
ship_adapter.close();
this.updateLastUpdateTimestamp(ShipAdapter.TABLE);
} catch (JSONException e) {
Log.e(TAG, "JSONException encountered in updateShips():" + e.getMessage());
e.printStackTrace();
return false;
}
} else {
Log.i(TAG, "Ship records exist. No API call necessary.");
}
return true;
}
private DateTime strToDateTime(String timestamp) {
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
return formatter.parseDateTime(timestamp);
}
}
Android would not be able to figure out that it needs to run MyDbAdapter on its own.
Create a class that extends Application.
public class MyApplication extends Application {
private static MyDbAdapter dbAdapter;
#Override
public void onCreate() {
super.onCreate();
dbAdapter = new MyDbAdapter(getApplicationContext());
}
}
On your AndroidManifest.xml, you need to set the attribute in the application element like this:
<application
android:name=".MyApplication"
...
/application>
After stepping away from the problem for a few hours I came up with this solution:
Instead of making the *Adapter classes independent of one another, I modified the code to make them children of MyDBAdapter. This way, when open() is called, it calls the open() method of MyDBAdapter, checking the DB version & upgrading when appropriate.
MyDbAdapter:
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class MyDbAdapter {
public static final String TAG = "MyDbAdapter";
protected static final String DB_NAME = "mydb.db";
protected static final int DB_VERSION = 21;
private final Context context;
private DbHelper helper;
private SQLiteDatabase db;
private static final String CREATE_TABLE_CRUISE_LINES = "create table " + CruiseLineAdapter.TABLE + " (" + CruiseLineAdapter.C_ID + " integer primary key autoincrement, "
+ CruiseLineAdapter.C_NAME + " TEXT);";
private static final String CREATE_TABLE_SHIPS = "create table " + ShipAdapter.TABLE + " (" + ShipAdapter.C_ID + " integer primary key autoincrement, "
+ ShipAdapter.C_NAME + " TEXT, "
+ ShipAdapter.C_CRUISE_LINE + " integer);";
private static final String CREATE_TABLE_TABLE_UPDATES = "create table " + UpdateTimestampAdapter.TABLE + " (" + UpdateTimestampAdapter.C_ID + " integer primary key autoincrement, "
+ UpdateTimestampAdapter.C_TABLE_NAME + " TEXT, "
+ UpdateTimestampAdapter.C_LAST_UPDATE + " TEXT);";
private static final String DROP_TABLE = "drop table if exists %s";
private static final String DROP_TABLE_CRUISE_LINES = String.format(DROP_TABLE, CruiseLineAdapter.TABLE);
private static final String DROP_TABLE_SHIPS = String.format(DROP_TABLE, ShipAdapter.TABLE);
private static final String DROP_TABLE_TABLE_UPDATES = String.format(DROP_TABLE, UpdateTimestampAdapter.TABLE);
public MyDbAdapter (Context context) {
this.context = context;
helper = new DbHelper(this.context);
}
private static class DbHelper extends SQLiteOpenHelper {
DbHelper (Context context) {
super(context, DB_NAME, null, DB_VERSION);
Log.i(TAG, "initialized");
}
#Override
public void onCreate(SQLiteDatabase db) {
Log.i(TAG, "Database created: version " + DB_VERSION);
db.execSQL(CREATE_TABLE_CRUISE_LINES);
db.execSQL(CREATE_TABLE_SHIPS);
db.execSQL(CREATE_TABLE_TABLE_UPDATES);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i(TAG, "Database upgraded to " + DB_VERSION);
db.execSQL(DROP_TABLE_CRUISE_LINES);
db.execSQL(DROP_TABLE_SHIPS);
db.execSQL(DROP_TABLE_TABLE_UPDATES);
this.onCreate(db);
}
}
public MyDbAdapter open() throws SQLException {
db = helper.getWritableDatabase();
return this;
}
public void close() {
helper.close();
}
}
ShipAdapter:
import java.util.ArrayList;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
public class ShipAdapter extends MyDbAdapter {
public static final String TAG = "ShipAdapter";
public static final String TABLE = "ships";
public static final String C_ID = BaseColumns._ID;
public static final String C_NAME = "name";
public static final String C_CRUISE_LINE = "cruise_line";
public ShipAdapter(Context context) {
this.context = context;
}
public long createShip(String name, long cruise_line_id) {
ContentValues initialValues = new ContentValues();
initialValues.put(C_NAME, name);
initialValues.put(C_CRUISE_LINE, cruise_line_id);
return db.insert(TABLE, null, initialValues);
}
public long createShip(long id, String name, long cruise_line_id) {
ContentValues initialValues = new ContentValues();
initialValues.put(C_ID, id);
initialValues.put(C_NAME, name);
initialValues.put(C_CRUISE_LINE, cruise_line_id);
return db.insert(TABLE, null, initialValues);
}
public long createShip(ShipModel ship) {
return createShip(ship.getName(), ship.getCruiseLineId());
}
public long insertOrIgnoreShip(long id, String name, long cruise_line_id) {
ContentValues initialValues = new ContentValues();
initialValues.put(C_ID, id);
initialValues.put(C_NAME, name);
initialValues.put(C_CRUISE_LINE, cruise_line_id);
return db.insertWithOnConflict(TABLE, null, initialValues, SQLiteDatabase.CONFLICT_IGNORE);
}
public long insertOrIgnoreShip(ShipModel ship) {
return insertOrIgnoreShip(ship.getId(), ship.getName(), ship.getCruiseLineId());
}
public List<ShipModel> getAllShips() {
List<ShipModel> ships = new ArrayList<ShipModel>();
Cursor cursor = getAllShipsCursor();
if (cursor.getCount() > 0) {
while(!cursor.isAfterLast()) {
ships.add(cursorToShip(cursor));
cursor.moveToNext();
}
}
return ships;
}
public Cursor getAllShipsCursor() {
Cursor cursor = db.query(TABLE, null, null, null, null, null, null);
if (cursor.getCount() > 0) {
cursor.moveToFirst();
}
return cursor;
}
public ShipModel getShip(long id) {
Cursor cursor = getShipCursor(id);
if (cursor.getCount() > 0) {
return cursorToShip(cursor);
}
return null;
}
public Cursor getShipCursor(long id) {
Cursor cursor = db.query(TABLE, null, C_ID + " = ?", new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor.getCount() > 0) {
cursor.moveToFirst();
}
return cursor;
}
public ShipModel getShip(String name) {
Cursor cursor = getShipCursor(name);
if (cursor.getCount() > 0) {
return cursorToShip(cursor);
}
return null;
}
public Cursor getShipCursor(String name) {
Cursor cursor = db.query(TABLE, null, C_NAME + " = ?", new String[] { name }, null, null, null, null);
if (cursor.getCount() > 0) {
cursor.moveToFirst();
}
return cursor;
}
public List<ShipModel> getShipsByCruiseLine(long cruise_line_id) {
List<ShipModel> ships = new ArrayList<ShipModel>();
Cursor cursor = getShipsCursorByCruiseLine(cruise_line_id);
if (cursor.getCount() > 0) {
while (!cursor.isAfterLast()) {
ships.add(cursorToShip(cursor));
cursor.moveToNext();
}
}
return ships;
}
public Cursor getShipsCursorByCruiseLine(long cruise_line_id) {
Cursor cursor = db.query(TABLE, null, C_CRUISE_LINE + " = ?", new String[] { String.valueOf(cruise_line_id) }, null, null, null, null);
if (cursor.getCount() > 0) {
cursor.moveToFirst();
}
return cursor;
}
public boolean updateShip(long id, String name, long cruise_line_id) {
ContentValues args = new ContentValues();
args.put(C_NAME, name);
args.put(C_CRUISE_LINE, cruise_line_id);
return db.update(TABLE, args, C_ID + " = ?", new String[] { String.valueOf(id) }) > 0;
}
public boolean updateShip(ShipModel ship) {
return updateShip(ship.getId(), ship.getName(), ship.getCruiseLineId());
}
public boolean deleteShip(long id) {
return db.delete(TABLE, C_ID + " = ?", new String[] { String.valueOf(id) }) > 0;
}
public boolean deleteShip(String name) {
return db.delete(TABLE, C_NAME + " = ?", new String[] { name }) > 0;
}
public boolean deleteShip(ShipModel ship) {
return deleteShip(ship.getName());
}
public boolean deleteAll() {
return db.delete(TABLE, null, null) > 0;
}
private ShipModel cursorToShip(Cursor cursor) {
long id = cursor.getLong(cursor.getColumnIndex(C_ID));
String name = cursor.getString(cursor.getColumnIndex(C_NAME));
long cruise_line_id = cursor.getLong(cursor.getColumnIndex(C_CRUISE_LINE));
return new ShipModel(id, name, cruise_line_id);
}
}
I am populating a ListView using a SimpleCursorAdapter
#Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
String[] projection = new String[] { BlogTable.TITLE_PLAIN, BlogTable.DATE_MODIFIED, BlogTable.EXCERPT, BlogTable.ID };
CursorLoader loader = new CursorLoader(parent, BlogContentProvider.CONTENT_URI, projection, null, null, BlogTable.DATE_MODIFIED + " DESC LIMIT " + BlogContentProvider.QUERY_LIMIT);
return loader;
}
private void fillData(){
//_id is expected from this method that is why we used it earlier
String[] from = new String[] { BlogTable.TITLE_PLAIN, BlogTable.DATE_MODIFIED, BlogTable.EXCERPT};
int[] to = new int[] { R.id.text_news_title, R.id.text_news_date, R.id.text_news_excerpt};
//initialize loader to call this class with a callback
getLoaderManager().initLoader(0, null, this);
//We create adapter to fill list with data, but we don't provide any data as it will be done by loader
adapter = new SimpleCursorAdapter(parent, R.layout.news_list_view, null, from, to, 0);
setListAdapter(adapter);
}
I want to load only 10 items at a time and then at the end of the list call a method addData() and get 10 more rows and so on. I know there is the CWAC EndlessAdapter for this, however I do not know what call to make to add another 10 rows to the current ListView and at the same time keep position.
I know this may sound like a stupid question but I am relatively new to Android development and still learning. Can anyone help?
EDIT:
This is the ContentProvider I am using, maybe it can be of help
package com.brndwgn.database;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
public class BlogContentProvider extends ContentProvider {
private DbHelper dbh;
//identifiers for URI types
public static final int BLOG_LIST = 1;
public static final int BLOG_ITEM = 2;
//elements of our URI to identify our COntentProvider
public static final String AUTHORITY = "com.brndwgn.database";
public static final String BASE_PATH = "blog";
//URI to query from this Content provider
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);
//MIME data types we offer
public static final String BLOG_LIST_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/bloglist";
public static final String BLOG_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/blogitem";
public static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
//patterns for our provider
static {
matcher.addURI(AUTHORITY, BASE_PATH, BLOG_LIST);
matcher.addURI(AUTHORITY, BASE_PATH + "/#", BLOG_ITEM);
}
public static final int QUERY_LIMIT = 2;
#Override
public boolean onCreate() {
dbh = new DbHelper(getContext());
return true;
}
#Override
public String getType(Uri uri) {
int uriId = matcher.match(uri);
//we check id of URI and return correct MIME type, we defined all of them before
switch(uriId) {
case BLOG_ITEM: return BLOG_ITEM_TYPE;
case BLOG_LIST: return BLOG_LIST_TYPE;
default:
throw new IllegalArgumentException("Unknown uri: " + uri);
}
}
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
int uriId = matcher.match(uri);
//we create object of SQL query builder so we don't need to use plain SQL
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
//Set a name for the table to query
builder.setTables(BlogTable.TABLE_NAME);
switch(uriId) {
case BLOG_ITEM:
//set where condition to get just one row
builder.appendWhere(BlogTable.ID + "=" + uri.getLastPathSegment());
break;
case BLOG_LIST:
//we don't need to do anything here
break;
default:
new IllegalArgumentException("Unknown uri: " + uri);
}
//get instance of database
SQLiteDatabase db = dbh.getReadableDatabase();
//execute query
Cursor cursor = builder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
//set notifications for this URI
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriId = matcher.match(uri);
int deleted=0;
SQLiteDatabase db = dbh.getWritableDatabase();
switch(uriId) {
case BLOG_LIST:
deleted = db.delete(BlogTable.TABLE_NAME, selection, selectionArgs);
break;
case BLOG_ITEM:
if(TextUtils.isEmpty(selection)) {
deleted = db.delete(BlogTable.TABLE_NAME, BlogTable.ID + "=" + uri.getLastPathSegment(), selectionArgs);
}
else {
deleted = db.delete(BlogTable.TABLE_NAME, selection + " and " + BlogTable.ID + "=" + uri.getLastPathSegment(), selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknow uri: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return deleted;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
int uriId = matcher.match(uri);
//Variable for ID of new record
long newId;
switch(uriId) {
case BLOG_LIST:
//get instance of Database
SQLiteDatabase db = dbh.getWritableDatabase();
//execute query
newId = db.replace(BlogTable.TABLE_NAME, null, values);
//newId = db.insertWithOnConflict(BlogTable.TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_IGNORE);
//create URI for new added record
Uri newuri = Uri.parse(CONTENT_URI + "/" + newId);
//notify change for list URI
getContext().getContentResolver().notifyChange(uri, null);
return newuri;
default:
throw new IllegalArgumentException("Unknown uri: " + uri);
}
}
#Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int uriId = matcher.match(uri);
int updated=0;
SQLiteDatabase db = dbh.getWritableDatabase();
switch(uriId) {
case BLOG_LIST:
updated = db.update(BlogTable.TABLE_NAME, values, selection, selectionArgs);
break;
case BLOG_ITEM:
if(TextUtils.isEmpty(selection)) {
updated = db.update(BlogTable.TABLE_NAME, values, BlogTable.ID + "=" + uri.getLastPathSegment(), null);
}
else {
updated = db.update(BlogTable.TABLE_NAME, values, selection + " and " + BlogTable.ID + "=" + uri.getLastPathSegment(), selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return updated;
}
}
Use
adapter.notifyDataSetChanged();
where adapter is your SimpleCursorAdapter for the listview
Edit:
before that you should add data to your adapter. To achieve this, add a method for your adapter to query from the database.