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

語言: 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機制很熟悉,我不是很熟,所以使用可能也出現不對,希望讀者可以積極指正,謝謝觀看!