我有一个WakefulBroadcastReceiver,用于捕获Google Cloud Messages并启动IntentService来处理传入的消息。在IntentService中,我需要访问单例SQLite数据库。通常,我使用getApplicationContext()从Activity打开数据库,但是当从IntentService打开时,它会抛出错误并提供NPE。如果应用程序已经长时间背景化,当消息到达并且目标服务需要访问数据库时,它会崩溃。如果该应用程序刚刚被后台化,则可以访问该数据库 一切正常。
我的问题是:
我应该传递什么上下文以确保数据库正确打开?由于IntentService是Context的子类,我尝试传入'this',传入BaseContext()甚至ApplicationContext()。
@Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
Log.i("Receiver", "Getting Data: "+intent.toString());
setResultCode(Activity.RESULT_OK);
}
public class GcmIntentService extends IntentService {
public static final String TAG = "GcmIntentService";
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
private static triDbAdapter mDbHelper;
private final static String GAME_ID = "game_id=";
private static OnActiveGameNotifyListener listener = null;
private static int currentUserId;
private static String currentUserName;
public GcmIntentService() {
super("GcmIntentService");
mDbHelper = new triDbAdapter(this.getBaseContext());
mDbHelper.open(); // <-- Fails here
// depending on what the Intent contains, I need to send notifications that include
// various items from thte database when the notification is created. I need to know
// the opponent's name, the score, etc. so the notification can say "Joe scored..."
currentUserId = mDbHelper.getUserId();
currentUserName = mDbHelper.getName();
}
@Override
protected void onHandleIntent(Intent intent) {
<snip>
}
public static class DatabaseHelper extends SQLiteOpenHelper {
private static DatabaseHelper mInstance = null;
public static DatabaseHelper getInstance(Context ctx) {
// Use the application context, which will ensure that you
// don't accidentally leak an Activity's context.
// See this article for more information: http://bit.ly/6LRzfx
if (mInstance == null) {
mInstance = new DatabaseHelper(ctx.getApplicationContext()); // <-- fail here
}
return mInstance;
}
/**
* Constructor should be private to prevent direct instantiation.
* make call to static factory method "getInstance()" instead.
*/
private DatabaseHelper(Context ctx) {
super(ctx, DATABASE_NAME, null, DATABASE_VERSION);
}
/**
* Constructor - takes the context to allow the database to be
* opened/created
*
* @param ctx the Context within which to work
*/
public triDbAdapter(Context ctx) {
this.mCtx = ctx;
}
public triDbAdapter open() throws SQLException {
mDbHelper = DatabaseHelper.getInstance(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
12-17 12:26:28.254 6888-6888/com.ulsanonline.triominoes I/Receiver﹕ Getting Data: Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x10 pkg=com.ulsanonline.triominoes cmp=com.ulsanonline.triominoes/.GcmIntentService (has extras) }
12-17 12:26:28.264 6888-6888/com.ulsanonline.triominoes E/GcmIntentService﹕ STACKTRACE: java.lang.NullPointerException: Attempt to invoke virtual method 'android.database.sqlite.SQLiteDatabase android.content.Context.openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase$CursorFactory, android.database.DatabaseErrorHandler)' on a null object reference
at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:267)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
at com.ulsanonline.triominoes.triDbAdapter.open(triDbAdapter.java:430)
at com.ulsanonline.triominoes.GcmIntentService.<init>(GcmIntentService.java:57)
at java.lang.reflect.Constructor.newInstance(Native Method)
at java.lang.Class.newInstance(Class.java:1572)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2713)
at android.app.ActivityThread.access$1800(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1361)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)