0

I need to copy a SQLite database from assets/ into the app's databases/ directory, but as I'll show you below, I keep getting null pointer exceptions. Below is some potentially relevant Logcat and code:

   [ 11-24 21:51:19.694  1652:0x67e E/AndroidRuntime ]
    FATAL EXCEPTION: AsyncTask #1
    java.lang.RuntimeException: An error occured while executing doInBackground()
        at android.os.AsyncTask$3.done(AsyncTask.java:200)
        at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
        at java.util.concurrent.FutureTask.run(FutureTask.java:138)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
        at java.lang.Thread.run(Thread.java:1019)
    Caused by: java.lang.NullPointerException
        at net.xx.wildedibles.full.common.DataBaseHelper.<init>(DataBaseHelper.java:27)
        at net.xx.wildedibles.full.common.DBAdapter.<init>(DBAdapter.java:21)
        at net.xx.wildedibles.full.intro.LoadingFragment$LoadingTask.doInBackground(LoadingFragment.java:75)
        at net.xx.wildedibles.full.intro.LoadingFragment$LoadingTask.doInBackground(LoadingFragment.java:68)
        at android.os.AsyncTask$2.call(AsyncTask.java:185)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
        ... 4 more

Line 27 of DatabaseHelper:

  DB_PATH = context.getDatabasePath(DB_NAME).toString();

Now I know that there are several ways out there to calculate the path to the databases/, and I've tried essentially all of them, with none working. Still get the same NPE.

But here's a little curiosity: I decided to do adb shell and look into the app's directory structure, to get a better idea as to where I've been going wrong. Here's what I get after navigating to data/data/package.name/:

# cd net.xx.wildedibles.full
# ls
lib
# 

Why can't I see /databases/, and where's all the other stuff? When I go into lib/, there's nothing inside. As you can see, I'm root while looking. Given this, I can certainly see why I'd be getting a null pointer...

Thanks so much for any advice you can offer!

As requested, here's the full code:

Here's a DBAdapter class:

public class DBAdapter 
{
    protected static final String TAG = "DataAdapter";

    private final Context mContext;
    private SQLiteDatabase mDb;
    private DataBaseHelper mDbHelper;

    public DBAdapter(Context context) 
    {
    mContext = context;
        mDbHelper = new DataBaseHelper(mContext);
   }

    public DBAdapter createDatabase() throws SQLException 
    {
        try 
        {
            mDbHelper.createDataBase();
        } 
        catch (IOException mIOException) 
        {
            Log.e(TAG, mIOException.toString() + "  UnableToCreateDatabase");
            throw new Error("UnableToCreateDatabase");
        }
        return this;
    }

    public DBAdapter open() throws SQLException 
    {
        try 
        {
            mDbHelper.openDataBase();
            mDbHelper.close();
            mDb = mDbHelper.getReadableDatabase();
        } 
        catch (SQLException mSQLException) 
        {
            Log.e(TAG, "open >>"+ mSQLException.toString());
            throw mSQLException;
        }
        return this;
    }

    public void close() 
    {
        mDbHelper.close();
    }

     public Cursor getData(String query)
     {
         try
         {

             Cursor mCur = mDb.rawQuery(query, null);
             if (mCur!=null)
             {
                mCur.moveToNext();
             }
             return mCur;
         }
         catch (SQLException mSQLException) 
         {
             Log.e(TAG, "getData >>"+ mSQLException.toString());
             throw mSQLException;
         }
     }
}

Here's the whole of the Helper class:

public class DataBaseHelper extends SQLiteOpenHelper{

    private static String TAG = "DataBaseHelper"; //tag for logcat
    private static String DB_PATH;
    private static String DB_NAME ="foraging.db";// Database name
    private SQLiteDatabase mDataBase; 
    private final Context mContext;

    public DataBaseHelper(Context context){

        super(context, DB_NAME, null, 1);
        if(android.os.Build.VERSION.SDK_INT >= 4.2){
           DB_PATH = context.getDatabasePath(DB_NAME).toString();

        }
        else
        {
           DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
        }
        this.mContext = context;
    }   

    public void onCreate(SQLiteDatabase db) {

    }

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
        //db.execSQL("DROP TABLE IF EXISTS" + DATABASE_TABLE);
        onCreate(db);
    }

    public void createDataBase() throws IOException
    {   
        //If database does not exist, copy from assets/

        boolean mDataBaseExist = checkDataBase();
      if(!mDataBaseExist)
       {
            this.getReadableDatabase();
            this.close();
            try {
                //Copy the database from assests
                copyDataBase();
                Log.e(TAG, "createDatabase database created");
        } 
        catch (IOException mIOException) 
        {
            throw new Error("ErrorCopyingDataBase");
        }
    }
    }

    private boolean checkDataBase()
    {
        File dbFile = new File(DB_PATH + DB_NAME);
        //Log.v("dbFile", dbFile + "   "+ dbFile.exists());
        return dbFile.exists();
    }

    //Copy the database from assets
    private void copyDataBase() throws IOException
    {
        InputStream mInput = mContext.getAssets().open(DB_NAME);
        String outFileName = DB_PATH + DB_NAME;
        OutputStream mOutput = new FileOutputStream(outFileName);
        byte[] mBuffer = new byte[1024];
        int mLength;
        while ((mLength = mInput.read(mBuffer))>0)
        {
            mOutput.write(mBuffer, 0, mLength);
        }
        mOutput.flush();
        mOutput.close();
        mInput.close();
    }


    public boolean openDataBase() throws SQLException
    {
        String mPath = DB_PATH + DB_NAME;
        //Log.v("mPath", mPath);
        mDataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.CREATE_IF_NECESSARY);
        //mDataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS);
        return mDataBase != null;
    }

    @Override
    public void close() 
    {
        if(mDataBase != null)
            mDataBase.close();
        super.close();
    }

}
nectaris
  • 85
  • 7
  • Maybe that directory is not created. Not all the apps need a DB. You could try to create it in case it does not already exists. – Mister Smith Nov 25 '13 at 16:29
  • I think we need to see the code that creates the db in order to help more on this – Thomas Nov 25 '13 at 16:52
  • Added the two DB-handling classes so that you can see exactly what's going on. But I don't think you'll find any surprises in there. – nectaris Nov 25 '13 at 18:18

1 Answers1

0

Your database isn't created until your first call to getReadableDatabase() or getWriteableDatabase(), straight from the horse's mouth:

public SQLiteDatabase getReadableDatabase()

Create and/or open a database. ...

If you want your created database to be duplicated from a prebuilt one you have in your assets folder (an idea I like since you don't have to do all your CREATE statements in SQL in Java) you'll need to first call getReadableDatabase() or getWriteableDatabase() then copy the file over. An example of that can be found in this answer.

Edit: Just saw in your edit that you're using the same code I linked to. Note that the code in the answer does not call getDatabasePath but instead tries to make the path manually since it knows it's possible it doesn't exist.

getDatabasePath is throwing a NPE because as it says in its description it returns the absolute path on the filesystem where a database created. Your file isn't created yet!

Community
  • 1
  • 1
Kasra Rahjerdi
  • 2,483
  • 26
  • 42