国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

OnSharedPreferenceChangeListener詳解及出現不觸發解決辦法

2019-12-12 05:27:43
字體:
來源:轉載
供稿:網友

之前使用OnSharedPreferenceChangeListener,遇到了點小問題,就是有些時候OnSharedPreferenceChangeListener沒有被觸發。最近花了點時間研究了一下,小做整理。本文將會介紹監聽器不被觸發的原因,解決方法,以及其中隱含的一些技術細節。

問題再現

OnSharedPreferenceChangeListener是Android中SharedPreference文件發生變化的監聽器。通常我們想要進行監聽,會實現如下的代碼。

protected void onCreate(Bundle savedInstanceState) { PreferenceManager.getDefaultSharedPreferences(getApplicationContext())  .registerOnSharedPreferenceChangeListener(new OnSharedPreferenceChangeListener() {  @Override  public void onSharedPreferenceChanged(   SharedPreferences sharedPreferences, String key) {   Log.i(LOGTAG, "testOnSharedPreferenceChangedWrong key =" + key);  } });}

這種寫法看上去沒有什么問題,而且很多時候開始幾次onSharedPreferenceChanged方法也可以被調用。但是過一段時間(簡單demo不容易出現,但是使用DDMS中的gc會立刻導致接下來的問題),你會發現前面的方法突然不再被調用,進而影響到程序的處理。

原因剖析

簡而言之,就是你注冊的監聽器被移除掉了。
首先我們先了解一下registerOnSharedPreferenceChangeListener注冊的實現。

private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners =   new WeakHashMap<OnSharedPreferenceChangeListener, Object>();//some code goes herepublic void More ...registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { synchronized(this) {  mListeners.put(listener, mContent); }}

從上面的代碼可以得知,一個OnSharedPreferenceChangeListener對象實際上是放到了一個WeakHashMap的容器中,執行完示例中的onCreate方法,這個監聽器對象很快就會成為垃圾回收的目標,由于放在WeakHashMap中作為key不會阻止垃圾回收,所以當監聽器對象被回收之后,這個監聽器也會從mListeners中移除。所以就造成了onSharedPreferenceChanged不會被調用。

關于WeakHashMap相關,請閱讀譯文:理解Java中的弱引用進而更多了解。

如何解決

改為對象成員變量(推薦)

將監聽器作為Activity的一個成員變量,在Activity的onResume進行注冊,在onPause時進行注銷。推薦在這兩個Activity生命周期中進行處理,尤其是當SharedPreference值發生變化后,對Activity展示的UI進行處理操作的情況。這種方法是最推薦的解決方案。

private OnSharedPreferenceChangeListener mListener = new OnSharedPreferenceChangeListener() { @Override public void onSharedPreferenceChanged(  SharedPreferences sharedPreferences, String key) {  Log.i(LOGTAG, "instance variable key=" + key); }};@Overrideprotected void onResume() { PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).registerOnSharedPreferenceChangeListener(mListener); super.onResume();}@Overrideprotected void onPause() { PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).unregisterOnSharedPreferenceChangeListener(mListener); super.onPause();}

改為靜態變量(不推薦)

如下,將一個指向匿名的內部類對象的變量sListener使用static修飾,這個內部類對象則不會持有外部類的引用。
但是這種做法并不推薦,因為一個靜態變量和與外部實例不相關,我們很難和外部實例進行一些操作。

private static OnSharedPreferenceChangeListener sListener = new OnSharedPreferenceChangeListener() { @Override public void onSharedPreferenceChanged(  SharedPreferences sharedPreferences, String key) {  Log.i(LOGTAG, "static variable key=" + key); }};

為什么這樣設計

可能會有人認為這是系統設計的貓膩或者bug,其實不然,這正是Android設計人員的高明之處。

正如我們示例的代碼一樣,將一個(隱式的)局部變量添加到監聽器容器中,如果該容器只是一個普通的HashMap,這樣會導致內存泄露,因為該容器還有局部變量指向的對象,該對象又隱式持有外部Activity的對象,導致Activity無法被銷毀。關于非靜態內部類持有隱式持有外部類引用,請參考細話Java:”失效”的private修飾符

除此之外,因為局部變量無法在其所在方法外部訪問,這樣就導致了我們只可以使用方法中使用局部變量就行注冊,在合適的時機卻無法使用局部變量進行注銷。

以上就是對 Android OnSharedPreferenceChangeListener的介紹,以及出現問題解決辦法,謝謝大家對本站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 准格尔旗| 农安县| 黑河市| 滕州市| 江阴市| 望江县| 丰县| 黄龙县| 白城市| 十堰市| 枝江市| 东乡族自治县| 黑龙江省| 阳谷县| 衡阳县| 汕尾市| 灵山县| 上高县| 离岛区| 正阳县| 湖州市| 西吉县| 安仁县| 财经| 梁平县| 克什克腾旗| 明光市| 弋阳县| 巫山县| 垦利县| 宾阳县| 石城县| 海丰县| 霍邱县| 台安县| 沐川县| 马龙县| 皋兰县| 鹿泉市| 宝清县| 金寨县|