1油挥、Activity相關(guān):
1敏释、Activity的生命周期
2癣疟、Activity的啟動(dòng)模式以及使用場(chǎng)景
啟動(dòng)模式
- standard:默認(rèn)的啟動(dòng)模式,每次創(chuàng)建都會(huì)產(chǎn)生新的實(shí)例惕虑,誰啟動(dòng)了該模式的Activity坟冲,該Activity就屬于啟動(dòng)它的Activity的任務(wù)棧中
- singleTop:棧頂復(fù)用模式,如果新的activity已經(jīng)位于棧頂溃蔫,那么這個(gè)Activity不會(huì)被重寫創(chuàng)建樱衷,同時(shí)它的onNewIntent(Intent intent)方法會(huì)被調(diào)用,通過此方法的參數(shù)我們可以去除當(dāng)前請(qǐng)求的信息酒唉,該 Activity的實(shí)例不在該椌毓穑或者不在棧頂 時(shí),其行為同standard啟動(dòng)模式
- singleTask:棧內(nèi)復(fù)用模式痪伦,如果棧中存在這個(gè)Activity的實(shí)例就會(huì)復(fù)用這個(gè)Activity侄榴,不管它是否位于棧頂,復(fù)用時(shí)网沾,會(huì)將它上面的Activity全部出棧癞蚕,并且會(huì)回調(diào)該實(shí)例的onNewIntent方法。
- singleInstance:全局唯一模式辉哥,具備singleTask模式的所有特性外桦山,與它的區(qū)別就是,這種模式下的Activity會(huì)單獨(dú)占用一個(gè)Task棧醋旦,具有全局唯一性恒水,即整個(gè)系統(tǒng)中就這么一個(gè)實(shí)例,由于棧內(nèi)復(fù)用的特性饲齐,后續(xù)的請(qǐng)求均不會(huì)創(chuàng)建新的Activity實(shí)例钉凌,除非這個(gè)特殊的任務(wù)棧被銷毀了,當(dāng)復(fù)用該實(shí)例 會(huì)回調(diào)onNewIntent方法
3捂人、Activity的啟動(dòng)過程(不要回答生命周期)
Activity的啟動(dòng)過程
必須掌握的Activity啟動(dòng)過程
4御雕、在Activity中如何保存/恢復(fù)狀態(tài)矢沿?
分別調(diào)用onSaveInstanceState和onRestoreInstanceState 2個(gè)方法保存和恢復(fù)狀態(tài)。
5酸纲、在Activity中如何保存/恢復(fù)狀態(tài)捣鲸?
- 不設(shè)置Activity的android:configChanges時(shí),切屏?xí)匦抡{(diào)用各個(gè)生命周期闽坡,切橫屏?xí)r會(huì)執(zhí)行一次巍举,切豎屏?xí)r會(huì)執(zhí)行兩次裸卫;
- 設(shè)置Activity的android:configChanges="orientation"時(shí),切屏還是會(huì)重新調(diào)用各個(gè)生命周期,切橫泽台、豎屏?xí)r只會(huì)執(zhí)行一次氮凝;
- 設(shè)置Activity的android:configChanges="orientation|keyboardHidden"時(shí)们豌,切屏不會(huì)重新調(diào)用各個(gè)生命周期树碱,只會(huì)執(zhí)行onConfigurationChanged方法;
2次泽、Service相關(guān)
1穿仪、Service的兩種啟動(dòng)方式
1. Service的startService(Intent)啟動(dòng)方式
- 使用這種start方式啟動(dòng)的Service的生命周期如下: onCreate()--->onStartCommand()(onStart()方法已過時(shí)) ---> onDestory()
- 如果服務(wù)已經(jīng)開啟,不會(huì)重復(fù)的執(zhí)行onCreate()意荤, 而是會(huì)調(diào)用onStart()和onStartCommand()
- 服務(wù)停止的時(shí)候調(diào)用 onDestory()啊片。服務(wù)只會(huì)被停止一次。
- 特點(diǎn):一旦服務(wù)開啟跟調(diào)用者(開啟者)就沒有任何關(guān)系了玖像。
開啟者退出了紫谷,開啟者掛了,服務(wù)還在后臺(tái)長(zhǎng)期的運(yùn)行捐寥。
開啟者不能調(diào)用服務(wù)里面的方法笤昨。
2. 采用bind的方式開啟服務(wù)
- 使用這種start方式啟動(dòng)的Service的生命周期如下:onCreate() --->onBind()--->onunbind()--->onDestory()
- bind的方式開啟服務(wù),綁定服務(wù)握恳,調(diào)用者掛了瞒窒,服務(wù)也會(huì)跟著掛掉。
綁定者可以調(diào)用服務(wù)里面的方法
3乡洼、Broadcast相關(guān)
1崇裁、Broadcast注冊(cè)方式與區(qū)別
- Manifest.xml中靜態(tài)注冊(cè):
//new出上邊定義好的BroadcastReceiver
MyBroadCastReceiver yBroadCastReceiver = new MyBroadCastReceiver();
//實(shí)例化過濾器并設(shè)置要過濾的廣播
IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
//注冊(cè)廣播
myContext.registerReceiver(smsBroadCastReceiver,intentFilter,
"android.permission.RECEIVE_SMS", null);
- 代碼中動(dòng)態(tài)注冊(cè):
直接在Manifest.xml文件的<application>節(jié)點(diǎn)中配置廣播接收者
<receiver android:name=".MyBroadCastReceiver">
<!-- android:priority屬性是設(shè)置此接收者的優(yōu)先級(jí)(從-1000到1000) -->
<intent-filter android:priority="20">
<actionandroid:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
2、兩種注冊(cè)廣播的不同
- 第一種不是常駐型廣播束昵,也就是說廣播跟隨程序的生命周期拔稳。
- 第二種是常駐型,也就是說當(dāng)應(yīng)用程序關(guān)閉后妻怎,如果有信息廣播來壳炎,程序也會(huì)被系統(tǒng)調(diào)用自動(dòng)運(yùn)行。
3逼侦、發(fā)送廣播的兩種方式
- 無序廣播:所有的接收者都會(huì)接收事件匿辩,不可以被攔截,不可以被修改榛丢。
- 有序廣播:按照優(yōu)先級(jí)铲球,一級(jí)一級(jí)的向下傳遞,接收者可以修改廣播數(shù)據(jù)晰赞,也可以終止廣播事件稼病。
Android 兩種注冊(cè)、發(fā)送廣播的區(qū)別
補(bǔ)1掖鱼、ContentProvider相關(guān):
ContentProvider的基本使用方法和作用然走。ContentValue的使用方法,他和HashMap的區(qū)別是什么戏挡?
ContentProvider 是Android系統(tǒng)中提供的專門用戶不同應(yīng)用間進(jìn)行數(shù)據(jù)共享的組件芍瑞,提供了一套標(biāo)準(zhǔn)的接口用來獲取以及操作數(shù)據(jù),準(zhǔn)許開發(fā)者把自己的應(yīng)用數(shù)據(jù)根據(jù)需求開放給其他應(yīng)用進(jìn)行增刪改查褐墅,而無須擔(dān)心直接開放數(shù)據(jù)庫權(quán)限而帶來的安全問題拆檬。
ContentValue: 存儲(chǔ)數(shù)據(jù)封裝的HashMap,提供 put、get等方法
4妥凳、網(wǎng)絡(luò)相關(guān)
1竟贯、HttpClient與HttpUrlConnection的區(qū)別 2
- 功能上:
- Http Client:適用于web瀏覽器,擁有大量靈活的API逝钥,提供了很多工具屑那,封裝了http的請(qǐng)求頭,參數(shù)艘款,內(nèi)容體齐莲,響應(yīng),還有一些高級(jí)功能磷箕,代理选酗、COOKIE、鑒權(quán)岳枷、壓縮芒填、連接池的處理正因此,在不破壞兼容性的前提下空繁,其龐大的API也使人難以改進(jìn)殿衰。
- HttpURLConnection: 對(duì)于大部分功能都進(jìn)行了包裝,Http Client的高級(jí)功能代碼會(huì)較復(fù)雜盛泡,
2.性能上:
- HttpURLConnection直接支持GZIP壓縮闷祥,默認(rèn)添加"Accept-Encoding: gzip"頭字段到請(qǐng)求中,并處理相應(yīng)的回應(yīng),
- 而Http Client雖然支持凯砍,但需要自己寫代碼處理箱硕。
3.選用:
- Volley里用的哪種請(qǐng)求方式(2.3前HttpClient,2.3后HttpUrlConnection)
2悟衩、HTTPS和HTTP的區(qū)別 2
1剧罩、什么是 HTTPS
HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全為目標(biāo)的HTTP通道座泳,簡(jiǎn)單講是HTTP的安全版惠昔。
即HTTP下加入SSL (Secure Socket Layer)層,HTTPS的安全基礎(chǔ)是SSL挑势,因此加密的詳細(xì)內(nèi)容就需要SSL镇防。
2、HTTPS 和 HTTP 的區(qū)別
- https 用的 443 端口潮饱, http 用的 80 端口
- https協(xié)議需要到ca申請(qǐng)證書来氧,一般免費(fèi)證書很少,需要交費(fèi)饼齿。
- http是超文本傳輸協(xié)議饲漾,信息是明文傳輸,https 則是具有安全性的ssl加密傳輸協(xié)議缕溉。
- http和https使用的是完全不同的連接方式考传,用的端口也不一樣,前者是80证鸥,后者是443僚楞。
- http的連接很簡(jiǎn)單,是無狀態(tài)的枉层;HTTPS協(xié)議是由SSL+HTTP協(xié)議構(gòu)建的可進(jìn)行加密傳輸泉褐、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議,比http協(xié)議安全鸟蜡。
Android使用OkHttp請(qǐng)求自簽名的https網(wǎng)站
Android Https相關(guān)完全解析 當(dāng)OkHttp遇到Https
HTTPS和HTTP的區(qū)別
5膜赃、View相關(guān)
1、view的Touch事件傳遞機(jī)制
1揉忘、和touch相關(guān)的三個(gè)方法
- public boolean dispatchTouchEvent(MotionEvent ev); //用來分派event
- public boolean onInterceptTouchEvent(MotionEvent ev); //用來攔截event
- public boolean onTouchEvent(MotionEvent ev); //用來處理event
方 法 | 解析 |
---|---|
dispatchTouchEvent() | 用來分派事件跳座。其中調(diào)用了onInterceptTouchEvent()和onTouchEvent(),一般不重寫該方法泣矛,返回true則表示該事件被消費(fèi) |
onInterceptTouchEvent() | 用來攔截事件疲眷。ViewGroup類中的源碼實(shí)現(xiàn)就是{return false;}表示不攔截該事件,事件將向下傳遞(傳遞給其子View)您朽;若手動(dòng)重寫該方法狂丝,使其返回true則表示攔截,事件將終止向下傳遞,事件由當(dāng)前ViewGroup類來處理几颜,就是調(diào)用該類的onTouchEvent()方法 |
onTouchEvent() | 用來處理事件倍试。返回true則表示該View能處理該事件,事件將終止向上傳遞(傳遞給其父View)菠剩;返回false表示不能處理易猫,則把事件傳遞給其父View的onTouchEvent()方法來處理 |
Android中的dispatchTouchEvent()耻煤、onInterceptTouchEvent()和onTouchEvent()
6具壮、動(dòng)畫相關(guān)
1、Android中有幾種動(dòng)畫哈蝇?
Android3.0之前有2種棺妓,3.0后有3種。
- FrameAnimation(逐幀動(dòng)畫):將多張圖片組合起來進(jìn)行播放炮赦,類似于早期電影的工作原理怜跑,很多App的loading是采用這種方式。
- TweenAnimation(補(bǔ)間動(dòng)畫):是對(duì)某個(gè)View進(jìn)行一系列的動(dòng)畫的操作吠勘,包括淡入淡出(AlphaAnimation)性芬,縮放(ScaleAnimation),平移(TranslateAnimation)剧防,旋轉(zhuǎn)(RotateAnimation)四種模式植锉。
- PropertyAnimation(屬性動(dòng)畫):屬性動(dòng)畫不再僅僅是一種視覺效果了,而是一種不斷地對(duì)值進(jìn)行操作的機(jī)制峭拘,并將值賦到指定對(duì)象的指定屬性上俊庇,可以是任意對(duì)象的任意屬性。
注1:AnimationSet 繼承自Animation鸡挠,是上面四種的組合容器管理類辉饱,沒有自己特有的屬性,他的屬性繼承自Animation拣展,所以特別注意彭沼,當(dāng)我們對(duì)set標(biāo)簽使用Animation的屬性時(shí)會(huì)對(duì)該標(biāo)簽下的所有子控件都產(chǎn)生影響。
注2:補(bǔ)間動(dòng)畫執(zhí)行之后并未改變View的真實(shí)布局屬性值备埃。切記這一點(diǎn)姓惑,譬如我們?cè)贏ctivity中有一個(gè)Button在屏幕上方,我們?cè)O(shè)置了平移動(dòng)畫移動(dòng)到屏幕下方然后保持動(dòng)畫最后執(zhí)行狀態(tài)呆在屏幕下方瓜喇,這時(shí)如果點(diǎn)擊屏幕下方動(dòng)畫執(zhí)行之后的Button是沒有任何反應(yīng)的挺益,而點(diǎn)擊原來屏幕上方?jīng)]有Button的地方卻響應(yīng)的是點(diǎn)擊Button的事件。
2乘寒、屬性動(dòng)畫
- ObjectAnimator:繼承自ValueAnimator望众,允許你指定要進(jìn)行動(dòng)畫的對(duì)象以及該對(duì)象的一個(gè)屬性。
- 大多數(shù)的情況使用ObjectAnimator就足夠了,因?yàn)樗沟媚繕?biāo)對(duì)象動(dòng)畫值的處理過程變得足夠簡(jiǎn)單烂翰,不用像ValueAnimator那樣自己寫動(dòng)畫更新的邏輯
- ObjectAnimator的動(dòng)畫原理是不停的調(diào)用setXXX方法更新屬性值夯缺,所有使用ObjectAnimator更新屬性時(shí)的前提是Object必須聲明有g(shù)etXXX和setXXX方法。
ObjectAnimator mObjectAnimator= ObjectAnimator.ofInt(view, "customerDefineAnyThingName", 0, 1).setDuration(2000);
mObjectAnimator.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
//int value = animation.getAnimatedValue(); 可以獲取當(dāng)前屬性值
//view.postInvalidate(); 可以主動(dòng)刷新
//view.setXXX(value);
//view.setXXX(value);
//......可以批量修改屬性
}
});
ObjectAnimator.ofFloat(view, "rotationY", 0.0f, 360.0f).setDuration(1000).start();
- PropertyValuesHolder:多屬性動(dòng)畫同時(shí)工作管理類甘耿。有時(shí)候我們需要同時(shí)修改多個(gè)屬性踊兜,那就可以用到此類
PropertyValuesHolder a1 = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);
PropertyValuesHolder a2 = PropertyValuesHolder.ofFloat("translationY", 0, viewWidth);
......
ObjectAnimator.ofPropertyValuesHolder(view, a1, a2, ......).setDuration(1000).start();
- ValueAnimator:屬性動(dòng)畫中的時(shí)間驅(qū)動(dòng),管理著動(dòng)畫時(shí)間的開始佳恬、結(jié)束屬性值捏境,相應(yīng)時(shí)間屬性值計(jì)算方法等。包含所有計(jì)算動(dòng)畫值的核心函數(shù)以及每一個(gè)動(dòng)畫時(shí)間節(jié)點(diǎn)上的信息毁葱、一個(gè)動(dòng)畫是否重復(fù)垫言、是否監(jiān)聽更新事件等,并且還可以設(shè)置自定義的計(jì)算類型倾剿。
ValueAnimator animator = ValueAnimator.ofFloat(0, mContentHeight); //定義動(dòng)畫
animator.setTarget(view); //設(shè)置作用目標(biāo)
animator.setDuration(5000).start();
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation){
float value = (float) animation.getAnimatedValue();
view.setXXX(value); //必須通過這里設(shè)置屬性值才有效
view.mXXX = value; //不需要setXXX屬性方法
}
});
特別注意:ValueAnimator只是動(dòng)畫計(jì)算管理驅(qū)動(dòng)筷频,設(shè)置了作用目標(biāo),但沒有設(shè)置屬性前痘,需要通過updateListener里設(shè)置屬性才會(huì)生效凛捏。
- AnimationSet:動(dòng)畫集合,提供把多個(gè)動(dòng)畫組合成一個(gè)組合的機(jī)制芹缔,并可設(shè)置動(dòng)畫的時(shí)序關(guān)系坯癣,如同時(shí)播放、順序播放或延遲播放乖菱。具體使用方法比較簡(jiǎn)單坡锡,如下:
Android應(yīng)用開發(fā)之所有動(dòng)畫使用詳解
7、Android中跨進(jìn)程通訊
android系統(tǒng)中應(yīng)用程序之間不能共享內(nèi)存窒所。
因此鹉勒,在不同應(yīng)用程序之間交互數(shù)據(jù)(跨進(jìn)程通訊)就稍微麻煩一些
- 1、訪問其他應(yīng)用程序的Activity
如調(diào)用系統(tǒng)通話應(yīng)用
Intent callIntent=new Intent(Intent.ACTION_CALL,Uri.parse("tel:12345678");
startActivity(callIntent);
- 2吵取、Content Provider
Content Provider提供了一種在多個(gè)應(yīng)用程序之間數(shù)據(jù)共享的方式(跨進(jìn)程共享數(shù)據(jù))禽额。應(yīng)用程序可以利用Content Provider完成下面的工作
- 查詢數(shù)據(jù)
- 修改數(shù)據(jù)
- 添加數(shù)據(jù)
- 刪除數(shù)據(jù)
雖然Content Provider也可以在同一個(gè)應(yīng)用程序中被訪問,但這么做并沒有什么意義皮官。Content Provider存在的目的向其他應(yīng)用程序共享數(shù)據(jù)和允許其他應(yīng)用程序?qū)?shù)據(jù)進(jìn)行增脯倒、刪、改操作捺氢。
Android系統(tǒng)本身提供了很多Content Provider藻丢,例如,音頻摄乒、視頻悠反、聯(lián)系人信息等等残黑。我們可以通過這些Content Provider獲得相關(guān)信息的列表。這些列表數(shù)據(jù)將以Cursor對(duì)象返回斋否。因此梨水,從Content Provider返回的數(shù)據(jù)是二維表的形式。
如訪問系統(tǒng)相冊(cè)
- 3茵臭、廣播(Broadcast)
廣播是一種被動(dòng)跨進(jìn)程通訊的方式疫诽。當(dāng)某個(gè)程序向系統(tǒng)發(fā)送廣播時(shí),其他的應(yīng)用程序只能被動(dòng)地接收廣播數(shù)據(jù)旦委。這就象電臺(tái)進(jìn)行廣播一樣奇徒,聽眾只能被動(dòng)地收聽,而不能主動(dòng)與電臺(tái)進(jìn)行溝通社证。例如獲取手機(jī)電量信息
- 4逼龟、AIDL服務(wù)
2评凝、AIDL理解
1追葡、定義:Android系統(tǒng)中的進(jìn)程之間不能共享內(nèi)存,因此奕短,需要提供一些機(jī)制在不同進(jìn)程之間進(jìn)行數(shù)據(jù)通信宜肉。
為了使其他的應(yīng)用程序也可以訪問本應(yīng)用程序提供的服務(wù),Android系統(tǒng)采用了遠(yuǎn)程過程調(diào)用(Remote Procedure Call翎碑,RPC)方式來實(shí)現(xiàn)谬返。與很多其他的基于RPC的解決方案一樣,Android使用一種接口定義語言(Interface Definition Language日杈,IDL)來公開服務(wù)的接口遣铝。我們知道4個(gè)Android應(yīng)用程序組件中的3個(gè)(Activity、BroadcastReceiver和ContentProvider)都可以進(jìn)行跨進(jìn)程訪問莉擒,另外一個(gè)Android應(yīng)用程序組件Service同樣可以酿炸。因此,可以將這種可以跨進(jìn)程訪問的服務(wù)稱為AIDL(Android Interface Definition Language)服務(wù)涨冀。
3填硕、Binder理解
1、什么是binder:
Binder是Android實(shí)現(xiàn) 跨進(jìn)程通訊(IPC)的方式,是一種虛擬的物理設(shè)備驅(qū)動(dòng)鹿鳖,實(shí)現(xiàn)了IBindler 接口扁眯。
2、知識(shí)概念
- 一個(gè)進(jìn)程空間分為 用戶空間 & 內(nèi)核空間(Kernel)翅帜,即把進(jìn)程內(nèi) 用戶 & 內(nèi)核 隔離開來
區(qū)別:
- 進(jìn)程間姻檀,用戶空間的數(shù)據(jù)不可共享,所以用戶空間 = 不可共享空間
- 進(jìn)程間涝滴,內(nèi)核空間的數(shù)據(jù)可共享绣版,所以內(nèi)核空間 = 可共享空間
- 進(jìn)程隔離:保證 安全性 & 獨(dú)立性周荐,一個(gè)進(jìn)程 不能直接操作或者訪問另一個(gè)進(jìn)程,即Android的進(jìn)程是相互獨(dú)立僵娃、隔離的
- 跨進(jìn)程通信( IPC ):隔離后概作,由于某些需求,進(jìn)程間 需要合作 / 交互
- 跨進(jìn)程間通信的原理
- 先通過 進(jìn)程間 的內(nèi)核空間進(jìn)行 數(shù)據(jù)交互
-
再通過 進(jìn)程內(nèi) 的用戶空間 & 內(nèi)核空間進(jìn)行 數(shù)據(jù)交互默怨,從而實(shí)現(xiàn) 進(jìn)程間的用戶空間 的數(shù)據(jù)交互
- 而Binder讯榕,就是充當(dāng) 連接 兩個(gè)進(jìn)程(內(nèi)核空間)的通道。
3匙睹、Binder 跨進(jìn)程通信機(jī)制 模型
- 模型原理:
4愚屁、優(yōu)點(diǎn)
對(duì)比 Linux (Android基于Linux)上的其他進(jìn)程通信方式(管道、消息隊(duì)列痕檬、共享內(nèi)存霎槐、
信號(hào)量、Socket)梦谜,Binder 機(jī)制的優(yōu)點(diǎn)有:
圖文詳解 Android Binder跨進(jìn)程通信的原理
8丘跌、Handler相關(guān)
1、handler 消息傳遞分析
作用:Handle 進(jìn)行消息傳遞
- Handle發(fā)送的msg通過enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)添加進(jìn)(MessageQueue)消息隊(duì)列中.
2唁桩、Handle闭树、Message、MessageQueue荒澡、Looper之間的關(guān)系
- Handle:主要發(fā)送 Message
- Message:消息
- MessageQueue:消息隊(duì)列.保存由Looper發(fā)送的消息列表报辱。
- Looper:用于為線程運(yùn)行消息循環(huán)的類。Thread默認(rèn)情況下沒有與之關(guān)聯(lián)单山,通過prepare()循環(huán)運(yùn)行在線程中碍现,通過loop(for(;;))來處理消息。
9米奸、熱修復(fù)相關(guān)
1昼接、熱修復(fù)包含:
- 資源替換
- 類替換(四大組件、類)
- SO補(bǔ)丁
2躏升、資源替換方法:
思路:Andorid APP默認(rèn)的類加載是PathClassLoader,這個(gè)只能加載自己APK的dex文件辩棒,所以我們需要使用DexClassLoader。我們用DexClassLoader加載外部的APK之后膨疏,通過反射獲取對(duì)應(yīng)的資源一睁。
3、類替換(四大組件佃却、類):
- 通過PathClassLoader 來加載我們自身App的dex
- 通過DexClassLoader來加載我們的補(bǔ)丁dex文件,這里面就是沒有bug的dex
- 反射兩個(gè)classLoader的<DexPathList pathList;>
- 接著我們來繼續(xù)反射兩個(gè)classloader中的pathList(注意:是兩個(gè)!一個(gè)是我們自己應(yīng)用的,另一個(gè)是我們補(bǔ)丁的,PathClassLoader和DexClassLoader都繼承BaseDexClassLoader),DexPathList里面的<Element[] dexElements;>,沒錯(cuò)還是拿到這個(gè)數(shù)組的值
- 合并兩個(gè)反射到的Element 數(shù)組!這里是重中之重.我們需要把我們的補(bǔ)丁dex放在數(shù)組的最前面!
- 將合并的新的數(shù)組,通過Field重新設(shè)置到我們自身App的DexPathList->dexElements.沒錯(cuò)!就是合并之后覆蓋有bug那個(gè)loader的Element 數(shù)組!!
- 通過Android build-tools 中的dx命令打包一個(gè)沒有bug的dex
Android 熱修復(fù)(全網(wǎng)最簡(jiǎn)單的熱修復(fù)講解)
4者吁、SO補(bǔ)丁:
10饲帅、圖片加載緩存相關(guān)
1复凳、設(shè)計(jì)一套圖片異步加載緩存方案
緩存層分為三層:內(nèi)存層瘤泪,磁盤層,網(wǎng)絡(luò)層
- 內(nèi)存層:內(nèi)存緩存相對(duì)于磁盤緩存而言育八,速度要來的快很多对途,但缺點(diǎn)容量較小且會(huì)被系統(tǒng)回收,這里的實(shí)現(xiàn)我用到了LruCache髓棋。
- 磁盤層:相比內(nèi)存緩存而言速度要來得慢很多实檀,但容量很大,這里的實(shí)現(xiàn)我用到了DiskLruCache類按声。
- 網(wǎng)絡(luò)層:網(wǎng)絡(luò)訪問實(shí)現(xiàn)我用到了開源框架Volley
11膳犹、內(nèi)存泄露及管理
1、內(nèi)存泄漏:
- 內(nèi)存泄露:程序在向系統(tǒng)申請(qǐng)分配內(nèi)存空間后(new)签则,在使用完畢后未釋放须床。結(jié)果導(dǎo)致一直占據(jù)該內(nèi)存單元,我們和程序都無法再使用該內(nèi)存單元渐裂,直到程序結(jié)束豺旬,這是內(nèi)存泄露。
- 內(nèi)存溢出:程序向系統(tǒng)申請(qǐng)的內(nèi)存空間超出了系統(tǒng)能給的芯义。比如內(nèi)存只能分配一個(gè)int類型哈垢,我卻要塞給他一個(gè)long類型,系統(tǒng)就出現(xiàn)oom扛拨。又比如一車最多能坐5個(gè)人,你卻非要塞下10個(gè)举塔,車就擠爆了绑警。
- 大量的內(nèi)存泄露會(huì)導(dǎo)致內(nèi)存溢出(oom)。
2央渣、內(nèi)存:
- 棧(stack):是簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu)计盒,但在計(jì)算機(jī)中使用廣泛。棧最顯著的特征是:LIFO(Last In, First Out, 后進(jìn)先出)芽丹,棧中只存放基本類型和對(duì)象的引用(不是對(duì)象)北启。
- 堆(heap):堆內(nèi)存用于存放由new創(chuàng)建的對(duì)象和數(shù)組。在堆中分配的內(nèi)存拔第,由java虛擬機(jī)自動(dòng)垃圾回收器來管理咕村。JVM只有一個(gè)堆區(qū)(heap)被所有線程共享,堆中不存放基本類型和對(duì)象引用蚊俺,只存放對(duì)象本身懈涛。
- 方法區(qū)(method):又叫靜態(tài)區(qū),跟堆一樣泳猬,被所有的線程共享批钠。方法區(qū)包含所有的class和static變量宇植。
3、內(nèi)存優(yōu)化
- 單例導(dǎo)致內(nèi)存泄露
public class AppSettings {
private static AppSettings sInstance;
private Context mContext;
private AppSettings(Context context) {
this.mContext = context;
//this.mContext = context.getApplicationContext();
}
public static AppSettings getInstance(Context context) {
if (sInstance == null) {
sInstance = new AppSettings(context);
}
return sInstance;
}
}
2埋心、靜態(tài)變量導(dǎo)致內(nèi)存泄露
public class MainActivity extends AppCompatActivity {
private static Info sInfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (sInfo != null) {
sInfo = new Info(this);
}
}
}
class Info {
public Info(Activity activity) {
}
}
Info作為Activity的靜態(tài)成員指郁,并且持有Activity的引用,但是sInfo作為靜態(tài)變量拷呆,生命周期肯定比Activity長(zhǎng)坡氯。所以當(dāng)Activity退出后,sInfo仍然引用了Activity洋腮,Activity不能被回收箫柳,這就導(dǎo)致了內(nèi)存泄露。
3啥供、非靜態(tài)內(nèi)部類導(dǎo)致內(nèi)存泄露
非靜態(tài)內(nèi)部類(包括匿名內(nèi)部類)默認(rèn)就會(huì)持有外部類的引用悯恍,當(dāng)非靜態(tài)內(nèi)部類對(duì)象的生命周期比外部類對(duì)象的生命周期長(zhǎng)時(shí),就會(huì)導(dǎo)致內(nèi)存泄露伙狐。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start();
}
private void start() {
Message msg = Message.obtain();
msg.what = 1;
mHandler.sendMessage(msg);
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
// 做相應(yīng)邏輯
}
}
};
}
熟悉Handler消息機(jī)制的都知道涮毫,mHandler會(huì)作為成員變量保存在發(fā)送的消息msg中,即msg持有mHandler的引用贷屎,而mHandler是Activity的非靜態(tài)內(nèi)部類實(shí)例罢防,即mHandler持有Activity的引用,那么我們就可以理解為msg間接持有Activity的引用唉侄。msg被發(fā)送后先放到消息隊(duì)列MessageQueue中咒吐,然后等待Looper的輪詢處理(MessageQueue和Looper都是與線程相關(guān)聯(lián)的,MessageQueue是Looper引用的成員變量属划,而Looper是保存在ThreadLocal中的)恬叹。那么當(dāng)Activity退出后,msg可能仍然存在于消息對(duì)列MessageQueue中未處理或者正在處理同眯,那么這樣就會(huì)導(dǎo)致Activity無法被回收绽昼,以致發(fā)生Activity的內(nèi)存泄露。
通常在Android開發(fā)中如果要使用內(nèi)部類须蜗,但又要規(guī)避內(nèi)存泄露硅确,一般都會(huì)采用靜態(tài)內(nèi)部類+弱引用的方式。
public class MainActivity extends AppCompatActivity {
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler = new MyHandler(this);
start();
}
private void start() {
Message msg = Message.obtain();
msg.what = 1;
mHandler.sendMessage(msg);
}
private static class MyHandler extends Handler {
private WeakReference<MainActivity> activityWeakReference;
public MyHandler(MainActivity activity) {
activityWeakReference = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = activityWeakReference.get();
if (activity != null) {
if (msg.what == 1) {
// 做相應(yīng)邏輯
}
}
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
非靜態(tài)內(nèi)部類造成內(nèi)存泄露還有一種情況就是使用Thread或者AsyncTask
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
// 模擬相應(yīng)耗時(shí)邏輯
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
這種方式新建的子線程Thread和AsyncTask都是匿名內(nèi)部類對(duì)象明肮,默認(rèn)就隱式的持有外部Activity的引用菱农,導(dǎo)致Activity內(nèi)存泄露。
4晤愧、未取消注冊(cè)或回調(diào)導(dǎo)致內(nèi)存泄露
- 在Activity中注冊(cè)廣播大莫,如果在Activity銷毀后不取消注冊(cè)
5、Timer和TimerTask導(dǎo)致內(nèi)存泄露
- Timer和TimerTask在Android中通常會(huì)被用來做一些計(jì)時(shí)或循環(huán)任務(wù)
6官份、集合中的對(duì)象未清理造成內(nèi)存泄露
如果一個(gè)對(duì)象放入到ArrayList只厘、HashMap等集合中烙丛,這個(gè)集合就會(huì)持有該對(duì)象的引用。當(dāng)我們不再需要這個(gè)對(duì)象時(shí)羔味,也并沒有將它從集合中移除河咽,這樣只要集合還在使用(而此對(duì)象已經(jīng)無用了),這個(gè)對(duì)象就造成了內(nèi)存泄露赋元。并且如果集合被靜態(tài)引用的話忘蟹,集合里面那些沒有用的對(duì)象更會(huì)造成內(nèi)存泄露了。所以在使用集合時(shí)要及時(shí)將不用的對(duì)象從集合remove搁凸,或者clear集合媚值,以避免內(nèi)存泄漏。
7护糖、資源未關(guān)閉或釋放導(dǎo)致內(nèi)存泄露
在使用IO褥芒、File流或者Sqlite、Cursor等資源時(shí)要及時(shí)關(guān)閉嫡良。這些資源在進(jìn)行讀寫操作時(shí)通常都使用了緩沖锰扶,如果及時(shí)不關(guān)閉,這些緩沖對(duì)象就會(huì)一直被占用而得不到釋放寝受,以致發(fā)生內(nèi)存泄露坷牛。因此我們?cè)诓恍枰褂盟鼈兊臅r(shí)候就及時(shí)關(guān)閉,以便緩沖能及時(shí)得到釋放很澄,從而避免內(nèi)存泄露京闰。
8、屬性動(dòng)畫造成內(nèi)存泄露
動(dòng)畫同樣是一個(gè)耗時(shí)任務(wù)痴怨,比如在Activity中啟動(dòng)了屬性動(dòng)畫(ObjectAnimator)忙干,但是在銷毀的時(shí)候,沒有調(diào)用cancle方法浪藻,雖然我們看不到動(dòng)畫了,但是這個(gè)動(dòng)畫依然會(huì)不斷地播放下去乾翔,動(dòng)畫引用所在的控件爱葵,所在的控件引用Activity,這就造成Activity無法正常釋放反浓。因此同樣要在Activity銷毀的時(shí)候cancel掉屬性動(dòng)畫萌丈,避免發(fā)生內(nèi)存泄漏。
@Override
protected void onDestroy() {
super.onDestroy();
mAnimator.cancel();
}
9雷则、WebView造成內(nèi)存泄露
關(guān)于WebView的內(nèi)存泄露辆雾,因?yàn)閃ebView在加載網(wǎng)頁后會(huì)長(zhǎng)期占用內(nèi)存而不能被釋放,因此我們?cè)贏ctivity銷毀后要調(diào)用它的destory()方法來銷毀它以釋放內(nèi)存月劈。
@Override
protected void onDestroy() {
super.onDestroy();
// 先從父控件中移除WebView
mWebViewContainer.removeView(mWebView);
mWebView.stopLoading();
mWebView.getSettings().setJavaScriptEnabled(false);
mWebView.clearHistory();
mWebView.removeAllViews();
mWebView.destroy();
}
10度迂、總結(jié)
1).資源對(duì)象沒關(guān)閉造成的內(nèi)存泄漏
2).構(gòu)造Adapter時(shí)藤乙,沒有使用緩存的convertView
3).Bitmap對(duì)象不在使用時(shí)調(diào)用recycle()釋放內(nèi)存
4).試著使用關(guān)于application的context來替代和activity相關(guān)的context
5).注冊(cè)沒取消造成的內(nèi)存泄漏
6).集合中對(duì)象沒清理造成的內(nèi)存泄漏
查找內(nèi)存泄漏可以使用Android Stdio 自帶的Android Profiler工具,也可以使用Square產(chǎn)品的LeadCanary.
12、android 屏幕適配
- 在 XML 布局文件中指定尺寸時(shí)使用 wrap_content惭墓、match_parent 或 dp 單位 坛梁。
- 不要在應(yīng)用代碼中使用硬編碼的像素值
- 不要使用 AbsoluteLayout(已棄用)
- 為不同屏幕密度提供替代位圖可繪制對(duì)象
13、HybridJAVA 與JS交互
-
Android 調(diào) JS :
1腊凶、java
webView.loadUrl("javascript:javacalljs()");
??2划咐、Html
注意:考慮有返回值情況;Android在4.4之前并沒有提供直接調(diào)用js函數(shù)并獲取值的方法钧萍,所以在此之前褐缠,常用的思路是 java調(diào)用js方法,js方法執(zhí)行完畢风瘦,再次調(diào)用java代碼將值返回队魏。
// 4.4之后 java代碼時(shí)用evaluateJavascript方法調(diào)用
private void testEvaluateJavascript(WebView webView) {
webView.evaluateJavascript("getGreetings()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
Log.i(LOGTAG, "onReceiveValue value=" + value);
}});
}
-
JS 調(diào) Android :
1、java
webView.addJavascriptInterface(MainActivity.this,"android");
??2弛秋、html
<body>
HTML 內(nèi)容顯示 <br/>
<h1><div id="content">內(nèi)容顯示</div></h1><br/>
<input type="button" value="點(diǎn)擊調(diào)用java代碼" onclick="window.android.startFunction()" /><br/>
<input type="button" value="點(diǎn)擊調(diào)用java代碼并傳遞參數(shù)" onclick="window.android.startFunction('http://blog.csdn.net/Leejizhou')" />
</body>
14器躏、單例模式(手寫)
//懶漢式
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static synchronized Singleton getSingleton() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
//餓漢式
public class Singleton {
private static final Singleton singleton = new Singleton();
private Singleton () {
}
public static Singleton getSingleton() {
return singleton;
}
}
//double-lock
public class Singleton {
private volatile static Singleton singleton;
private Singleton() {
}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized(Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
14、ANR相關(guān)
1蟹略、什么是ANR
在Android上登失,如果你的應(yīng)用程序有一段時(shí)間響應(yīng)不夠靈敏,系統(tǒng)會(huì)向用戶顯示一個(gè)對(duì)話框挖炬,這個(gè)對(duì)話框稱作應(yīng)用程序無響應(yīng)(ANR:Application Not Responding)對(duì)話框揽浙。
2、ANR產(chǎn)生的原因
ANR產(chǎn)生的根本原因是APP阻塞了UI線程
3意敛、ANR產(chǎn)生的原因
1:UI線程盡量只做跟UI相關(guān)的工作馅巷,但一些復(fù)雜的UI操作,還是需要一些技巧來處理草姻,不如你讓一個(gè)Button去setText一個(gè)10M的文本钓猬,UI肯定崩掉了,不過對(duì)于此類問題撩独,分段加載貌似是最好的方法了敞曹。
2:讓耗時(shí)的工作(比如數(shù)據(jù)庫操作,I/O综膀,連接網(wǎng)絡(luò)或者別的有可能阻礙UI線程的操作)把它放入單獨(dú)的線程處理澳迫。
3:盡量用Handler來處理UIthread和別的thread之間的交互。
15剧劝、SharedPreference相關(guān)
- SharedPreference三種獲得方法和區(qū)別:
1橄登、 Activity類中的getPreferences(int mode)文件自動(dòng)命名為當(dāng)前活動(dòng)的類名。
2、 Context類中g(shù)etSharedPreferences("fileName", int mode) 此方法可以指定文件名拢锹,mode同上谣妻。
3、PreferenceManager類中的getDefaultSharedPreferences(Context context)它只接收一個(gè)context參數(shù)面褐。
文件用當(dāng)前應(yīng)用程序的包名和PreferenceActivity一起來命名拌禾。屬于整個(gè)應(yīng)用程序
- commit和apply的區(qū)別:
- apply沒有返回值而commit返回boolean表明修改是否提交成功。
- apply是將修改數(shù)據(jù)原子提交到內(nèi)存, 而后異步真正提交到硬件磁盤, 而commit是同步的提交到硬件磁盤展哭,因此湃窍,在多個(gè)并發(fā)的提交commit的時(shí)候,他們會(huì)等待正在處理的commit保存到磁盤后在操作匪傍,從而降低了效率您市。而apply只是原子的提交到內(nèi)容,后面有調(diào)用apply的函數(shù)的將會(huì)直接覆蓋前面的內(nèi)存數(shù)據(jù)役衡,這樣從一定程度上提高了很多效率茵休。
- apply方法不會(huì)提示任何失敗的提示。 由于在一個(gè)進(jìn)程中手蝎,sharedPreference是單實(shí)例榕莺,一般不會(huì)出現(xiàn)并發(fā)沖突,如果對(duì)提交的結(jié)果不關(guān)心的話棵介,建議使用apply钉鸯,當(dāng)然需要確保提交成功且有后續(xù)操作的話,還是需要用commit的邮辽。
16唠雕、View,SurfaceView吨述,GLSurfaceView的關(guān)系和區(qū)別:
- View:顯示視圖岩睁,內(nèi)置畫布,提供圖形繪制函數(shù)揣云、觸屏事件捕儒、按鍵事件函數(shù)等;必須在UI主線程內(nèi)更新畫面邓夕,速度較慢肋层。
- SurfaceView:基于view視圖進(jìn)行拓展的視圖類,更適合2D游戲的開發(fā)翎迁;是view的子類,類似使用雙緩機(jī)制净薛,在新的線程中更新畫面所以刷新界面速度比view快汪榔。
- GLSurfaceView:基于SurfaceView視圖再次進(jìn)行拓展的視圖類,專用于3D游戲開發(fā)的視圖;是SurfaceView的子類痴腌,openGL專用雌团。
17、其他
1士聪、Android 中序列化有哪些方式?區(qū)別?
-
Serializable(Java自帶):
Serializable是序列化的意思黄刚,表示將一個(gè)對(duì)象轉(zhuǎn)換成可存儲(chǔ)或可傳輸?shù)臓顟B(tài)蹦骑。序列化后的對(duì)象可以在網(wǎng)絡(luò)上進(jìn)行傳輸,也可以存儲(chǔ)到本地区岗。 -
Parcelable(android 專用):
不過不同于將對(duì)象進(jìn)行序列化略板,Parcelable方式的實(shí)現(xiàn)原理是將一個(gè)完整的對(duì)象進(jìn)行分解,
而分解后的每一部分都是Intent所支持的數(shù)據(jù)類型 -
區(qū)別:
- Parcelable比Serializable性能高慈缔,所以應(yīng)用內(nèi)傳遞數(shù)據(jù)推薦使用Parcelable
- Serializable代碼量少叮称,寫起來方便,缺點(diǎn)是使用了反射藐鹤,序列化的過程較慢瓤檐。這種機(jī)制會(huì)在序列化的時(shí)候創(chuàng)建許多的臨時(shí)對(duì)象,容易觸發(fā)垃圾回收娱节。
2挠蛉、glide 源碼
3、Android中進(jìn)程的級(jí)別括堤,以及各自的區(qū)別碌秸。
- 1、前臺(tái)進(jìn)程
用戶當(dāng)前正在做的事情需要這個(gè)進(jìn)程悄窃。如果滿足下面的條件之一讥电,一個(gè)進(jìn)程就被認(rèn)為是前臺(tái)進(jìn)程:
1).這個(gè)進(jìn)程擁有一個(gè)正在與用戶交互的Activity(這個(gè)Activity的onResume()方法被調(diào)用)。
2).這個(gè)進(jìn)程擁有一個(gè)綁定到正在與用戶交互的activity上的Service轧抗。
3).這個(gè)進(jìn)程擁有一個(gè)前臺(tái)運(yùn)行的Service(service調(diào)用了方法startForeground()).
4).這個(gè)進(jìn)程擁有一個(gè)正在執(zhí)行其任何一個(gè)生命周期回調(diào)方法(onCreate(),onStart(),或onDestroy())的Service恩敌。
5).這個(gè)進(jìn)程擁有正在執(zhí)行其onReceive()方法的BroadcastReceiver。
通常横媚,在任何時(shí)間點(diǎn)纠炮,只有很少的前臺(tái)進(jìn)程存在。它們只有在達(dá)到無法調(diào)合的矛盾時(shí)才會(huì)被殺--如內(nèi)存太小而不能繼續(xù)運(yùn)行時(shí)灯蝴。通常恢口,到了這時(shí),設(shè)備就達(dá)到了一個(gè)內(nèi)存分頁調(diào)度狀態(tài)穷躁,所以需要?dú)⒁恍┣芭_(tái)進(jìn)程來保證用戶界面的反應(yīng).
- 2耕肩、可見進(jìn)程
一個(gè)進(jìn)程不擁有運(yùn)行于前臺(tái)的組件,但是依然能影響用戶所見。滿足下列條件時(shí)猿诸,進(jìn)程即為可見:
這個(gè)進(jìn)程擁有一個(gè)不在前臺(tái)但仍可見的Activity(它的onPause()方法被調(diào)用)婚被。當(dāng)一個(gè)前臺(tái)activity啟動(dòng)一個(gè)對(duì)話框時(shí),就出了這種情況梳虽。
- 3址芯、服務(wù)進(jìn)程
一個(gè)可見進(jìn)程被認(rèn)為是極其重要的。并且窜觉,除非只有殺掉它才可以保證所有前臺(tái)進(jìn)程的運(yùn)行谷炸,否則是不能動(dòng)它的。
這個(gè)進(jìn)程擁有一個(gè)綁定到可見activity的Service竖螃。
一個(gè)進(jìn)程不在上述兩種之內(nèi)淑廊,但它運(yùn)行著一個(gè)被startService()所啟動(dòng)的service。
盡管一個(gè)服務(wù)進(jìn)程不直接影響用戶所見特咆,但是它們通常做一些用戶關(guān)心的事情(比如播放音樂或下載數(shù)據(jù))季惩,所以系統(tǒng)不到前臺(tái)進(jìn)程和可見進(jìn)程活不下去時(shí)不會(huì)殺它。
- 4腻格、后臺(tái)進(jìn)程
一個(gè)進(jìn)程擁有一個(gè)當(dāng)前不可見的activity(activity的onStop()方法被調(diào)用)画拾。
- 5、空進(jìn)程
一個(gè)進(jìn)程不擁有任何active組件菜职。
4青抛、線程池的相關(guān)知識(shí)。
Android中的線程池都是之間或間接通過配置ThreadPoolExecutor來實(shí)現(xiàn)不同特性的線程池.Android中最常見的四類具有不同特性的線程池分別為FixThreadPool酬核、CachedThreadPool蜜另、SingleThreadPool、ScheduleThreadExecutor.
FixThreadPool:只有核心線程,并且數(shù)量固定的,也不會(huì)被回收,所有線程都活動(dòng)時(shí),因?yàn)殛?duì)列沒有限制大小,新任務(wù)會(huì)等待執(zhí)行.
優(yōu)點(diǎn):更快的響應(yīng)外界請(qǐng)求.SingleThreadPool:只有一個(gè)核心線程,確保所有的任務(wù)都在同一線程中按順序完成.因此不需要處理線程同步的問題.
CachedThreadPool:只有非核心線程,最大線程數(shù)非常大,所有線程都活動(dòng)時(shí),會(huì)為新任務(wù)創(chuàng)建新線程,否則會(huì)利用空閑線程(60s空閑時(shí)間,過了就會(huì)被回收,所以線程池中有0個(gè)線程的可能)處理任務(wù).
優(yōu)點(diǎn):任何任務(wù)都會(huì)被立即執(zhí)行(任務(wù)隊(duì)列SynchronousQueue相當(dāng)于一個(gè)空集合);比較適合執(zhí)行大量的耗時(shí)較少的任務(wù).ScheduleThreadExecutor:核心線程數(shù)固定,非核心線程(閑著沒活干會(huì)被立即回收)數(shù)沒有限制.
優(yōu)點(diǎn):執(zhí)行定時(shí)任務(wù)以及有固定周期的重復(fù)任務(wù)
5嫡意、怎樣計(jì)算一張圖片的大小举瑰,加載bitmap過程(怎樣保證不產(chǎn)生內(nèi)存溢出),二級(jí)緩存蔬螟,LRUCache算法此迅。
1、計(jì)算一張圖片的大小
圖片占用內(nèi)存的計(jì)算公式:圖片高度 * 圖片寬度 * 一個(gè)像素占用的內(nèi)存大小.所以旧巾,計(jì)算圖片占用內(nèi)存大小的時(shí)候耸序,要考慮圖片所在的目錄跟設(shè)備密度,這兩個(gè)因素其實(shí)影響的是圖片的高寬鲁猩,android會(huì)對(duì)圖片進(jìn)行拉升跟壓縮坎怪。
2、加載bitmap過程(怎樣保證不產(chǎn)生內(nèi)存溢出)
由于Android對(duì)圖片使用內(nèi)存有限制廓握,若是加載幾兆的大圖片便內(nèi)存溢出芋忿。
Bitmap會(huì)將圖片的所有像素(即長(zhǎng)x寬)加載到內(nèi)存中炸客,如果圖片分辨率過大,會(huì)直接導(dǎo)致內(nèi)存OOM戈钢,只有在BitmapFactory加載圖片時(shí)使用BitmapFactory.Options對(duì)相關(guān)參數(shù)進(jìn)行配置來減少加載的像素。
3是尔、BitmapFactory.Options相關(guān)參數(shù)詳解
(1).Options.inPreferredConfig值來降低內(nèi)存消耗殉了。
比如:默認(rèn)值A(chǔ)RGB_8888改為RGB_565,節(jié)約一半內(nèi)存。
(2).設(shè)置Options.inSampleSize 縮放比例拟枚,對(duì)大圖片進(jìn)行壓縮 薪铜。
(3).設(shè)置Options.inPurgeable和inInputShareable:讓系統(tǒng)能及時(shí)回 收內(nèi)存。
A:inPurgeable:設(shè)置為True時(shí)恩溅,表示系統(tǒng)內(nèi)存不足時(shí)可以被回 收隔箍,設(shè)置為False時(shí),表示不能被回收脚乡。
B:inInputShareable:設(shè)置是否深拷貝蜒滩,與inPurgeable結(jié)合使用,inPurgeable為false時(shí)奶稠,該參數(shù)無意義俯艰。
(4).使用decodeStream代替其他方法。
decodeResource,setImageResource,setImageBitmap等方法
LRUCache算法:內(nèi)部存在一個(gè)LinkedHashMap和maxSize锌订,把最近使用的對(duì)象用強(qiáng)引用存儲(chǔ)在 LinkedHashMap中竹握,給出來put和get方法,每次put圖片時(shí)計(jì)算緩存中所有圖片總大小辆飘,跟maxSize進(jìn)行比較啦辐,大于maxSize,就將最久添加的圖片移除蜈项;反之小于maxSize就添加進(jìn)來芹关。(400行代碼不到...)