gpt4 book ai didi

android - 在 Android 应用程序组件之间共享数据的最佳方式

转载 作者:行者123 更新时间:2023-11-29 17:54:09 24 4
gpt4 key购买 nike

我正在开发一个包含许多组件的应用程序。
该应用程序使用 AlarmManager 从服务器进行一些轮询。还有显示数据的常规 Activity (存储在 SqliteSharedPreferences 上)

一切正常,直到我尝试添加一个功能,在设备完成启动时开始轮询(BOOT_COMPLETED),当我这样做时,我发现我无法访问SharedPreferencesContext 我从扩展 BroadcastReceiver 的类的 onReceive(Context context, Intent intent) 方法中得到>.

另一件事是,我使用 Singleton 来处理所有 SharedPreferencesDB 功能。此 Singleton 包含应用的第一个午餐 Activity (LoginActivity) 的Context。并在整个应用程序和 Polling BroadcastReciver 中使用它。

所以我理解(相信......)当设备完成启动时,我得到不同 Context(不是 LoginActivity 上下文我曾经得到),这就是问题的根源(是吗???)

在所有这些序言之后,我真正需要的是一个最佳实践方法来完成这样的任务 - 如何在 SharedPreferencesDB 上存储和获取数据 在整个应用程序中:

  1. 当用户运行时
  2. 当它通过 AlarmManager 执行后台任务时
  3. 当它通过BOOT_COMPLETED广播自动启动时

不会遇到此 Context 问题。一个例子会很棒。

编辑:这是我的代码 fragment :

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);
}
}

当然还有更多的类(class) - 我尽量带上所需的最低限度。

编辑 我在 2 处收到的异常:如果应用程序的轮询机制处于 Activity 状态(单例将 LoginActivity 作为上下文)并且我从任务管理器关闭了应用程序,则轮询停止并显示这个异常(exception):

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 上下文。这是个异常(exception):

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

最佳答案

您的问题应该与您在 BR 中收到的上下文是 ReceiverRestrictedContext 有关。 - 我打赌你会遇到异常 ReceiverCallNotAllowedException。如果你有一个异常,你总是必须发布一个异常 - 所以请发布它以便我们能够准确了解发生了什么!话虽这么说 - 你在接收器中做的太多了!

而且,拜托,拜托,拜托,简化你的代码。示例:

public void setPollingActive(boolean active) {
_sharedPref.edit().putBoolean("myapp.polling", active).commit();
(active) ? startRepeatingTimer() : cancelRepeatingTimer();
}

此外,如果您被闹钟管理器唤醒,则不需要接收器中的唤醒锁!警报管理器持有唤醒锁!如果你在你的接收器中做了很多事情,你确实需要一个 WakefulIntentService。
最后,如果你想要一个单例,那就做对吧 use an enum .您的实现是错误的 - 它不是线程安全的。

编辑:根据发布的异常,问题与上下文无关——这是一个 NPE,因为静态字段在某个时候变为空

关于android - 在 Android 应用程序组件之间共享数据的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20790720/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com