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

相關問題