【问题标题】:Leaving PreferenceActivity, calling Activity still reads old preference?离开PreferenceActivity,调用Activity还是读取旧的preference?
【发布时间】:2012-04-26 06:07:53
【问题描述】:

我觉得我遗漏了一些明显的东西,但搜索让我找到了几个不同的点击,所有这些都没有直接访问我的奇怪问题。

拥有一个包含主要活动和偏好活动的应用。添加一个“偏好”类,它简化了阅读和设置偏好。主要活动有一个选项菜单可以访问偏好活动:

Preferences 类(包括相关性,如果我不使用此类读取设置,也会发生同样的事情)。

public class Preferences
{
    public static SharedPreferences getPrefs(Context context)
    {
        SharedPreferences retCont = PreferenceManager.getDefaultSharedPreferences(context);
        return retCont;
    }

    /* Map Page: Show Satellite */
    public static boolean getMapShowSatellite(Context context)
    {
        return Preferences.getPrefs(context).getBoolean(Preferences.getString(context, R.string.option_showSatellite), false);
    }

    public static void setMapShowSatellite(Context context, boolean newValue)
    {
        Editor prefsEditor = Preferences.getPrefs(context).edit();
        prefsEditor.putBoolean(Preferences.getString(context, R.string.option_showSatellite), newValue);
        prefsEditor.commit();
    }
}

PreferencesActivity:

public class AppSettings extends PreferenceActivity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        addPreferencesFromResource(R.xml.app_preferences);

        ListPreference stationType = (ListPreference)this.findPreference(this.getString(R.string.option_filterStationType));
        stationType.setOnPreferenceChangeListener(this.stationOrderEnable());
    }
[...]
}

最后两行连接了一个事件,以根据一个人的选择启用/禁用其他首选项。正如预期的那样,这有效。 简单的主要活动,以及相关功能:

public class MainMapScreen extends MapActivity
{
    private void launchSettings()
    {
        Intent prefsIntent = new Intent(this.getApplicationContext(), AppSettings.class);
        this.startActivity(prefsIntent);
    }

    @Override
    protected void onResume()
    {
        super.onResume();

        Preferences.getMapShowSatellite(); // <-- Returns previous value.
        // Re-start the MyLocation Layer from tracking.
        this._mapView.requestLayout();
    }
[...]
}

好的,接下来会发生什么,假设我们运行应用程序。在应用程序加载时,getMapShowSatellite() 返回True。进入 PreferenceActivity,然后将该选项更改为 False。通过点击返回按钮退出 PreferenceActivity。这时候调用了主Activity的onResume()。此时获取getMapShowSatellite() 将返回True 的先前设置。退出并重新启动应用程序最终将返回预期的False

我没有手动调用.commit() - 而且我认为我不需要,因为设置正在保存,我只是没有得到更新值。

我错过了什么? :) --狐狸。

编辑 2: 小更新。我认为问题可能是静态调用 - 所以我暂时将我的 Preferences 类(上图)更改为实例化类,不再是静态的。我还在主要活动中的onResume() 调用中添加了以下代码:

//Try reloading preferences?
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
String test = sp.getString(Preferences.OPTION_FILTERSTATIONTYPE, "---");
Log.e("BMMaps", test);

此时从离开 PreferenceActivity 开始记录的内容是旧设置。手动读取首选项文件显示 .xml 文件正在使用用户的新设置进行更新。

由于不明显,我迷上了 Google 的 Maps API。因此,我必须指定两个不同的进程 - 一个用于主要活动(这个),另一个用于与此问题无关的活动。所有其他活动,包括 PreferencesActivity 都没有在其定义中指定 android:process=""

编辑 3: 根据要求,这是数据首选项文件:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="com.tsqmadness.bmmaps.filterStationType">V-?</string>
    <boolean name="com.tsqmadness.bmmaps.deviceHasLocation" value="false" />
</map>

