1

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.

  • 1
    Possible duplicate of [Can't determine what is throwing a NullPointer exception](http://stackoverflow.com/questions/2291159/cant-determine-what-is-throwing-a-nullpointer-exception) – Luiz Fernando Salvaterra May 08 '17 at 15:42
  • "App crashes at getWritableDatabase: NullPointerException" -- `dbHelper` is `null`, apparently. – CommonsWare May 08 '17 at 15:42
  • 1
    I bet you that `Context ctx = MyApp.getContext();` returned null because static methods for getting a context are bad – OneCricketeer May 10 '17 at 18:57

2 Answers2

1

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.

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • I know because in an earlier version, I had an if/else that would put out a specific message if the context was null, and once I implemented the MyApp version that stopped showing up as a problem. – IronLucario2012 May 10 '17 at 19:04
  • Also, as regards making a database without a ContentProvider, I've already torn this to shreds and rebuilt it from the ground up twice. I'd rather not do it a third time if at all possible. – IronLucario2012 May 10 '17 at 19:27
  • It's just a suggestion. Have you tested the database before attempting to strap a ContentProvider over it? – OneCricketeer May 10 '17 at 19:29
  • Also, the "DBHelper" is supposed to "help" with the `SQLiteDatabase` object. Why do you have one just floating around on its own in the ContentProvider? – OneCricketeer May 10 '17 at 19:32
  • I've tested the database by itself and it was fine. And the DBHelper is in the ContentProvider to deal with setting up the tables for me. – IronLucario2012 May 10 '17 at 19:47
  • Not sure what to tell you, other than the Context has to be null... Source code: https://github.com/android/platform_frameworks_base/blob/master/core/java/android/database/sqlite/SQLiteOpenHelper.java#L223 – OneCricketeer May 10 '17 at 20:03
  • 1
    So, despite the fact that I tried this exact solution not four hours ago and it failed, eventually some permutation of putting in getContext() somewhere seems to have fixed it. Somehow. There are still errors, but they're completely unrelated. Thanks! – IronLucario2012 May 10 '17 at 20:18
  • Again, `getContext()` shouldn't be used in that capacity. Try `YourActivity.this`, or `getApplicationContext()` at the very least when you call `getInstance` on the content provider – OneCricketeer May 10 '17 at 20:20
0

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

jayeshsolanki93
  • 2,096
  • 1
  • 20
  • 37
  • That just moved the problem. Now the stacktrace looks like this: `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.query(DigimonContentProvider.java:126)` – IronLucario2012 May 10 '17 at 17:34
  • Also nope. The `DBHelper` class is a singleton. And the `insert()` method doesn't even involve `dbHelper`, the error is now at line 62 which is in the `onCreate()` method. – IronLucario2012 May 10 '17 at 18:14
  • I added the DBHelper code to the main question, in case it helps. – IronLucario2012 May 10 '17 at 18:23