Sam Palmer
Sam Palmer

Reputation: 1725

Open DB connection from an IntentService Constructor

When trying to open up a DB connection via the normal mechanism a nullpointerexecption is thrown at the point dbhelper.getWritableDatabase.

The problem seems to stem from the IntentService context I am passing in.

    public AnalysisService() {
    super("AnalysisService");
    Log.d("ANALYSIS_SERVICE", "Service started");
    try{
    db = new DBAdapter(this)
    db.openDB();
    }catch(Exception e){
        Log.d("ANALYSIS_SERVICE", Arrays.toString(e.getStackTrace()));
        Log.e("ANALYSIS_SERVICE", e.toString());
    }
}

The db.open method is executed here:

public class DBAdapter implements Database {

protected Context context;
protected SQLiteDatabase db;
private DatabaseHelper dbHelper;

public DBAdapter(Context context) {
    this.context = context;
    Log.e("DB_ADAPTER", "CREATED");
}

/**
 * Opens a database connection.
 * @return
 * @throws SQLException
 */
@Override
public DBAdapter openDB() throws SQLException {
    dbHelper = new DatabaseHelper(context);
    db = dbHelper.getWritableDatabase(); //NULLP EXCEPTION THROWN HERE
    return this;
}

And if it helps the constructor for the dbHelper is:

    public DatabaseHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
    Log.e("DB_HELPER", "created");
}

This has been puzzling me for the last day or so I can't understand why the context is invalid. Also I have logged all the constructors and all the objects are being created correctly, so it is not the case that DBHelper is null.

As well as using the context as this, I have also tried using getBaseContext() and getApplicationContext(), both resulting in the same error.

From the debug printing the stack trace, I get:

    11-21 13:23:45.419: D/ANALYSIS_SERVICE(3930): 
[android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:221), 
android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:166), 
com.emotifi.database.DBAdapter.openDB(DBAdapter.java:42), 
com.emotifi.analysis.AnalysisService.<init>(AnalysisService.java:45),
 java.lang.Class.newInstanceImpl(Native Method), 
java.lang.Class.newInstance(Class.java:1319), 
android.app.ActivityThread.handleCreateService(ActivityThread.java:2234), 
android.app.ActivityThread.access$1600(ActivityThread.java:123), 
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1201), 
android.os.Handler.dispatchMessage(Handler.java:99), 
android.os.Looper.loop(Looper.java:137), 
android.app.ActivityThread.main(ActivityThread.java:4424), 
java.lang.reflect.Method.invokeNative(Native Method), 
java.lang.reflect.Method.invoke(Method.java:511), 
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:817), 
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:584), 
dalvik.system.NativeStart.main(Native Method)]

Upvotes: 2

Views: 2549

Answers (1)

Kavi
Kavi

Reputation: 3880

You're setting the context too early in the IntentService lifecycle.

Override onCreate and set it there:

@Override
public void onCreate() {
    super.onCreate();
    Log.d("ANALYSIS_SERVICE", "Service started");
    db = DatabaseFactory.getDefault(this);
}

Then open the database connection in onHandleIntent:

@Override
protected void onHandleIntent(Intent intent) {
    // Logging
    Log.d("ANALYSIS_SERVICE", "Intent handled");

    try {
        db.openDB();
    } catch (Exception e) {
        Log.d("ANALYSIS_SERVICE", "Unable to open database");
        e.printStackTrace();
    }
}

Upvotes: 7

Related Questions