安卓開發基礎——弱引用的使用

語言: CN / TW / HK

theme: devui-blue highlight: atelier-lakeside-dark


開啟掘金成長之旅!這是我參與「掘金日新計劃 · 2 月更文挑戰」的第 7 天,點選檢視活動詳情

前言

起因

今天開發遇到一個問題,就是在快速點選帶點選事件的控制元件,如果控制元件裡面寫的是Dialog彈窗就有概率出現彈窗連續在介面上出現兩次,也就是你關閉彈窗後發現還有一個一樣的彈窗在介面,這樣就會帶來不好的體驗。

結果

2月9日

在網上查了許多解決方法,就有提到將該Dialog變成類的成員變數,不用每次都new就可能避免這種情況出現,但我著實不清楚為什麼以及具體怎麼做,於是請教了組裡的大哥,大哥和我說他之前也處理過這種問題,使用了弱引用,可我還是不知道具體的實現方式,於是便找到大哥的程式碼,並在網上了解了弱引用的具體作用。

2月10日

今天我請教了我們掘金開發群的Java大佬,他告訴我,我這個寫法仍然避免不了彈兩次Dialog的,並給出意見,可以使用共享狀態,推薦我建立一個共享的ReentrantLock,不過我還沒去實現,等有時間再看看。

下面就讓我們看看弱引用到底是什麼。

正篇

弱引用的概念

想知道弱引用,那就得知道幾個名詞: - 強引用 - 軟引用 - 弱引用 - 虛引用

首先我們來看看這些詞的概念: 1. 強引用

強引用(StrongReference):最傳統的“引用”的定義,是指在程式程式碼之中普遍存在的引用賦值,即類似“Object obj = new Object()”這種引用關係。無論任何情況下,只要強引用關係還存在,垃圾收集器就永遠不會回收掉被引用的物件。

  1. 軟引用

軟引用(SoftReference):在系統將要發生記憶體溢位之前,將會把這些物件列入回收範圍之中進行第二次回收。如果這次回收後還沒有足夠的記憶體,才會丟擲記憶體流出異常。

  1. 弱引用

弱引用(WeakReference):被弱引用關聯的物件只能生存到下一次垃圾收集之前。當垃圾收集器工作時,無論記憶體空間是否足夠,都會回收掉被弱引用關聯的物件。

  1. 虛引用

虛引用(PhantomReference):一個物件是否有虛引用的存在,完全不會對其生存時間構成影響,也無法通過虛引用來獲得一個物件的例項。為一個物件設定虛引用關聯的唯一目的就是能在這個物件被收集器回收時收到一個系統通知。

以上定義都是參考自知乎回答 :強引用、軟引用、弱引用、虛引用有什麼區別?具體使用場景是什麼? - 知乎 (zhihu.com),從這我們可以瞭解到其實我們Java中new物件就是強引用,強引用的物件是可觸及的,垃圾收集器就永遠不會回收掉被引用的物件,也就簡而言之物件在引用時,不回收,上面說的文章中也舉例說明了強引用的特點:

image.png

而我們本篇說的弱引用,則是發現即回收,它通常是用來描述那些非必需物件,只被弱引用關聯的物件只能生存到下一次垃圾收集發生為止。在系統GC時,只要發現弱引用,不管系統堆空間使用是否充足,都會回收掉只被弱引用關聯的物件。

但是,又因為垃圾回收器的執行緒通常優先順序很低,所以,一般並不一定能很快地發現持有弱引用的物件,而在這種情況下,弱引用物件就可以存在較長的時間。

而如何使用弱引用,我們接著往下看:

使用方法

前言提到我們使用了弱引用在開發中大哥已經使用過,所以我就跟著後面仿寫一下就好,而知乎的那篇文章也提到:

image.png

這就基本是弱引用的定義方法,因為之前前言說的Dialog問題弱引用並沒有真正起效果,所以我們換一種方法去展示他在安卓上的使用,那就是在使用Bitmap時防止OOM,寫法如下: Java ImageView imageView = findViewById(R.id.vImage); Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher_background); Drawable drawable = new BitmapDrawable(getResources(), bitmap); WeakReference<Drawable> weakDrawable = new WeakReference<>(drawable); Drawable bgDrawable = weakDrawable.get(); if(bgDrawable != null) { imageView.setBackground(drawable); } 我們再對比一下普通的強引用方法: Java ImageView imageView = findViewById(R.id.vImage); Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher_background); Drawable drawable = new BitmapDrawable(getResources(), bitmap); imageView.setBackground(drawable); 其實,就是對drawable物件從強引用轉為弱引用,這樣一旦出現記憶體不足,不會直接去使用drawable物件,讓JVM自動回收這些快取圖片物件所佔用的空間,從而有效地避免了OOM的問題。

總結

其實這塊內容需要對GC機制很熟悉,我不是很熟,所以使用可能也出現不對,希望讀者可以積極指正,謝謝觀看!