这里是首选项存储 XML 文件:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceCategory android:title="Map Options">
        <CheckBoxPreference android:key="com.tsqmadness.bmmaps.mapShowSatellite" android:order="1" android:summary="Whether or not to show satellite imagery on the map." android:summaryOff="Standard road map will be shown." android:summaryOn="Satellite imagery will be show." android:title="Show Satellite Layer?" />
        <CheckBoxPreference android:key="com.tsqmadness.bmmaps.mapShowScale" android:order="2" android:summary="Whether or not to show the distance bar on the map." android:summaryOff="The distance bar will not be shown on the map." android:summaryOn="The distance bar will be shown on the map." android:title="Show Map Scale?" />
        <CheckBoxPreference android:defaultValue="false" android:key="com.tsqmadness.bmmaps.useMetric" android:order="3" android:summary="Whether to use Metric os SI values." android:summaryOff="SI units (mi/ft) will be shown." android:summaryOn="Metric units (km/m) will be shown." android:title="Use Metric?" />
        <ListPreference android:dialogTitle="Station Load Delay" android:entries="@array/static_listDelayDisplay" android:entryValues="@array/static_listDelayValues" android:key="com.tsqmadness.bmmaps.mapBMDelay" android:negativeButtonText="Cancel" android:order="4" android:positiveButtonText="Save" android:summary="The delay after map panning before staions are loaded." android:title="Delay Before Loading" />
    </PreferenceCategory>
    <PreferenceCategory android:title="Control Station Filter">
        <ListPreference android:dialogTitle="Station Type" android:entries="@array/static_listStationTypeDisplay" android:entryValues="@array/static_listStationTypeValues" android:key="com.tsqmadness.bmmaps.filterStationType" android:negativeButtonText="Cancel" android:positiveButtonText="Save" android:summary="The station type to filter on." android:title="Station Type" android:order="1" />
        <ListPreference android:dialogTitle="Select Station Order" android:entries="@array/static_listStationHOrderDisplay" android:entryValues="@array/static_listStationHOrderValues" android:key="com.tsqmadness.bmmaps.filterStationOrder" android:negativeButtonText="Cancel" android:positiveButtonText="Save" android:summary="Station Order to filter by." android:title="Station Order" android:order="2" />
        <ListPreference android:dialogTitle="Select Station Stability" android:entries="@array/static_listStationStabilityDisplay" android:entryValues="@array/static_listStationStabilityValues" android:key="com.tsqmadness.bmmaps.filterStationStability" android:negativeButtonText="Cancel" android:positiveButtonText="Save" android:summary="Station stability to filter by." android:title="Station Stability" android:order="3" />
        <CheckBoxPreference android:key="com.tsqmadness.bmmaps.filterNonPub" android:summaryOff="Non-Publishable stations will not be shown." android:defaultValue="false" android:summaryOn="Non-Publishable stations will be shown on the map." android:order="4" android:title="Show Non-Publishable" />
    </PreferenceCategory>
    <Preference android:key="temp" android:title="Test" android:summary="Test Item">
        <intent android:targetClass="com.tsqmadness.bmmaps.activities.MainMapScreen" android:targetPackage="com.tsqmadness.bmmaps" />
    </Preference>
</PreferenceScreen>

当更改filterStationType 参数时,并在 PreferenceActivity 中点击返回按钮时,会将上面的首选项文件从V-? 更改为H-?,这是应该的。但是,从主 Activity 上的 SharedPreferences 读取值仍然会给出V-?,直到应用重新启动。啊,还有,我在 PreferenceActivity 中有一个OnPreferenceChangeListnener(),当值发生变化时会调用它。

最终编辑:显然,这是对给定活动使用命名的 android:process。 Google 地图 API 需要这样做,以允许同一应用程序中的两个单独的 MapActivity 使用不同的设置。如果将 PreferenceActivity 移动到同一个命名进程,那么上面的代码读取onResume() 中的设置会返回正确的值。

