0

在实现OnSharedPreferenceChangeListener接口的android服务中使用线程/任务时,首选项屏幕中所做的更改不会反映回android服务中的线程/任务对象。OnSharedPreferenceChangeListener不能在另一个线程任务中工作

我要完成两件事情:当MyTask构造和初始化

  • SharedPreference数据应被加载。

  • 当首选项更改发生时,必须使用首选项屏幕中设置的新首选项值更新MyTask对象。

问题是:偏好初始化和偏好更改不会反映到MyTask对象。

这是我的设置(仅适用于基本部分提及):

MyService.class:

public class MyService extends Sevice { 
    private MyTask myTask; 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     if (!serviceStarted) { 
      serviceStarted = true; 
      myTask = new MyTask(this); 
      Thread t = new Thread(myTask); 
      t.start(); 
     } 
     return Service.START_STICKY; 
    } 

    @Override 
    public void onDestroy() { 
     myTask.cancel(); 
     super.onDestroy(); 
    } 
} 

MyTask.class:

public MyTask implements Runnable, OnSharedPreferenceChangeListener { 
    private Context mContext; 
    private boolean mCancelled; 
    public MyTask(Context context) { 
     mContext = context; 
    } 

    @Override 
    public void run() { 
     while(!mCancelled) { 
      // do something 
     } 
    } 

    @Override 
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, 
     String key) { 
     // FIXME: DOESN'T GET CALLED after change in preference!!!! 
     Log.d(TAG, "Key= " + key); 
    } 

    public void cancel() { 
     mCancelled = true; 
    } 
} 

preference_devices.xml :

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > 
    <PreferenceCategory 
     android:key="pref_category_devices" 
     android:title="@string/pref_category_devices_title" > 
     <CheckBoxPreference 
      android:defaultValue="true" 
      android:key="pref_devices_server" 
      android:title="@string/pref_devices_server_title" /> 
    </PreferenceCategory> 
</PreferenceScreen> 

我试过将SharedPreferences侦听器对象编码为MyTask类的成员字段,并从提供的上下文中注册/取消注册侦听器,但那也不起作用。这些变化也没有工作:

MyTask.class(使用SharedPreference监听器类的字段成员):

public MyTask implements Runnable { 
    private Context mContext; 
    private boolean mCancelled; 
    private boolean mServerEnabled; 
    private SharedPreferences mPrefs; 
    private SharedPreferences.OnSharedPreferenceChangeListener 
     mPreferenceListener; 

    public MyTask(Context context) { 
     mContext = context; 
     mPrefs = mContext.getSharedPreferences("pref_category_devices", 
       Context.MODE_PRIVATE); 
     mPreferenceListener = new OnSharedPreferenceChangeListener() { 
      @Override 
      public void onSharedPreferenceChanged(
       SharedPreferences sharedPreferences, String key) { 
       // FIXME: DOESN'T GET CALLED after change in preference!!!! 
       Log.d(TAG, "Key= " + key); 
      } 
     }; 
     mPrefs.registerOnSharedPreferenceChangeListener(mPreferenceListener); 
     // set the initial value of the preference setting 
     mServerEnabled = mPrefs.getBoolean("pref_devices_server", false); 
    } 

    @Override 
    public void run() { 
     while(!mCancelled) { 
      // do something 
     } 
    } 

    public void cancel() { 
     mCancelled = true; 
    } 
} 

现在我已经达到了我的扔电脑窗外的点: (

在正确的方向的任何帮助的高度赞赏:)

编辑:在代码

mPrefs = mContext.getSharedPreferences("pref_category_devices", Context.MODE_PRIVATE); 

我认为第一个参数应该是首选项文件的首选项类别名称,如:“pref_category_devices”。这是不正确的!第一个参数必须是共享的首选项文件名。这并没有解决问题,但至少现在你知道不应该陷入这个陷阱。

===解决方案:===看到这条线之下Mr_and_Mrs_D +代码答案:

变化MyTask:

mPrefs = mContext.getSharedPreferences("pref_category_devices", 
      Context.MODE_PRIVATE); 

到:

mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext); 
mPreferenceListener = new OnSharedPreferenceChangeListener() { 
    @Override 
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 
     if (key.equals("preference_name_here")) { 
      mPrefValue = sharedPreferences.getBoolean(key, false); 
      // do something with boolean pref value 
     } 
    } 
}; 
mPrefs.registerOnSharedPreferenceChangeListener(myPreferenceListener); 

凡mPrefValue是MyTask中布尔类型的字段成员,当“preference_name_here”首选项更改时需要设置它。

+0

当onDestroy被调用时,你的服务是否被取消? –

+0

@Mr_and_Mrs_D是的,它被取消了。我在logcat日志中看到它。它逃脱了while循环。 – user504342

+0

re:你的编辑 - 我猜对了 - 但无论如何,最好使用'getDefaultSharedPreferences',除非你真的需要一个文件 –

回答

1

变化:

private volatile boolean mCancelled; //otherwise the myTask thread may never stop 

对于您的问题:

if (!serviceStarted) { 
    serviceStarted = true; 
    myTask = new MyTask(this); 
    SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); 
    sp.registerOnSharedPreferenceChangeListener(myTask); //err, you must register 
    Thread t = new Thread(myTask); t.start(); 
} 

Docs:当用户与他们互动

这些首选项将自动保存到SharedPreferences。要检索此活动中首选层次将使用的SharedPreferences实例,在与此活动相同的包中调用getDefaultSharedPreferences(android.content.Context)

[重点煤矿]

编辑:你的第二个片段可能失败,因为你得到了错误的共享首选项 - 你必须得到默认的 - 我认为这是因为失败:

SharedPreferences.onSharedPreferenceChangeListener not being called consistently

+0

为什么在if-construction中使用“SharedPreferences sp = ...”?不应该将它添加到MyTask对象中吗? – user504342

+0

如果在'onStartCommand'里面 - clear(no constructor)?现在我做的是1.检索_default_共享首选项。 2.对android说“嗨,注册这个myTask对象,我只是为了听我刚刚得到的默认偏好的更改而构建的”。然后我继续你的代码。所以你不要把sp添加到myTask中 - 你可以将myTask添加到sp的(listeners)中。你可以在myTask构造函数中作为'SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); sp.registerOnSharedPreferenceChangeListener(this);'但是最好在服务中使用 –

+0

描述它的方式意味着我无法读取更改后的pref键/值的值,一旦它被更改并触发。我需要更改MyTask对象中的设置,而不是MyService对象中的设置。这样,每个OnSharedPreferenceChangeListener实现可以为您想要添加的每个侦听器都有不同的实现(请参阅我的解决方案编辑)。 – user504342

相关问题