从广播接收器拨打电话时出现上下文错误

Context Error when making call from Broadcast Receiver

我的应用程序检查 onResume 中的日期以查看是否需要调用 MainActivity 中名为 changeReminder 的方法。也就是说,如果日期与存储的日期不同,则调用 changeReminder(也从其他方法调用 changeReminder,例如刷新按钮)。 changeReminder 依次调用 Reminder class,它将在创建实例时创建一个新提醒。

现在,我正在向应用添加闹钟、广播接收器和通知。因为更改提醒是从 MainActivity 调用的,所以我在我的 BroadcastReceiver class 中创建了一个 activity 的实例,但是因为提醒 class 需要上下文(它有总是来自 MainActivity) 它抛出错误。在这种情况下,有没有办法从广播接收器成功传递上下文?我想我在下面包含了相关代码,但如果需要我可以添加更多...

触发警报后的日志:

05-02 13:23:00.712  15511-15511/com.mycompany.dudesmyreminders I/System.out﹕ onReceive
05-02 13:23:00.722  15511-15511/com.mycompany.dudesmyreminders I/System.out﹕ start changeReminder
05-02 13:23:00.722  15511-15511/com.mycompany.dudesmyreminders I/System.out﹕ start Reminder
05-02 13:23:00.752  15511-15511/com.mycompany.dudesmyreminders E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.mycompany.dudesmyreminders, PID: 15511
    java.lang.RuntimeException: Unable to start receiver com.mycompany.dudesmyreminders.ReminderReceiver: 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.app.ActivityThread.handleReceiver(ActivityThread.java:2726)
            at android.app.ActivityThread.access00(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1449)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:155)
            at android.app.ActivityThread.main(ActivityThread.java:5696)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
     Caused by: 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.mycompany.dudesmyreminders.dbDataSource.open(dbDataSource.java:39)
            at com.mycompany.dudesmyreminders.Reminder.<init>(Reminder.java:37)
            at com.mycompany.dudesmyreminders.MainActivity.changeReminder(MainActivity.java:283)
            at com.mycompany.dudesmyreminders.ReminderReceiver.onReceive(ReminderReceiver.java:23)
            at android.app.ActivityThread.handleReceiver(ActivityThread.java:2712)
            at android.app.ActivityThread.access00(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1449)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:155)
            at android.app.ActivityThread.main(ActivityThread.java:5696)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)

Main 中的警报管理器Activity onCreate:

//Alarm manager for notifications....
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, Calendar.getInstance().get(Calendar.HOUR_OF_DAY));
System.out.println("Hour = " + Calendar.getInstance().get(Calendar.HOUR_OF_DAY));
calendar.set(Calendar.MINUTE, Calendar.getInstance().get(Calendar.MINUTE) + 2);
System.out.println("Minute = " + Calendar.getInstance().get(Calendar.MINUTE));
calendar.set(Calendar.SECOND, 0);
Intent intent1 = new Intent(MainActivity.this, ReminderReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0,intent1, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) MainActivity.this.getSystemService(MainActivity.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);

广播接收器:

public class ReminderReceiver extends BroadcastReceiver {


    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        //throw new UnsupportedOperationException("Not yet implemented");
        System.out.println("onReceive");

        MainActivity ma = new MainActivity();
        ma.changeReminder(context);
        String message = ma.getStoredPreference("CurrentMessage");

        NewReminderNotification.notify(context,message,1);


    }
}

主菜单中的 changeReminder Activity:

public void changeReminder(Context context) {
    System.out.println("start changeReminder");

    Reminder reminder = new Reminder(this);

    // Save the message to the Shared Preferences file
    int altitude = getStoredPreferenceInt(SEEKBAR_CURRENT_INT);
    savePreference("CurrentMessage", reminder.determineReminder(altitude));
    savePreferenceInt(DBDATA_ID, (int) reminder.dbData.getId());
    //populates the reminder dbData for current session
    //DBDATA_ID is only changed in the line above
    dbDataCurrentReminder = datasource.getDB_Row_FromID(dbRTable, (long) getStoredPreferenceInt(DBDATA_ID));

    //display the message just saved
    DisplaySavedMessage();

    // save the current date to Preferences
    saveDate();
    setToggles(0);

}

提醒构造函数:

public Reminder(Context context) {
    System.out.println("start Reminder");
    ds = new dbDataSource(context);
    ds.open();
    DatabaseVersion = ds.DatabaseVersion;

}

尝试将 changeReminder(Context context) 方法块放入您的广播接收器而不是 Activity 并删除此行

MainActivity ma = new MainActivity();
ma.changeReminder(ma.getApplicationContext());

并成功

changeReminder(context); //you already have a context

另外 idk 如果你知道但是你调用 this 的任何地方你都可以调用你的 Context 除非它需要一个 Activity class 实例..这是指this 你调用了 changeReminder 也把这个方法 getStoredPreference("CurrentMessage"); 块放在你的 Receiver class 或一个单例中 class

您的代码存在一些问题。

MainActivity ma = new MainActivity();

首先,永远 自己创建一个 ActivityServiceContentProvider 的实例。这些只能由框架实例化,而不是你。这就是您的实例不起作用的原因。

其次,不要在主应用程序线程上执行磁盘 I/O 或网络 I/O,因为在 I/O 进行时您的 UI 将被冻结。在主应用程序线程上调用了 BroadcastReceiveronReceive(),而您正在尝试(徒劳地)在该线程上执行数据库 I/O。

Is there a way to successfully pass the context from the Broadcast Receiver in this case?

欢迎您将方法设为 static 方法。

但是,更好的解决方案是将此代码移动到 IntentService 中。首先,它为您提供了一个安全的、受管理的后台线程来完成这项工作。其次,它与您应该使用的 WakefulBroadcastReceiver 一起工作,以确保设备可以保持唤醒状态足够长的时间供您执行此数据库 I/O。始终将 WakefulBroadcastReceiver、我的 WakefulIntentService 或您自己的 WakeLockRTC_WAKEUPELAPSED_REALTIME_WAKEUP 警报一起使用。