【问题讨论】:

  • 仍在查看您的代码,但这里有一个更好的代码提示:使用static final Strings 而不是字符串资源作为您的设置键。这些值不需要本地化,并且永远不应该改变。这些以及一些小的性能原因使它们成为常量的理想候选者。
  • 当您将OnPreferenceChangeListener 添加到您的showSatellite 偏好设置时,您会看到什么样的行为?
  • @Austyn - 谢谢!我是 Java 新手,所以我确信我的代码 - 从技术上讲 - 很糟糕。 :)
  • 我会考虑附加一个监听器,明天回来更新..
  • 另一个技巧,而不是使用 Preferences 类的静态方法并每次都传递您的上下文,如果您要进行多次调用,为什么不保留对 PreferenceManager 的引用到静态 Preference 方法?

标签: android sharedpreferences


【解决方案1】:

由于所有内容都已检查完毕,我的猜测是您在 PreferenceActivity 的 app_preferences.xml 文件中键入了一个拼写错误、不正确或未定义的密钥 R.string.option_showSatellite(无论该字符串是什么)。这将导致两个具有 [您不知道的] 不同名称的键,您认为它们指向相同的值。实际上,prefs 活动正在使用一个键,而您的 Preference 类正在使用另一个 - 导致两个不同的键和两个不同的值。

仔细检查您的密钥。确保您没有使用文字 "R.string.options_showSatellite" 作为 xml 文件中的键,而是使用实际的字符串。如果您想使用本地化版本,那么 @string/options_showSatellite 将适用于密钥。但是,键不需要本地化。

如果您好奇,可以通过在标准文本编辑器中打开应用程序数据目录中的首选项管理器创建的首选项文件来仔细检查。

【讨论】:

  • 以上所有的检查,奇怪。我验证了活动结束时首选项文件正在更新,谢谢!
  • @Coyttl 你能发布你的偏好文件吗?
  • 完成,上面发布了 PreferencesLayout 和存储首选项文件。
  • @Coyttl 很抱歉,我没有时间导入您的代码并对其进行测试等。但我剩下的就是告诉您完全废弃您的 Preferences 类。创建一个成员变量来为您的上下文保存对您 SharedPreferences 的引用。在 onCreate 中获取该引用。每当您需要获得偏好时,请使用该参考。仅在您的 PreferenceActivity 中编辑您的首选项。如果可以的话,删除你的回调——那些可能会变得很糟糕。看看你是否可以先简单地让它工作。然后,如果你能做到这一点,如果你愿意,可以构建你的 Preference 类。
  • @Coyttl 哦,R.string.option_filterStationType 的值是多少?
【解决方案2】:

onResume 你必须获得对 SharedPreferences 的新引用,否则你只是在使用一个已经在内存中的对象(并且有你的旧值)

编辑: 与其对你不理解的答案投反对票,为什么不要求澄清呢? 我的意思是你应该以正确的方式(而不是你如何做)拉你的首选项......

 SharedPreferences sp = getSharedPreferences(getPackageName(), MODE_PRIVATE);

然后看看会发生什么。

【讨论】:

  • 没有改变任何东西,我在设置之前尝试了PreferenceManager.getDefaultSharedPreferences(this);,但它并没有改变我得到的答案。
  • 刚接触 Java 并且不知道自己在做什么并不是对试图帮助您的人的(正确)答案投反对票的最佳理由。
  • @Dr.Dredel 我认为你有一个错字。您的意思是“试图帮助您的人的(不正确)答案”对吗? (;
  • @David,你是说我建议 OP 检索他的共享首选项的方式有问题吗?
  • @Dr.Dredel 好吧,现在没有什么不好的感觉了。让我试着解释一下。您使用SharedPreferences 的方法建议OP 在他的onResume 方法中获得对SharedPreferences 的新引用。这只需要在onCreate 方法中发生。这是因为SharedPreference 只是指向 Activity 使用的首选项文件的“指针”。此文件在同一应用程序中的活动之间共享,并且没有任何信息存储在 SharedPreference 对象本身中。但是,您确实需要重新加载您的活动可能已加载的任何首选项字段onResume
猜你喜欢
  • 2014-02-19
  • 2018-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多