我正在开发一个包含许多组件的应用程序。
该应用程序AlarmManager
用于从服务器进行一些轮询。还有一些常规活动显示数据(存储在Sqlite
和SharedPreferences
上)
一切都很好,直到我尝试添加一个在设备完成启动(BOOT_COMPLETED
)时开始轮询的功能,当我这样做时我发现我无法使用SharedPreferences
从Context
扩展onReceive(Context context, Intent intent)
的类的方法中获得的BroadcastReceiver
获得的访问。
另一件事是我使用 Singleton 来处理所有的SharedPreferences
和DB
功能。此 Singleton 包含应用程序Context
的第一个午餐活动( LoginActivity
)。并在整个应用程序和投票中使用它BroadcastReciver
。
所以我理解(相信......)当设备完成启动时,我会变得不同 Context
(不是LoginActivity
我以前得到的上下文),这是问题的根源(是吗???)
在所有这些序言之后,我真正需要的是针对此类任务的最佳实践方法 - 如何在整个应用程序上存储SharedPreferences
和获取数据:DB
- 当用户运行它时
- 当它通过
AlarmManager
- 当它通过
BOOT_COMPLETED
广播自动启动时
没有遇到这个Context
问题。一个例子会很棒。
编辑: 这是我的代码片段:
ConnectionManager.java
- 此类保存 REST 请求实现并将内容存储到 SharedPreferences:
public class ConnectionManager {
//There are many more variables here - irrelevant for the example
private CookieStore _cookieStore;
private static ConnectionManager _instance;
private SharedPreferences _sharedPref;
private Context _context;
private DataPollingBroadcastReceiver _dataPoller;
private ConnectionManager(Context caller) {
_context = caller;
_sharedPref = PreferenceManager.getDefaultSharedPreferences(_context);
}
public static ConnectionManager getInstance(Context caller) {
if (_instance == null) {
_instance = new ConnectionManager(caller);
}
return _instance;
}
public void setPollingActive(boolean active) {
if (active) {
SharedPreferences.Editor editor = _sharedPref.edit();
editor.putString("myapp.polling", "true");
editor.commit();
startRepeatingTimer();
} else {
SharedPreferences.Editor editor = _sharedPref.edit();
editor.putString("myapp.polling", "false");
editor.commit();
cancelRepeatingTimer();
}
}
private void startRepeatingTimer() {
if (_dataPoller!= null) {
_dataPoller.SetAlarm(_context);
} else {
Toast.makeText(_context, "_dataPoller object is null",
Toast.LENGTH_SHORT).show();
}
}
private void cancelRepeatingTimer() {
if (_dataPoller!= null) {
_dataPoller.CancelAlarm(_context);
} else {
Toast.makeText(_context, "_dataPoller object is null",
Toast.LENGTH_SHORT).show();
}
}
//There are many more methods here - irrelevant for the example
}
MainBootListener.java
:这个类假设激活轮询机制 - 它不起作用,因为 ConnectionManager 上有异常。
public class MainBootListener extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Activated by boot event",
Toast.LENGTH_LONG).show();
ConnectionManager cm = ConnectionManager.getInstance(context);
cm.setPollingActive(true);
}
}
DataPollingBroadcastReceiver.java
: 这个类从服务器轮询数据
public class DataPollingBroadcastReceiver extends BroadcastReceiver {
private ConnectionManager _mngr;
@Override
public void onReceive(Context context, Intent intent) {
if (_mngr == null) {
_mngr = ConnectionManager.getInstance(context);
}
PowerManager pm = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, TAG);
// Acquire the lock
wl.acquire();
// You can do the processing here update the widget/remote views.
Bundle extras = intent.getExtras();
StringBuilder msgStr = new StringBuilder();
Format formatter = new SimpleDateFormat("hh:mm:ss");
msgStr.append(formatter.format(new Date()));
// /////
_mngr.updateDataFromServer();
msgStr.append(" [Updated AccessControlTable]");
Log.i(TAG, msgStr.toString());
Toast.makeText(context, msgStr, Toast.LENGTH_SHORT).show();
// ////
// Release the lock
wl.release();
}
public void SetAlarm(Context context) {
if (_mngr == null) {
_mngr = ConnectionManager.getInstance(context);
}
AlarmManager am = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, DataPollingBroadcastReceiver.class);
intent.putExtra(ONE_TIME, Boolean.TRUE);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
1000 * _mngr.getPollingIntervalInSeconds(), pi);
}
public void CancelAlarm(Context context) {
if (_mngr == null) {
_mngr = ConnectionManager.getInstance(context);
}
Intent intent = new Intent(context, DataPollingBroadcastReceiver.class);
PendingIntent sender = PendingIntent
.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
}
当然还有更多的课程——我尽量带上最低要求。
编辑我收到的异常2:如果轮询机制在应用程序中处于活动状态(单例将 LoginActivity 作为上下文)并且我从任务管理器关闭了应用程序,则轮询停止并显示此异常:
12-29 14:02:03.061: E/AndroidRuntime(9402): FATAL EXCEPTION: main
12-29 14:02:03.061: E/AndroidRuntime(9402): java.lang.RuntimeException: Unable to start receiver my.app.DataPollingBroadcastReceiver : java.lang.NullPointerException
12-29 14:02:03.061: E/AndroidRuntime(9402): at android.app.ActivityThread.handleReceiver(ActivityThread.java:2277)
12-29 14:02:03.061: E/AndroidRuntime(9402): at android.app.ActivityThread.access$1500(ActivityThread.java:140)
12-29 14:02:03.061: E/AndroidRuntime(9402): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
12-29 14:02:03.061: E/AndroidRuntime(9402): at android.os.Handler.dispatchMessage(Handler.java:99)
12-29 14:02:03.061: E/AndroidRuntime(9402): at android.os.Looper.loop(Looper.java:137)
12-29 14:02:03.061: E/AndroidRuntime(9402): at android.app.ActivityThread.main(ActivityThread.java:4898)
12-29 14:02:03.061: E/AndroidRuntime(9402): at java.lang.reflect.Method.invokeNative(Native Method)
12-29 14:02:03.061: E/AndroidRuntime(9402): at java.lang.reflect.Method.invoke(Method.java:511)
12-29 14:02:03.061: E/AndroidRuntime(9402): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1006)
12-29 14:02:03.061: E/AndroidRuntime(9402): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
12-29 14:02:03.061: E/AndroidRuntime(9402): at dalvik.system.NativeStart.main(Native Method)
12-29 14:02:03.061: E/AndroidRuntime(9402): Caused by: java.lang.NullPointerException
12-29 14:02:03.061: E/AndroidRuntime(9402): at my.app.ConnectionManager.<init>(ConnectionManager.java:172)
12-29 14:02:03.061: E/AndroidRuntime(9402): at my.app.ConnectionManager.getInstance(ConnectionManager.java:196)
12-29 14:02:03.061: E/AndroidRuntime(9402): at my.app.DataPollingBroadcastReceiver .onReceive(DataPollingBroadcastReceiver .java:27)
12-29 14:02:03.061: E/AndroidRuntime(9402): at android.app.ActivityThread.handleReceiver(ActivityThread.java:2270)
12-29 14:02:03.061: E/AndroidRuntime(9402): ... 10 more
当应用程序未运行并且我从 adb 发送 BOOT_COMPLETED 时发生了第二个异常,而不是单音尝试初始化。使用 BroadcastReciver 上下文。这是个例外:
12-26 11:54:58.556: E/AndroidRuntime(12373): FATAL EXCEPTION: main
12-26 11:54:58.556: E/AndroidRuntime(12373): java.lang.RuntimeException: Unable to start receiver my.app.MainBootListener : java.lang.NullPointerException
12-26 11:54:58.556: E/AndroidRuntime(12373): at android.app.ActivityThread.handleReceiver(ActivityThread.java:2277)
12-26 11:54:58.556: E/AndroidRuntime(12373): at android.app.ActivityThread.access$1500(ActivityThread.java:140)
12-26 11:54:58.556: E/AndroidRuntime(12373): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
12-26 11:54:58.556: E/AndroidRuntime(12373): at android.os.Handler.dispatchMessage(Handler.java:99)
12-26 11:54:58.556: E/AndroidRuntime(12373): at android.os.Looper.loop(Looper.java:137)
12-26 11:54:58.556: E/AndroidRuntime(12373): at android.app.ActivityThread.main(ActivityThread.java:4898)
12-26 11:54:58.556: E/AndroidRuntime(12373): at java.lang.reflect.Method.invokeNative(Native Method)
12-26 11:54:58.556: E/AndroidRuntime(12373): at java.lang.reflect.Method.invoke(Method.java:511)
12-26 11:54:58.556: E/AndroidRuntime(12373): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1006)
12-26 11:54:58.556: E/AndroidRuntime(12373): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
12-26 11:54:58.556: E/AndroidRuntime(12373): at dalvik.system.NativeStart.main(Native Method)
12-26 11:54:58.556: E/AndroidRuntime(12373): Caused by: java.lang.NullPointerException
12-26 11:54:58.556: E/AndroidRuntime(12373): at my.app.ConnectionManager.<init>(ConnectionManager.java:172)
12-26 11:54:58.556: E/AndroidRuntime(12373): at my.app.ConnectionManager.getInstance(ConnectionManager.java:196)
12-26 11:54:58.556: E/AndroidRuntime(12373): at my.app.MainBootListener .onReceive(MainBootListener .java:14)
12-26 11:54:58.556: E/AndroidRuntime(12373): at android.app.ActivityThread.handleReceiver(ActivityThread.java:2270)
12-26 11:54:58.556: E/AndroidRuntime(12373): ... 10 more