序
之前一直都是new對象的砖织,壓根就不知道什么引用之類的東西虏冻,直到用SharedPreference的時候貌踏,用到了OnSharedPreferenceChangeListener逃贝,被坑了一把磅轻,才了解到引用的概念赏壹,然后了解一番璧眠。初看覺得這東西好麻煩渠鸽,仔細了解一下之后才發(fā)現(xiàn)颈抚,這東西在內(nèi)存控制方面還是很重要踩衩,很實用的。
事情是這個樣子贩汉,我將一個值存到SharedPreference里面驱富,如果其他的地方改變這個值,我需要將新的值給顯示出來匹舞,一個很簡單的邏輯褐鸥,可做完之后發(fā)現(xiàn)運行的結(jié)果與實際情況并不是每次都相符的,經(jīng)過打log發(fā)現(xiàn)赐稽,居然是叫榕,額,監(jiān)聽有時候有效姊舵,有時候無效晰绎,OnSharedPreferenceChangeListener沒有被觸發(fā)。
第一次碰到這種監(jiān)聽無效的情況蠢莺,很是一臉的懵逼寒匙。
內(nèi)部的項目的代碼就不分享了,用一個demo來說明一下。
點擊Button锄弱,計數(shù)加1考蕾,將點擊數(shù)存到SharedPreference中,用OnSharedPreferenceChangeListener來監(jiān)聽SharedPreference中值的變化会宪,變化的時候?qū)⒂嫈?shù)打印出來肖卧,運行一段時間會發(fā)現(xiàn),OnSharedPreferenceChangeListener失效了掸鹅。
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private SharedPreferences spJ;
private SharedPreferences.Editor editor;
private Button buttonNum;
private int clickN;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final int initTimes=0;
clickN=initTimes;
buttonNum=(Button)findViewById(R.id.Button_Num);
spJ =getApplicationContext().getSharedPreferences("ClickN",MODE_PRIVATE);
editor= spJ.edit();
buttonNum.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
clickN++;
editor.putInt("times",clickN).commit();
}
});
spJ.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
Log.d("MainActivity", "onSharedPreferenceChanged: "+spJ.getInt("times",initTimes));
}
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.uidq0205.jtodo.MainActivity">
<Button
android:id="@+id/Button_Num"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="00"/>
</LinearLayout>
這讓人很奇怪啊塞帐,于是就往源碼里看,還好巍沙,剛一看葵姥,就看出了問題,“not currently store a strong reference to the listener”句携。繼續(xù)了解之后榔幸,發(fā)現(xiàn),原來是引用惹的禍矮嫉。
強引用
從名字也很好理解削咆,就是很強的引用咯,那么有多強呢蠢笋?即使在內(nèi)存很不夠用的時候拨齐,程序報出Out Of Memory錯誤,也不會回收強引用的對象的昨寞。這種我們在編程中用的是最廣了瞻惋,比如說new。
軟引用
軟引用编矾,顧名思義熟史,就是比較弱的一種引用,弱是相對于上一個來說的窄俏。這個還是比較講義氣的蹂匹,當內(nèi)存不夠用的時候,他會犧牲自己凹蜈,貢獻出自己的內(nèi)存限寞,避免發(fā)生Out Of Memory。當內(nèi)存足夠時仰坦,他是比較安全的履植,并不會被回收掉。
弱引用
弱引用悄晃,就是比較弱咯玫霎,弱到什么程度呢凿滤,如果一不小心,被垃圾回收機制檢測到庶近,就有可能被回收翁脆,貌似跟此時內(nèi)存夠不夠也沒有關(guān)系。
虛引用
這個鼻种,就比較奇葩了反番,因為比弱還弱,弱到什么程度呢叉钥。對對象的生命周期沒有影響罢缸,而且,無法通過弱引用得到對象投队,弱的不行不行的枫疆。它基本只有一個作用,在對象被回收的時候蛾洛,得到一個系統(tǒng)通知养铸,這一點雁芙,基本是它唯一可以被利用的一點轧膘。
這一點怎么用呢,在需要對內(nèi)存十分克制的開發(fā)中兔甘,這一點很重要谎碍,可以通過這一點來準確的判斷對象是否被回收,來決定是否申請一個新的對象來占用內(nèi)存洞焙。準確是相對通常用的finalize()方法來說的蟆淀。
finalize()被調(diào)用的時候,只是準備好釋放存儲空間澡匪,只有在下一次垃圾收集的過程中熔任,對象的內(nèi)存才會被清除掉,并不準確唁情。還有一點疑苔,存在finalize()重寫不規(guī)范的情況,如果在該方法中又創(chuàng)建了一個強引用來指向要被銷毀的對象時甸鸟,這個對象就重新復(fù)活了惦费。
而使用虛引用就不會存在這種問題,只有當對象占用的內(nèi)存空間被清除的時候抢韭,才會返回系統(tǒng)通知薪贫,這個時候,被銷毀的對象是不會被重新激活的刻恭。
咋一看瞧省,會覺得區(qū)分起來蠻麻煩的,不過當你內(nèi)存緊缺的時候就不會這么想了,哈哈鞍匾。