一、為什么要使用DialogFragment:

創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),延吉企業(yè)網(wǎng)站建設(shè),延吉品牌網(wǎng)站建設(shè),網(wǎng)站定制,延吉網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷(xiāo),網(wǎng)絡(luò)優(yōu)化,延吉網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力。可充分滿(mǎn)足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專(zhuān)業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶(hù)成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
在程序開(kāi)發(fā)中我們經(jīng)常要做一些彈窗提醒,如果用自帶的Dialog雖然能解決一部分,但強(qiáng)大的UI是不會(huì)給你這個(gè)機(jī)會(huì)的,各種自定義UI,時(shí)間選擇器彈窗,巴拉巴拉~~~
使用DialogFragment就是能配合一些工具進(jìn)行自定義,同時(shí)官方也是比較推薦使用,極大方便了開(kāi)發(fā),比如自定義一個(gè)baseDialogFragment.
二、內(nèi)存泄漏的原因:
源碼如下:
但一般在DialogFragment的源碼默認(rèn)實(shí)現(xiàn)了對(duì)dialog的取消和結(jié)束的監(jiān)聽(tīng):
根據(jù)源碼分析,DialogFragment的dialog的變量Handler對(duì)DialogFragment持有。
網(wǎng)上有些分析是直接置為空,但是根本不能解決問(wèn)題,在super.onActivityCreated(savedInstanceState)中仍然會(huì)handler先持有DialogFragment。
最終解決方案,重寫(xiě)onActivityCreated方法,并在super.onActivityCreated(savedInstanceState),修改dialog顯示.
區(qū)別:
內(nèi)存溢出就是要求分配的內(nèi)存超出了系統(tǒng)能給的,系統(tǒng)不能滿(mǎn)足需求,于是產(chǎn)生溢出。
內(nèi)存泄漏是指向系統(tǒng)申請(qǐng)分配內(nèi)存進(jìn)行使用(new),可是使用完了以后卻不歸還(delete),結(jié)果申請(qǐng)到的那塊內(nèi)存自己也不能再訪問(wèn)(也許把它的地址給弄丟了),而系統(tǒng)也不能再次將它分配給需要的程序。
一個(gè)盤(pán)子用盡各種方法只能裝4個(gè)果子,你裝了5個(gè),結(jié)果掉倒地上不能吃了。這就是溢出!比方說(shuō)棧,棧滿(mǎn)時(shí)再做進(jìn)棧必定產(chǎn)生空間溢出,叫上溢,棧空時(shí)再做退棧也產(chǎn)生空間溢出,稱(chēng)為下溢。就是分配的內(nèi)存不足以放下數(shù)據(jù)項(xiàng)序列,稱(chēng)為內(nèi)存溢出.
定義:
1.內(nèi)存溢出 out of memory
是指程序在申請(qǐng)內(nèi)存時(shí),沒(méi)有足夠的內(nèi)存空間供其使用,出現(xiàn)out of memory;比如申請(qǐng)了一個(gè)integer,但給它存了long才能存下的數(shù),那就是內(nèi)存溢出。
2.內(nèi)存泄露 memory leak
是指程序在申請(qǐng)內(nèi)存后,無(wú)法釋放已申請(qǐng)的內(nèi)存空間,一次內(nèi)存泄露危害可以忽略,但內(nèi)存泄露堆積后果很?chē)?yán)重,無(wú)論多少內(nèi)存,遲早會(huì)被占光。
3.二者的聯(lián)系
內(nèi)存泄露最終會(huì)導(dǎo)致內(nèi)存溢出
不是成功來(lái)得太慢,只是下的功夫還不夠
最近在寫(xiě)一個(gè)關(guān)于貝塞爾曲線水波紋的小DEMO,發(fā)現(xiàn)關(guān)閉當(dāng)前視圖時(shí)報(bào)出內(nèi)存泄漏的問(wèn)題,檢查下內(nèi)存泄漏信息,經(jīng)過(guò)排查發(fā)現(xiàn)是ValueAnimator的監(jiān)聽(tīng)事件引起的,
先上解決方法:
在Activity/Fragment銷(xiāo)毀時(shí)調(diào)用如下方法:
找到問(wèn)題就好辦了,查源碼
檢查發(fā)現(xiàn)在ValueAnimator start()方法中有個(gè) addAnimationCallback(0); 調(diào)用,繼續(xù)檢查發(fā)現(xiàn)
這里就發(fā)現(xiàn)問(wèn)題了, AnimationHandler.getInstance(); 這個(gè)是單例獲取,所以在退出Activity時(shí),ValueAnimator沒(méi)有被釋放,找到問(wèn)題就好辦了,就在Activity或者Fragment被銷(xiāo)毀時(shí),主動(dòng)把動(dòng)畫(huà)監(jiān)聽(tīng)取消掉。最后上一下我Demo的效果圖 \得意
泄露信息如下:
====================================
HEAP ANALYSIS RESULT
====================================
1 APPLICATION LEAKS
References underlined with "~~~" are likely causes.
Learn more at .
Displaying only 1 leak trace out of 4 with the same signature
Signature: 645952c17f5aa992b39740a17b9afc2f3ccf5619
┬───
│ GC Root: System class
│
├─ android.os.AsyncTask class
│? ? Leaking: NO (a class is never leaking)
│? ? ↓ static AsyncTask.SERIAL_EXECUTOR
│? ? ? ? ? ? ? ? ? ? ? ~~~~~~~~~~~~~~~
├─ android.os.AsyncTask$SerialExecutor instance
│? ? Leaking: UNKNOWN
│? ? ↓ AsyncTask$SerialExecutor.mTasks
│? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ~~~~~~
├─ java.util.ArrayDeque instance
│? ? Leaking: UNKNOWN
│? ? ↓ ArrayDeque.elements
│? ? ? ? ? ? ? ? ~~~~~~~~
├─ java.lang.Object[] array
│? ? Leaking: UNKNOWN
│? ? ↓ Object[].[0]
│? ? ? ? ? ? ? ~~~
├─ android.os.AsyncTask$SerialExecutor$1 instance
│? ? Leaking: UNKNOWN
│? ? Anonymous class implementing java.lang.Runnable
│? ? ↓ AsyncTask$SerialExecutor$1.val$r
│? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ~~~~~
├─ android.widget.TextView$3 instance
│? ? Leaking: UNKNOWN
│? ? Anonymous class implementing java.lang.Runnable
│? ? ↓ TextView$3.this$0
│? ? ? ? ? ? ? ? ~~~~~~
├─ androidx.appcompat.widget.AppCompatEditText instance
│? ? Leaking: YES (View.mContext references a destroyed activity)
│? ? View not part of a window view hierarchy
│? ? View.mAttachInfo is null (view detached)
│? ? View.mID = R.id.input_edit
│? ? View.mWindowAttachCount = 1
│? ? mContext instance of RoomMainActivity with mDestroyed = true
│? ? ↓ View.mContext
╰→ RoomMainActivity instance
? ? Leaking: YES (ObjectWatcher was watching this because RoomMainActivity
? ? received Activity#onDestroy() callback and Activity#mDestroyed is true)
? ? key = cb388a5c-0ff2-452f-a9b0-6ea7d03a5105
? ? watchDurationMillis = 37631
? ? retainedDurationMillis = 32630
? ? mApplication instance of ChatApplication
? ? mBase instance of androidx.appcompat.view.ContextThemeWrapper
====================================
原因分析:
1、引用鏈結(jié)構(gòu):AsyncTask的SerialExecutor執(zhí)行器引用了EditText對(duì)象,而EditText對(duì)象中的mContext引用到了RoomMainActivity中context,導(dǎo)致RoomMainActivity 無(wú)法銷(xiāo)毀。
查看源碼得知在TextView中有updateTextServicesLocaleAsync()方法,調(diào)用了AsyncTask.execute()向其中傳入了匿名內(nèi)部類(lèi)Runnable,而持有了控件對(duì)象。
2、解決方法:因?yàn)樵谠创a層面無(wú)法修改源碼,在引用端切斷引用鏈。
給EditText使用Application的上下文,在EditText使用的頁(yè)面退出銷(xiāo)毀時(shí)移除EditText控件,包括置空它的監(jiān)聽(tīng)器、清除它的焦點(diǎn)。
import android.content.Context;
import android.os.Build;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.ViewGroup;
import androidx.appcompat.widget.AppCompatEditText;
/**
* 關(guān)于Android EditText導(dǎo)致的內(nèi)存泄漏的問(wèn)題
*/
public class NoMemoryLeakEditTextextends AppCompatEditText {
public NoMemoryLeakEditText(Context context) {
super(context.getApplicationContext());
}
public NoMemoryLeakEditText(Context context, AttributeSet attrs) {
super(context.getApplicationContext(), attrs);
}
public NoMemoryLeakEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context.getApplicationContext(), attrs, defStyleAttr);
}
public void clearMemoryLeak(TextWatcher watcher, ViewGroup container) {
clearFocus();
? ? setOnTouchListener(null);
? ? setOnClickListener(null);
? ? setOnDragListener(null);
? ? setOnKeyListener(null);
? ? setOnLongClickListener(null);
? ? setOnEditorActionListener(null);
? ? if (Build.VERSION.SDK_INT = Build.VERSION_CODES.KITKAT_WATCH) {
setOnApplyWindowInsetsListener(null);
? ? }
if (Build.VERSION.SDK_INT = Build.VERSION_CODES.M) {
setOnScrollChangeListener(null);
? ? }
setOnFocusChangeListener(null);
? ? removeTextChangedListener(watcher);
? ? container.removeView(this);
}
}
最后在頁(yè)面銷(xiāo)毀的地方調(diào)用clearMemoryLeak方法
內(nèi)存泄漏是指分配出去的內(nèi)存無(wú)法回收了
內(nèi)存泄漏指由于疏忽或錯(cuò)誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存的情況,是應(yīng)用程序分配某段內(nèi)存后,由于設(shè)計(jì)錯(cuò)誤,失去了對(duì)該段內(nèi)存的控制,因而造成了內(nèi)存的浪費(fèi)。
一般我們常說(shuō)的內(nèi)存泄漏是指堆內(nèi)存的泄漏。堆內(nèi)存是指程序從堆中分配的,大小任意的(內(nèi)存塊的大小可以在程序運(yùn)行期決定),使用完后必須顯示釋放的內(nèi)存。應(yīng)用程序一般使用malloc,realloc,new等函數(shù)從堆中分配到一塊內(nèi)存,使用完后,程序必須負(fù)責(zé)相應(yīng)的調(diào)用free或delete釋放該內(nèi)存塊,否則,這塊內(nèi)存就不能被再次使用,我們就說(shuō)這塊內(nèi)存泄漏了。
內(nèi)存溢出是指程序要求的內(nèi)存,超出了系統(tǒng)所能分配的范圍,從而發(fā)生溢出。
內(nèi)存溢是指在一個(gè)域中輸入的數(shù)據(jù)超過(guò)它的要求而且沒(méi)有對(duì)此作出處理引發(fā)的數(shù)據(jù)溢出問(wèn)題,多余的數(shù)據(jù)就可以作為指令在計(jì)算機(jī)上運(yùn)行。
依賴(lài)庫(kù)即可,重點(diǎn)在分析工具和分析方法:
debugImplementation'com.squareup.leakcanary:leakcanary-android:2.8.1'
分析工具:MAT 、AndroidStudioProfiler?和?自帶分析工具;
這里先看一下Leaking的狀態(tài)(YES、NO、UNKNOWN),NO表示沒(méi)泄露、YES表示出現(xiàn)泄漏、UNKNOW表示可能泄漏。
具體學(xué)習(xí)資料: 學(xué)習(xí)資料
首先了解下Android中最重要的四大內(nèi)存指標(biāo)的概念
我們主要使用USS和PSS來(lái)衡量進(jìn)程的內(nèi)存使用情況
dumpsys meminfo命令展示的是系統(tǒng)整體內(nèi)存情況,內(nèi)存項(xiàng)按進(jìn)程進(jìn)行分類(lèi)
查看單個(gè)進(jìn)程的內(nèi)存信息,命令如下
adb shell dumpsys meminfo [pid | packageName]
Objects中Views、Activities、AppContexts的異常可以判斷有內(nèi)存泄露,比如剛退出應(yīng)用,查看Activites是否為0,如果不為0,則有Activity沒(méi)有銷(xiāo)毀。
具體用法直接參考大佬的資源即可,不贅述。
android studio 中Memory Profile的用法
接入LeakCanary,監(jiān)控所有Activity和Fragment的釋放,App所有功能跑一遍,觀察是否有抓到內(nèi)存泄露的地方,分析引用鏈找到并解決問(wèn)題,如此反復(fù),直到LeakCanary檢查不到內(nèi)存泄露。
adb shell dumpsys meminfo命令查看退出界面后Objects的Views和Activities數(shù)目,特別是退出App后數(shù)目為否為0。
打開(kāi)Android Studio Memory Profiler,反復(fù)打開(kāi)關(guān)閉頁(yè)面多次,點(diǎn)擊GC,如果內(nèi)存沒(méi)有恢復(fù)到之前的數(shù)值,則可能發(fā)生了內(nèi)存泄露。再點(diǎn)擊Profiler的垃圾桶圖標(biāo)旁的heap dump按鈕查看當(dāng)面內(nèi)存堆棧情況,按包名找到當(dāng)前測(cè)試的Activity,如果存在多份實(shí)例,則很可能發(fā)生了內(nèi)存泄露。
分享名稱(chēng):android內(nèi)存泄漏,Android內(nèi)存泄漏的場(chǎng)景
轉(zhuǎn)載源于:http://chinadenli.net/article19/dsggsgh.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)、網(wǎng)站收錄、App開(kāi)發(fā)、微信公眾號(hào)、網(wǎng)站營(yíng)銷(xiāo)、標(biāo)簽優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)