版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、1 關(guān)于Http協(xié)議介紹 http屬于應(yīng)用層的面向?qū)ο蟮膮f(xié)議。其特點(diǎn)是簡(jiǎn)潔,快速,適用于分布式超媒體信息系統(tǒng)。詳細(xì)描述是: 1 支持客戶(hù)端/服務(wù)器模式;2簡(jiǎn)單快速;客戶(hù)向服務(wù)器發(fā)送請(qǐng)求時(shí),只需傳送請(qǐng)求方法和路徑,請(qǐng)求常用的方法是 get post 少數(shù)用head,每種方法規(guī)定了客戶(hù)與服務(wù)器聯(lián)系的類(lèi)型不同,由于http協(xié)議簡(jiǎn)單,使得http服務(wù)器器程序規(guī)模小,通信速度快。3 靈活,http允許傳輸任意類(lèi)型數(shù)據(jù)對(duì)象。正在傳輸?shù)念?lèi)型由Content-Type加以標(biāo)記。4無(wú)連接;無(wú)連接的含義是限制每次連接只處理一個(gè)請(qǐng)求。服務(wù)器處理完客戶(hù)端的請(qǐng)求,并收到客戶(hù)端的應(yīng)答后,即斷開(kāi)連接,采用這種方式可以節(jié)省傳
2、輸?shù)臅r(shí)間。5 無(wú)狀態(tài) http協(xié)議是無(wú)狀態(tài)協(xié)議,無(wú)狀態(tài)協(xié)議是指協(xié)議對(duì)事物的處理沒(méi)有記憶能力。缺少狀態(tài)意味著如果后續(xù)處理需要前面的信息,則它必須重新連接,這樣可能導(dǎo)致每次連接傳輸?shù)臄?shù)據(jù)量增大。另一方面,服務(wù)器不需要先前信息時(shí)它的應(yīng)答速度比較快。6 http請(qǐng)求由三部分組成,分別是:請(qǐng)求行、消息報(bào)頭、請(qǐng)求正文狀態(tài)代碼有三位數(shù)字組成,第一個(gè)數(shù)字定義了響應(yīng)的類(lèi)別,且有五種可能取值:1xx:指示信息-表示請(qǐng)求已接收,繼續(xù)處理2xx:成功-表示請(qǐng)求已被成功接收、理解、接受3xx:重定向-要完成請(qǐng)求必須進(jìn)行更進(jìn)一步的操作4xx:客戶(hù)端錯(cuò)誤-請(qǐng)求有語(yǔ)法錯(cuò)誤或請(qǐng)求無(wú)法實(shí)現(xiàn)5xx:服務(wù)器端錯(cuò)誤-服務(wù)器未
3、能實(shí)現(xiàn)合法的請(qǐng)求常見(jiàn)狀態(tài)代碼、狀態(tài)描述、說(shuō)明:200 OK /客戶(hù)端請(qǐng)求成功400 Bad Request /客戶(hù)端請(qǐng)求有語(yǔ)法錯(cuò)誤,不能被服務(wù)器所理解401 Unauthorized /請(qǐng)求未經(jīng)授權(quán),這個(gè)狀態(tài)代碼必須和WWW-Authenticate報(bào)頭域一起使用 403 Forbidden /服務(wù)器收到請(qǐng)求,但是拒絕提供服務(wù)404 Not Found /請(qǐng)求資源不存在,eg:輸入了錯(cuò)誤的URL500 Internal Server Error /服務(wù)器發(fā)生不可預(yù)期的錯(cuò)誤503 Serve
4、r Unavailable /服務(wù)器當(dāng)前不能處理客戶(hù)端的請(qǐng)求,一段時(shí)間后可能恢復(fù)正常2消息推送 消息推送最簡(jiǎn)單的方法就是使用第三方的,比如現(xiàn)在使用比較多的是極光推送,機(jī)關(guān)推送的技術(shù)原理是:移動(dòng)無(wú)線(xiàn)網(wǎng)絡(luò)長(zhǎng)連接移動(dòng)互聯(lián)網(wǎng)絡(luò)的現(xiàn)狀:因?yàn)槭謾C(jī)平臺(tái)本身、電量、網(wǎng)絡(luò)流量的限制,移動(dòng)互聯(lián)網(wǎng)應(yīng)用在設(shè)計(jì)上跟傳統(tǒng)PC 上的應(yīng)用很大不一樣,需要根據(jù)手機(jī)本身的特點(diǎn),盡量的節(jié)省電量和流量,同時(shí)又要盡可能的保證數(shù)據(jù)能及時(shí)到達(dá)客戶(hù)端。為了解決數(shù)據(jù)同步的問(wèn)題,在手機(jī)平臺(tái)上,常用的方法有2種。一種是定時(shí)去服務(wù)器上查詢(xún)數(shù)據(jù),也叫Polling,還有一種手機(jī)跟服務(wù)器之間維護(hù)一個(gè)TCP 長(zhǎng)連接,當(dāng)服務(wù)器有數(shù)據(jù)時(shí),實(shí)時(shí)推送
5、到客戶(hù)端,也就是我們說(shuō)的Push。從耗費(fèi)的電量、流量和數(shù)據(jù)送達(dá)的及時(shí)性來(lái)說(shuō),Push 都會(huì)有明顯的優(yōu)勢(shì),但Push 的實(shí)現(xiàn)和維護(hù)成本相對(duì)較高。在移動(dòng)無(wú)線(xiàn)網(wǎng)絡(luò)下維護(hù)長(zhǎng)連接,相對(duì)也有一些技術(shù)上的難度移動(dòng)無(wú)線(xiàn)網(wǎng)絡(luò)的特點(diǎn):因?yàn)镮P v4 的IP 量有限,運(yùn)營(yíng)商分配給手機(jī)終端的IP 是運(yùn)營(yíng)商內(nèi)網(wǎng)的IP,手機(jī)要連接Internet,就需要通過(guò)運(yùn)營(yíng)商的網(wǎng)關(guān)做一個(gè)網(wǎng)絡(luò)地址轉(zhuǎn)換(Network Address Translation,NAT)。簡(jiǎn)單的說(shuō)運(yùn)營(yíng)商的網(wǎng)關(guān)需要維護(hù)一個(gè)外網(wǎng)IP、端口到內(nèi)網(wǎng)IP、端口的對(duì)應(yīng)關(guān)系,以確保內(nèi)網(wǎng)的手機(jī)可以跟Internet 的服務(wù)器通訊。對(duì)于大部分移動(dòng)無(wú)線(xiàn)網(wǎng)絡(luò)運(yùn)營(yíng)商都在鏈路一段時(shí)
6、間沒(méi)有數(shù)據(jù)通訊時(shí),會(huì)淘汰NAT 表中的對(duì)應(yīng)項(xiàng),造成鏈路中斷。Android 平臺(tái)上長(zhǎng)連接的實(shí)現(xiàn)為了不讓NAT 表失效,我們需要定時(shí)的發(fā)心跳,以刷新NAT 表項(xiàng),避免被淘汰。Android 上定時(shí)運(yùn)行任務(wù)常用的方法有2種,一種方法用Timer,另一種是AlarmManager。TimerAndroid 的Timer 類(lèi)可以用來(lái)計(jì)劃需要循環(huán)執(zhí)行的任務(wù),Timer 的問(wèn)題是它需要用WakeLock 讓CPU 保持喚醒狀態(tài),這樣會(huì)大量消耗手機(jī)電量,大大減短手機(jī)待機(jī)時(shí)間。這種方式不能滿(mǎn)足我們的需求。AlarmManagerAlarmManager 是Android 系統(tǒng)封裝的用于管理RTC 的模塊,RT
7、C (Real Time Clock) 是一個(gè)獨(dú)立的硬件時(shí)鐘,可以在CPU 休眠時(shí)正常運(yùn)行,在預(yù)設(shè)的時(shí)間到達(dá)時(shí),通過(guò)中斷喚醒CPU。這意味著,如果我們用AlarmManager 來(lái)定時(shí)執(zhí)行任務(wù),CPU 可以正常的休眠,只有在需要運(yùn)行任務(wù)時(shí)醒來(lái)一段很短的時(shí)間。極光推送的Android SDK 就是基于這種技術(shù)實(shí)現(xiàn)的。服務(wù)器設(shè)計(jì)當(dāng)有大量的手機(jī)終端需要與服務(wù)器維持長(zhǎng)連接時(shí),對(duì)服務(wù)器的設(shè)計(jì)會(huì)是一個(gè)很大的挑戰(zhàn)。假設(shè)一臺(tái)服務(wù)器維護(hù)10萬(wàn)個(gè)長(zhǎng)連接,當(dāng)有1000萬(wàn)用戶(hù)量時(shí),需要有多達(dá)100臺(tái)的服務(wù)器來(lái)維護(hù)這些用戶(hù)的長(zhǎng)連接,這里還不算用于做備份的服務(wù)器,這將會(huì)是一個(gè)巨大的成本問(wèn)題。那就需要我們盡可能提高單臺(tái)服務(wù)
8、器接入用戶(hù)的量,也就是業(yè)界已經(jīng)討論很久了的C10K 問(wèn)題。 上面只是針對(duì)極光推送來(lái)說(shuō),下面是具體的消息推送的一般有的方式:1) 通過(guò)SMS進(jìn)行服務(wù)器端和客戶(hù)端的交流通信在Android平臺(tái)上,你可以通過(guò)攔截SMS消息并且解析消息內(nèi)容來(lái)了解服務(wù)器的意圖,可以實(shí)現(xiàn)完全的實(shí)時(shí)操作。但是問(wèn)題是這個(gè)方案的成本相對(duì)比較高,且依賴(lài)于運(yùn)營(yíng)商2) 循環(huán)主動(dòng)定時(shí)獲取這種方法需要客戶(hù)端來(lái)做一個(gè)定時(shí)或者周期性的訪(fǎng)問(wèn)服務(wù)器端接口,以獲得最新的消息。輪詢(xún)的頻率太慢可能導(dǎo)致某些消息的延遲,太快則會(huì)大量消耗網(wǎng)絡(luò)帶寬和電池3) 持久連接這個(gè)方案可以解決由輪詢(xún)帶來(lái)的性能問(wèn)題,但是還是會(huì)消耗手機(jī)的電池。我們需要開(kāi)一個(gè)服務(wù)來(lái)保持和服
9、務(wù)器端的持久連接(蘋(píng)果就和谷歌的C2DM是這種機(jī)制)。但是對(duì)于Android系統(tǒng),當(dāng)系統(tǒng)可用資源較低,系統(tǒng)會(huì)強(qiáng)制關(guān)閉我們的服務(wù)或者是應(yīng)用,這種情況下連接會(huì)強(qiáng)制中斷。(Apple的推送服務(wù)之所以工作的很好,是因?yàn)槊恳慌_(tái)手機(jī)僅僅保持一個(gè)與服務(wù)器之間的連接,事實(shí)上C2DM也是這么工作的。即所有的推送服務(wù)都是經(jīng)由一個(gè)代理服務(wù)器完成的,這種情況下只需要和一臺(tái)服務(wù)器保持持久連接即可。C2DM=Cloud to Device Messaging)。相比之下第三種還是最可行的。為軟件編寫(xiě)系統(tǒng)服務(wù)或開(kāi)機(jī)啟動(dòng)功能;或者如果系統(tǒng)資源較低,服務(wù)被關(guān)閉后可以在onDestroy ()方法里面再重啟該服務(wù),進(jìn)而實(shí)現(xiàn)持久連
10、接的方式。C2DM內(nèi)置于Android的2.2系統(tǒng)上,無(wú)法兼容老的1.6到2.1系統(tǒng);且依賴(lài)于Google官方提供的C2DM服務(wù)器,由于國(guó)內(nèi)的網(wǎng)絡(luò)環(huán)境,這個(gè)服務(wù)經(jīng)常不可用。建立在TCP協(xié)議之上的XMPP協(xié)議,不僅可提供可這種持久連接的功能,能實(shí)現(xiàn)服務(wù)器和客戶(hù)機(jī)的雙工通信,還能不依賴(lài)與系統(tǒng)版本和google服務(wù)器的限制,提供了比較好的解決方案。當(dāng)別人要求你講解詳細(xì)的xmpp協(xié)議的時(shí)候才需要講解詳細(xì)下面講到的是XMPP協(xié)議的一些介紹:XMPP全稱(chēng)Extensible Messaging and Presence Protocol,前身是Jabber項(xiàng)目,是一種以XML為基礎(chǔ)的開(kāi)放式即時(shí)通訊協(xié)議。X
11、MPP因?yàn)楸籊oogle Talk和網(wǎng)易泡泡應(yīng)用而被廣大網(wǎng)民所接觸。XMPP的關(guān)鍵特色是,分散式的即時(shí)通訊系統(tǒng),以及使用XML串流。XMPP目前被IETF國(guó)際標(biāo)準(zhǔn)組織完成了標(biāo)準(zhǔn)化工作。Android push notification(androidpn) 是一個(gè)基于XMPP協(xié)議的java開(kāi)源實(shí)現(xiàn),它包含了完整的客戶(hù)端和服務(wù)器端。該服務(wù)器端基本是在另外一個(gè)開(kāi)源工程openfire基礎(chǔ)上修改實(shí)現(xiàn)的。androidpn客戶(hù)端需要用到一個(gè)基于java的開(kāi)源XMPP協(xié)議包asmack,這個(gè)包同樣也是基于openfire下的另外一個(gè)開(kāi)源項(xiàng)目smack,不過(guò)我們不需要自己編譯,可以直接把a(bǔ)ndroidpn
12、客戶(hù)端里面的asmack.jar拿來(lái)使用??蛻?hù)端利用asmack中提供的XMPPConnection類(lèi)與服務(wù)器建立持久連接,并通過(guò)該連接進(jìn)行用戶(hù)注冊(cè)和登錄認(rèn)證,同樣也是通過(guò)這條連接,接收服務(wù)器發(fā)送的通知。androidpn服務(wù)器端也是java語(yǔ)言實(shí)現(xiàn)的,基于openfire開(kāi)源工程,不過(guò)它的Web部分采用的是spring框架,這一點(diǎn)與openfire是不同的。Androidpn服務(wù)器包含兩個(gè)部分,一個(gè)是偵聽(tīng)在5222端口上的XMPP服務(wù),負(fù)責(zé)與客戶(hù)端的XMPPConnection類(lèi)進(jìn)行通信,作用是用戶(hù)注冊(cè)和身份認(rèn)證,并發(fā)送推送通知消息。另外一部分是Web服務(wù)器,采用一個(gè)輕量級(jí)的HTTP服務(wù)器,
13、負(fù)責(zé)接收用戶(hù)的Web請(qǐng)求。服務(wù)器的這兩方式,意義非凡:當(dāng)相應(yīng)的TCP端口被防火墻封閉,可以使用輪詢(xún)的方式進(jìn)行訪(fǎng)問(wèn),因此又有助于通過(guò)防火墻。下面是xmpp詳解深入學(xué)習(xí)XMPP議一 XMPP(協(xié)議簡(jiǎn)介)XMPP協(xié)議(Extensible Messaging and PresenceProtocol消息處理現(xiàn)場(chǎng)協(xié)議)是一種基于XML的協(xié)議,目的是為了解決及時(shí)通信標(biāo)準(zhǔn)而提出來(lái)的,最早是在Jabber上實(shí)現(xiàn)的。它繼承了在XM環(huán)境中靈活的發(fā)展性。因此,基于XMPP的應(yīng)用具有超強(qiáng)的可擴(kuò)展性。并且XML很易穿過(guò)防火墻,所以用XMPP構(gòu)建的應(yīng)用不易受到防火墻的阻礙。利用XMPP作為通用的傳輸機(jī)制,不同組織內(nèi)的不
14、同應(yīng)用都可以進(jìn)行有效的通信。二IM(即時(shí)通訊軟件簡(jiǎn)介)Instant Messenger,及時(shí)通信軟件,就是大家使用的QQ、MSN Messenger和Gtalk等等。其中Gtalk 就是基于XMPP 協(xié)議的一個(gè)實(shí)現(xiàn),其他的則不是。當(dāng)前IM 幾乎作為每個(gè)上網(wǎng)者必然使用的工具,在國(guó)外的大型企業(yè)中有一些企業(yè)級(jí)的IM應(yīng)用,但是其商業(yè)價(jià)值還沒(méi)完全發(fā)揮出來(lái)。設(shè)想既然XMPP 協(xié)議是一個(gè)公開(kāi)的協(xié)議,那么每個(gè)企業(yè)都可以利用它來(lái)開(kāi)發(fā)適合本身企業(yè)工作,提高自身生產(chǎn)效率的IM;甚至,你還可以在網(wǎng)絡(luò)游戲中集成這種通信軟件,不但讓你可以邊游戲邊聊天,也可以開(kāi)發(fā)出適合游戲本身的IM 應(yīng)用,比如說(shuō)一些游戲關(guān)鍵場(chǎng)景提醒功能
15、,團(tuán)隊(duì)語(yǔ)音交流等等都可以基于IM來(lái)實(shí)現(xiàn)。三本文主要內(nèi)容本文主要講解在android使用xmpp協(xié)議進(jìn)行即時(shí)通信,所涉及3個(gè)主要的東西,它們是openfire、smack和spark,這個(gè)三個(gè)東東結(jié)合起來(lái)就是完整的xmpp IM實(shí)現(xiàn),這里簡(jiǎn)單介紹一下這3個(gè)東東在下文的作用:openfire主要是作為服務(wù)器,負(fù)責(zé)管理客戶(hù)端的通信連接,以及提供客戶(hù)端一些通信信息和連接信息。Smack主要是xmpp協(xié)議的實(shí)現(xiàn),提供了一套很好的api,所以下面操作xmpp都是通過(guò)使用smack的api來(lái)實(shí)現(xiàn),當(dāng)然因?yàn)槭窃赼ndroid里,所以使用的是asmack這個(gè)包,里面方法跟smack包差不多。Spark 是IM客
16、戶(hù)端的實(shí)現(xiàn),其實(shí)就是使用了smack 的api實(shí)現(xiàn)的。數(shù)據(jù)通訊具體實(shí)現(xiàn)的流程:四開(kāi)發(fā)具體配置環(huán)境:1.配置openfire服務(wù)器Openfire是一個(gè)強(qiáng)大的即時(shí)消息(IM)和聊天服務(wù)器,它實(shí)現(xiàn)了XMPP協(xié)議,可以使用它輕易的構(gòu)建高效率的即時(shí)通信服務(wù)器. 其安裝和部署都十分簡(jiǎn)單,并利用Web進(jìn)行管理。單臺(tái)服務(wù)器可支持上萬(wàn)并發(fā)用戶(hù),由于是采用開(kāi)放的XMPP協(xié)議,可以使用各種支持XMPP協(xié)議的IM客戶(hù)端軟件登陸服務(wù)。安裝前準(zhǔn)備工作:一:Java運(yùn)行環(huán)境(已安裝則可跳過(guò)此步驟)官方下載地址: 二:數(shù)據(jù)庫(kù)(之前已安裝則可跳過(guò)此步驟)數(shù)據(jù)庫(kù)可以使用DB2,Oracle,MySQL,PostgreSQL,S
17、QL Server等其中任意一種安裝前準(zhǔn)備工作完成后:一:建立數(shù)據(jù)庫(kù)a.建立數(shù)據(jù)庫(kù),記下數(shù)據(jù)庫(kù)名,如OpenfireServer。b.在數(shù)據(jù)庫(kù)管理系統(tǒng)下建立新用戶(hù),如OpenfireUser。選擇SQL server身份驗(yàn)證,把強(qiáng)制密碼過(guò)期的勾去掉,只勾上強(qiáng)制實(shí)施密碼策略。在下面的數(shù)據(jù)庫(kù)下拉列表中選擇OpenfireServer,然后確定即可。c.然后在OpenfireServer數(shù)據(jù)庫(kù)目錄下,在其安全性中,新建一個(gè)用戶(hù),用戶(hù)名任取。登錄名選擇上面創(chuàng)建的OpenfireUser,架構(gòu)選擇db_owner,數(shù)據(jù)庫(kù)角色成員身份選擇db_owner, 二:安裝Openfire a.到官方下載最新版的
18、Openfire安裝包官方網(wǎng)址為:/projects/openfire/ b.雙擊Openfire安裝包開(kāi)始安裝安裝完畢后,會(huì)有提示框提示是否登錄,此時(shí)先放著不動(dòng)三:執(zhí)行數(shù)據(jù)庫(kù)腳本a.到Openfire安裝目錄下:如D:Program FilesOpenfireresourcesdatabase 下面有幾個(gè)數(shù)據(jù)庫(kù)的SQL腳本,直接拖動(dòng)到SQL Server Studio中執(zhí)行,執(zhí)行前確??捎脭?shù)據(jù)庫(kù)下拉列表選中的是OpenfireServer。b.接著連接對(duì)象資源管理器,使用SQL Server身份驗(yàn)證方式,輸入用戶(hù)名OpenfireUse
19、r,密碼嘗試進(jìn)行登錄操作。若成功登陸,則證明數(shù)據(jù)庫(kù)建立成功。四:首次設(shè)置Openfire a.點(diǎn)擊Openfire提示框中Launch Admin 按鈕,進(jìn)入首次設(shè)置頁(yè)面b.語(yǔ)言選擇簡(jiǎn)體中文數(shù)據(jù)庫(kù)選擇標(biāo)準(zhǔn)數(shù)據(jù)庫(kù)連接選擇相應(yīng)的數(shù)據(jù)庫(kù)驅(qū)動(dòng)類(lèi)型;URL一欄中,把hostname改成當(dāng)前的主機(jī)名;把database改成數(shù)據(jù)庫(kù)名OpenfireServer;接著分號(hào)后面的Appname全部去掉;點(diǎn)擊continue ,設(shè)置密碼>>結(jié)束五:重啟Openfire 然后登錄管理頁(yè)面,進(jìn)行Openfire管理。至此,恭喜您,Openfire部署安裝完成。配置成功如果以后ip地址變了,那肯定又是開(kāi)不了
20、,解決辦法請(qǐng)移步: 配置成功后,在服務(wù)器創(chuàng)建一個(gè)簡(jiǎn)單的用戶(hù)來(lái)測(cè)試,然后安裝spark,設(shè)置好服務(wù)器的ip與端口,使用剛才創(chuàng)建的用戶(hù)登錄,登錄OK說(shuō)明服務(wù)器成功搭建。2.客戶(hù)端配置要求(1)android 2.2平臺(tái)及以上。(2)asmack-jse.jar開(kāi)發(fā)必須包。(3)客戶(hù)端Eclispse,服務(wù)端Myeclipse IDE開(kāi)發(fā)環(huán)境。五具體實(shí)例展示1.先建一個(gè)Android項(xiàng)目。2.導(dǎo)入項(xiàng)目必須XMPP協(xié)議jar包。4通過(guò)XMPP協(xié)議規(guī)則,進(jìn)行數(shù)據(jù)通訊。最后我們就可以利用connection進(jìn)行連接,登錄,注冊(cè)最后如有錯(cuò)誤請(qǐng)包容,學(xué)習(xí)資料如有不夠深入,請(qǐng)選擇其它專(zhuān)業(yè)資料。3關(guān)于大圖片的問(wèn)題
21、:張澤華老師講過(guò) 4關(guān)于內(nèi)存優(yōu)化:不少人認(rèn)為JAVA程序,因?yàn)橛欣厥諜C(jī)制,應(yīng)該沒(méi)有內(nèi)存泄露。其實(shí)如果我們一個(gè)程序中,已經(jīng)不再使用某個(gè)對(duì)象,但是因?yàn)槿匀挥幸弥赶蛩厥掌骶蜔o(wú)法回收它,當(dāng)然該對(duì)象占用的內(nèi)存就無(wú)法被使用,這就造成了內(nèi)存泄露。如果我們的java運(yùn)行很久,而這種內(nèi)存泄露不斷的發(fā)生,最后就沒(méi)內(nèi)存可用了。當(dāng)然java的,內(nèi)存泄漏和C/C+是不一樣的。如果java程序完全結(jié)束后,它所有的對(duì)象就都不可達(dá)了,系統(tǒng)就可以對(duì)他們進(jìn)行垃圾回收,它的內(nèi)存泄露僅僅限于它本身,而不會(huì)影響整個(gè)系統(tǒng)的。C/C+的內(nèi)存泄露就比較糟糕了,它的內(nèi)存泄露是系統(tǒng)級(jí),即使該C/C+程序退出,它的泄露的內(nèi)存也無(wú)法被
22、系統(tǒng)回收,永遠(yuǎn)不可用了,除非重啟機(jī)器。Android的一個(gè)應(yīng)用程序的內(nèi)存泄露對(duì)別的應(yīng)用程序影響不大。為了能夠使得Android應(yīng)用程序安全且快速的運(yùn)行,Android的每個(gè)應(yīng)用程序都會(huì)使用一個(gè)專(zhuān)有的Dalvik虛擬機(jī)實(shí)例來(lái)運(yùn)行,它是由Zygote服務(wù)進(jìn)程孵化出來(lái)的,也就是說(shuō)每個(gè)應(yīng)用程序都是在屬于自己的進(jìn)程中運(yùn)行的。Android為不同類(lèi)型的進(jìn)程分配了不同的內(nèi)存使用上限,如果程序在運(yùn)行過(guò)程中出現(xiàn)了內(nèi)存泄漏的而造成應(yīng)用進(jìn)程使用的內(nèi)存超過(guò)了這個(gè)上限,則會(huì)被系統(tǒng)視為內(nèi)存泄漏,從而被kill掉,這使得僅僅自己的進(jìn)程被kill掉,而不會(huì)影響其他進(jìn)程(如果是system_process等系統(tǒng)進(jìn)程出問(wèn)題的話(huà),
23、則會(huì)引起系統(tǒng)重啟)。一、引用沒(méi)釋放造成的內(nèi)存泄露1.1注冊(cè)沒(méi)取消造成的內(nèi)存泄露這種Android的內(nèi)存泄露比純java的內(nèi)存泄露還要嚴(yán)重,因?yàn)槠渌恍〢ndroid程序可能引用我們的Anroid程序的對(duì)象(比如注冊(cè)機(jī)制)。即使我們的Android程序已經(jīng)結(jié)束了,但是別的引用程序仍然還有對(duì)我們的Android程序的某個(gè)對(duì)象的引用,泄露的內(nèi)存依然不能被垃圾回收。比如示例1:假設(shè)我們希望在鎖屏界面(LockScreen)中,監(jiān)聽(tīng)系統(tǒng)中的電話(huà)服務(wù)以獲取一些信息(如信號(hào)強(qiáng)度等),則可以在LockScreen中定義一個(gè)PhoneStateListener的對(duì)象,同時(shí)將它注冊(cè)到TelephonyManage
24、r服務(wù)中。對(duì)于LockScreen對(duì)象,當(dāng)需要顯示鎖屏界面的時(shí)候就會(huì)創(chuàng)建一個(gè)LockScreen對(duì)象,而當(dāng)鎖屏界面消失的時(shí)候LockScreen對(duì)象就會(huì)被釋放掉。但是如果在釋放LockScreen對(duì)象的時(shí)候忘記取消我們之前注冊(cè)的PhoneStateListener對(duì)象,則會(huì)導(dǎo)致LockScreen無(wú)法被垃圾回收。如果不斷的使鎖屏界面顯示和消失,則最終會(huì)由于大量的LockScreen對(duì)象沒(méi)有辦法被回收而引起OutOfMemory,使得system_process進(jìn)程掛掉。雖然有些系統(tǒng)程序,它本身好像是可以自動(dòng)取消注冊(cè)的(當(dāng)然不及時(shí)),但是我們還是應(yīng)該在我們的程序中明確的取消注冊(cè),程序結(jié)束時(shí)應(yīng)該把
25、所有的注冊(cè)都取消掉。1.2集合中對(duì)象沒(méi)清理造成的內(nèi)存泄露我們通常把一些對(duì)象的引用加入到了集合中,當(dāng)我們不需要該對(duì)象時(shí),并沒(méi)有把它的引用從集合中清理掉,這樣這個(gè)集合就會(huì)越來(lái)越大。如果這個(gè)集合是static的話(huà),那情況就更嚴(yán)重了。二、資源對(duì)象沒(méi)關(guān)閉造成的內(nèi)存泄露資源性對(duì)象比如(Cursor,F(xiàn)ile文件等)往往都用了一些緩沖,我們?cè)诓皇褂玫臅r(shí)候,應(yīng)該及時(shí)關(guān)閉它們,以便它們的緩沖及時(shí)回收內(nèi)存。它們的緩沖不僅存在于java虛擬機(jī)內(nèi),還存在于java虛擬機(jī)外。如果我們僅僅是把它的引用設(shè)置為null,而不關(guān)閉它們,往往會(huì)造成內(nèi)存泄露。因?yàn)橛行┵Y源性對(duì)象,比如SQLiteCursor(在析構(gòu)函數(shù)finali
26、ze(),如果我們沒(méi)有關(guān)閉它,它自己會(huì)調(diào)close()關(guān)閉),如果我們沒(méi)有關(guān)閉它,系統(tǒng)在回收它時(shí)也會(huì)關(guān)閉它,但是這樣的效率太低了。因此對(duì)于資源性對(duì)象在不使用的時(shí)候,應(yīng)該調(diào)用它的close()函數(shù),將其關(guān)閉掉,然后才置為null.在我們的程序退出時(shí)一定要確保我們的資源性對(duì)象已經(jīng)關(guān)閉。程序中經(jīng)常會(huì)進(jìn)行查詢(xún)數(shù)據(jù)庫(kù)的操作,但是經(jīng)常會(huì)有使用完畢Cursor后沒(méi)有關(guān)閉的情況。如果我們的查詢(xún)結(jié)果集比較小,對(duì)內(nèi)存的消耗不容易被發(fā)現(xiàn),只有在常時(shí)間大量操作的情況下才會(huì)復(fù)現(xiàn)內(nèi)存問(wèn)題,這樣就會(huì)給以后的測(cè)試和問(wèn)題排查帶來(lái)困難和風(fēng)險(xiǎn)。三、一些不良代碼成內(nèi)存壓力有些代碼并不造成內(nèi)存泄露,但是它們,或是對(duì)沒(méi)使用的內(nèi)存沒(méi)進(jìn)行有
27、效及時(shí)的釋放,或是沒(méi)有有效的利用已有的對(duì)象而是頻繁的申請(qǐng)新內(nèi)存,對(duì)內(nèi)存的回收和分配造成很大影響的,容易迫使虛擬機(jī)不得不給該應(yīng)用進(jìn)程分配更多的內(nèi)存,造成不必要的內(nèi)存開(kāi)支。3.1,Bitmap沒(méi)調(diào)用recycle()Bitmap對(duì)象在不使用時(shí),我們應(yīng)該先調(diào)用recycle()釋放內(nèi)存,然后才它設(shè)置為null.雖然recycle()從源碼上看,調(diào)用它應(yīng)該能立即釋放Bitmap的主要內(nèi)存,但是測(cè)試結(jié)果顯示它并沒(méi)能立即釋放內(nèi)存。但是我它應(yīng)該還是能大大的加速Bitmap的主要內(nèi)存的釋放。3.2,構(gòu)造Adapter時(shí),沒(méi)有使用緩存的 convertView以構(gòu)造ListView的BaseAdapter為例,
28、在BaseAdapter中提共了方法:public View getView(int position, View convertView, ViewGroup parent)來(lái)向ListView提供每一個(gè)item所需要的view對(duì)象。初始時(shí)ListView會(huì)從BaseAdapter中根據(jù)當(dāng)前的屏幕布局實(shí)例化一定數(shù)量的view對(duì)象,同時(shí)ListView會(huì)將這些view對(duì)象緩存起來(lái)。當(dāng)向上滾動(dòng)ListView時(shí),原先位于最上面的list item的view對(duì)象會(huì)被回收,然后被用來(lái)構(gòu)造新出現(xiàn)的最下面的list item。這個(gè)構(gòu)造過(guò)程就是由getView()方法完成的,getView()的第二個(gè)形參
29、 View convertView就是被緩存起來(lái)的list item的view對(duì)象(初始化時(shí)緩存中沒(méi)有view對(duì)象則convertView是null)。由此可以看出,如果我們不去使用convertView,而是每次都在getView()中重新實(shí)例化一個(gè)View對(duì)象的話(huà),即浪費(fèi)時(shí)間,也造成內(nèi)存垃圾,給垃圾回收增加壓力,如果垃圾回收來(lái)不及的話(huà),虛擬機(jī)將不得不給該應(yīng)用進(jìn)程分配更多的內(nèi)存,造成不必要的內(nèi)存開(kāi)支。ListView回收l(shuí)ist item的view對(duì)象的過(guò)程可以查看:view plaincopy to clipboardprint?android.widget.AbsListView.jav
30、a -> void addScrapView(View scrap) 方法。示例代碼: 1 public View getView(int position, View convertView, ViewGroup parent) 2 3 View view = new Xxx(.); 4 5 . . 6 7 return view; 8 9 修正示例代碼: Android內(nèi)存管理 1 public View getView(int position, View convertView, ViewGroup parent) 2 3 View v
31、iew = null; 4 5 if (convertView != null) 6 7 view = convertView; 8 9 populate(view, getItem(position); 10 11 . 12 13 else 14 15 view = new Xxx(.); 16 17 . 18 19 20 21 return view; 22 23 概述:在android的開(kāi)發(fā)中,要時(shí)刻主要內(nèi)存的分配和垃圾回收,因?yàn)橄到y(tǒng)為每一個(gè)dalvik虛擬機(jī)分配的內(nèi)存是有限的,在google的G1中,分配的最大堆大小只有16M,后來(lái)的機(jī)器一般都為24M,實(shí)在是少的可憐。這樣就需要我們?cè)?/p>
32、開(kāi)發(fā)過(guò)程中要時(shí)刻注意。不要因?yàn)樽约旱拇a問(wèn)題而造成OOM錯(cuò)誤。JAVA的內(nèi)存管理:大家都知道,android應(yīng)用層是由java開(kāi)發(fā)的,android的davlik虛擬機(jī)與jvm也類(lèi)似,只不過(guò)它是基于寄存器的。因此要了解android的內(nèi)存管理就必須得了解java的內(nèi)存分配和垃圾回收機(jī)制。在java中,是通過(guò)new關(guān)鍵字來(lái)為對(duì)象分配內(nèi)存的,而內(nèi)存的釋放是由垃圾收集器(GC)來(lái)回收的,工程師在開(kāi)發(fā)的過(guò)程中,不需要顯式的去管理內(nèi)存。但是這樣有可能在不知不覺(jué)中就會(huì)浪費(fèi)了很多內(nèi)存,最終導(dǎo)致java虛擬機(jī)花費(fèi)很多時(shí)間去進(jìn)行垃圾回收,更嚴(yán)重的是造成JVM的OOM。因此,java工程師還是有必要了解JAVA的
33、內(nèi)存分配和垃圾回收機(jī)制。 內(nèi)存結(jié)構(gòu)file:/C:/DOCUME1/ADMINI1/LOCALS1/Temp/ksohtml/wps_clip_image-6926.png上面這張圖是JVM的結(jié)構(gòu)圖,它主要四個(gè)部分組成:Class Loader子系統(tǒng)和執(zhí)行引擎,運(yùn)行時(shí)方法區(qū)和本地方法區(qū),我們主要來(lái)看下RUNTIME DATA AREA區(qū),也就是我們常說(shuō)的JVM內(nèi)存。從圖中可以看出,RUNTIMEDATA AREA區(qū)主要由5個(gè)部分組成:· Method Area:被裝載的class的元信息存儲(chǔ)在Method Area中,它是線(xiàn)程共享的· Heap(堆):一個(gè)java
34、虛擬機(jī)實(shí)例中只存在一個(gè)堆空間,存放一些對(duì)象信息,它是線(xiàn)程共享的· Java棧: java虛擬機(jī)直接對(duì)java棧進(jìn)行兩種操作,以幀為單位的壓棧和出棧(非線(xiàn)程共享)· 程序計(jì)數(shù)器(非線(xiàn)程共享)· 本地方法棧(非線(xiàn)程共享) JVM的垃圾回收(GC)file:/C:/DOCUME1/ADMINI1/LOCALS1/Temp/ksohtml/wps_clip_image-12485.pngJVM的垃圾原理是這樣的,它把對(duì)象分為年輕代(Young)、年老代(Tenured)、持久代(Perm),對(duì)不同生命周期的對(duì)象使用不同的垃圾回收算法。· 年輕代(You
35、ng)年輕代分為三個(gè)區(qū),一個(gè)eden區(qū),兩個(gè)Survivor區(qū)。程序中生成的大部分新的對(duì)象都在Eden區(qū)中,當(dāng)Eden區(qū)滿(mǎn)時(shí),還存活的對(duì)象將被復(fù)制到其中一個(gè)Survivor區(qū),當(dāng)此Survivor區(qū)的對(duì)象占用空間滿(mǎn)了時(shí),此區(qū)存活的對(duì)象又被復(fù)制到另外一個(gè)Survivor區(qū),當(dāng)這個(gè)Survivor區(qū)也滿(mǎn)了的時(shí)候,從第一個(gè)Survivor區(qū)復(fù)制過(guò)來(lái)的并且此時(shí)還存活的對(duì)象,將被復(fù)制到年老代。· 年老代(Tenured)年老代存放的是上面年輕代復(fù)制過(guò)來(lái)的對(duì)象,也就是在年輕代中還存活的對(duì)象,并且區(qū)滿(mǎn)了復(fù)制過(guò)來(lái)的。一般來(lái)說(shuō),年老代中的對(duì)象生命周期都比較長(zhǎng)。· 持久代(Perm)用于存放靜
36、態(tài)的類(lèi)和方法,持久代對(duì)垃圾回收沒(méi)有顯著的影響。Android中內(nèi)存泄露監(jiān)測(cè)在了解了JVM的內(nèi)存管理后,我們?cè)倩剡^(guò)頭來(lái)看看,在android中應(yīng)該怎樣來(lái)監(jiān)測(cè)內(nèi)存,從而看在應(yīng)用中是否存在內(nèi)存分配和垃圾回收問(wèn)題而造成內(nèi)存泄露情況。在android中,有一個(gè)相對(duì)來(lái)說(shuō)還不錯(cuò)的工具,可以用來(lái)監(jiān)測(cè)內(nèi)存是否存在泄露情況:DDMSHeapfile:/C:/DOCUME1/ADMINI1/LOCALS1/Temp/ksohtml/wps_clip_image-22715.png使用方法比較簡(jiǎn)單:· 選擇DDMS視圖,并打開(kāi)Devices視圖和Heap視圖· 點(diǎn)擊選擇要監(jiān)控的進(jìn)程,比如:上圖中我
37、選擇的是system_process· 選中Devices視圖界面上的"update heap" 圖標(biāo)· 點(diǎn)擊Heap視圖中的"Cause GC" 按鈕(相當(dāng)于向虛擬機(jī)發(fā)送了一次GC請(qǐng)求的操作)在Heap視圖中選擇想要監(jiān)控的Type,一般我們會(huì)觀察dataobject的 total size的變化,正常情況下total size的值會(huì)穩(wěn)定在一個(gè)有限的范圍內(nèi),也就說(shuō)程序中的代碼良好,沒(méi)有造成程序中的對(duì)象不被回收的情況。如果代碼中存在沒(méi)有釋放對(duì)象引用的情況,那么data object的total size在每次GC之后
38、都不會(huì)有明顯的回落,隨著操作次數(shù)的增加而total size也在不斷的增加。(說(shuō)明:選擇好data object后,不斷的操作應(yīng)用,這樣才可以看出total size的變化)。如果totalsize確實(shí)是在不斷增加而沒(méi)有回落,說(shuō)明程序中有沒(méi)有被釋放的資源引用。那么我們應(yīng)該怎么來(lái)定位呢?Android中內(nèi)存泄露定位Mat(memory analyzer tools)是我們常用的用來(lái)定位內(nèi)存泄露的工具,如果你使用ADT,并且安裝了MAT的eclipse插件,你需要做的是進(jìn)入DDMS視圖的Devices視圖:file:/C:/DOCUME1/ADMINI1/LOCALS1/Temp/ksohtml/
39、wps_clip_image-2165.png點(diǎn)擊"dump HPROF file"按鈕,然后使用MAT分析下載下來(lái)的文件。file:/C:/DOCUME1/ADMINI1/LOCALS1/Temp/ksohtml/wps_clip_image-6565.png 下面列出了存在的問(wèn)題,點(diǎn)擊detail進(jìn)去,會(huì)列出詳細(xì)的,可能會(huì)存在問(wèn)題的代碼:file:/C:/DOCUME1/ADMINI1/LOCALS1/Temp/ksohtml/wps_clip_image-32625.pngfile:/C:/DOCUME1/ADMINI1/LOCALS1/Temp
40、/ksohtml/wps_clip_image-21158.png關(guān)于MAT的使用可以參考: . .html這位兄弟寫(xiě)的比較詳細(xì)??偨Y(jié)不管是java還是android,都應(yīng)該了解內(nèi)存分配和垃圾回收機(jī)制,工程師要做到寫(xiě)的代碼中沒(méi)有bad code很難,關(guān)鍵是在出現(xiàn)問(wèn)題的時(shí)候該怎么去排查Android內(nèi)存優(yōu)化一、 Android的內(nèi)存機(jī)制Android的程序由Java語(yǔ)言編寫(xiě),所以Android的內(nèi)存管理與Java的內(nèi)存管理相似。程序員通過(guò)new為對(duì)象分配內(nèi)存,所有對(duì)象在java堆內(nèi)分配空間;然而對(duì)象的釋放是由垃圾回收器來(lái)完成的。CC+中的內(nèi)存機(jī)制是“誰(shuí)污染,誰(shuí)治理”,java的就比較人性化了,給
41、我們請(qǐng)了一個(gè)專(zhuān)門(mén)的清潔工(GC)。那么GC怎么能夠確認(rèn)某一個(gè)對(duì)象是不是已經(jīng)被廢棄了呢?Java采用了有向圖的原理。Java將引用關(guān)系考慮為圖的有向邊,有向邊從引用者指向引用對(duì)象。線(xiàn)程對(duì)象可以作為有向圖的起始頂點(diǎn),該圖就是從起始頂點(diǎn)開(kāi)始的一棵樹(shù),根頂點(diǎn)可以到達(dá)的對(duì)象都是有效對(duì)象,GC不會(huì)回收這些對(duì)象。如果某個(gè)對(duì)象 (連通子圖)與這個(gè)根頂點(diǎn)不可達(dá)(注意,該圖為有向圖),那么我們認(rèn)為這個(gè)(這些)對(duì)象不再被引用,可以被GC回收。二、Android的內(nèi)存溢出Android的內(nèi)存溢出是如何發(fā)生的?Android的虛擬機(jī)是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的機(jī)器為24M。因此我們所能利
42、用的內(nèi)存空間是有限的。如果我們的內(nèi)存占用超過(guò)了一定的水平就會(huì)出現(xiàn)OutOfMemory的錯(cuò)誤。為什么會(huì)出現(xiàn)內(nèi)存不夠用的情況呢?我想原因主要有兩個(gè):由于我們程序的失誤,長(zhǎng)期保持某些資源(如Context)的引用,造成內(nèi)存泄露,資源造成得不到釋放。保存了多個(gè)耗用內(nèi)存過(guò)大的對(duì)象(如Bitmap),造成內(nèi)存超出限制。三、萬(wàn)惡的staticstatic是Java中的一個(gè)關(guān)鍵字,當(dāng)用它來(lái)修飾成員變量時(shí),那么該變量就屬于該類(lèi),而不是該類(lèi)的實(shí)例。所以用static修飾的變量,它的生命周期是很長(zhǎng)的,如果用它來(lái)引用一些資源耗費(fèi)過(guò)多的實(shí)例(Context的情況最多),這時(shí)就要謹(jǐn)慎對(duì)待了。1 public class
43、 ClassName 2 3 private static Context mContext; 4 5 /省略 6 7 以上的代碼是很危險(xiǎn)的,如果將Activity賦值到么mContext的話(huà)。那么即使該Activity已經(jīng)onDestroy,但是由于仍有對(duì)象保存它的引用,因此該Activity依然不會(huì)被釋放。我們舉Android文檔中的一個(gè)例子。private static Drawable sBackground; Override protected void onCreate(Bundle state) super.onCreate(state); TextView label = n
44、ew TextView(this); label.setText("Leaks are bad"); if (sBackground = null) sBackground = getDrawable(R.drawable.large_bitmap); label.setBackgroundDrawable(sBackground); setContentView(label); sBackground是一個(gè)靜態(tài)的變量,但是我們發(fā)現(xiàn),我們并沒(méi)有顯式的保存Contex的引用,但是,當(dāng)Drawable與View連接之后,Drawable就將View設(shè)置為一個(gè)回調(diào),由于View中
45、是包含Context的引用的,所以,實(shí)際上我們依然保存了Context的引用。這個(gè)引用鏈如下:Drawable->TextView->Context所以,最終該Context也沒(méi)有得到釋放,發(fā)生了內(nèi)存泄露。如何才能有效的避免這種引用的發(fā)生呢?應(yīng)該盡量避免static成員變量引用資源耗費(fèi)過(guò)多的實(shí)例,比如Context。Context盡量使用Application Context,因?yàn)锳pplication的Context的生命周期比較長(zhǎng),引用它不會(huì)出現(xiàn)內(nèi)存泄露的問(wèn)題。使用WeakReference代替強(qiáng)引用。比如可以使用WeakReference<Context> mCo
46、ntextRef;該部分的詳細(xì)內(nèi)容也可以參考Android文檔中Article部分。四、都是線(xiàn)程惹的禍線(xiàn)程也是造成內(nèi)存泄露的一個(gè)重要的源頭。線(xiàn)程產(chǎn)生內(nèi)存泄露的主要原因在于線(xiàn)程生命周期的不可控。我們來(lái)考慮下面一段代碼。 1 public class MyActivity extends Activity 2 3 Override 4 5 public void onCreate(Bundle savedInstanceState) 6 7 super.onCreate(savedInstanceState); 8 9 setContentView(R.layout.main); 10 11 ne
47、w MyThread().start(); 12 13 14 15 16 private class MyThread extends Thread 17 18 Override 19 20 public void run() 21 22 super.run(); 23 24 /do somthing 25 26 27 28 29 30 這段代碼很平常也很簡(jiǎn)單,是我們經(jīng)常使用的形式。我們思考一個(gè)問(wèn)題:假設(shè)MyThread的run函數(shù)是一個(gè)很費(fèi)時(shí)的操作,當(dāng)我們開(kāi)啟該線(xiàn)程后,將設(shè)備的橫屏變?yōu)榱素Q屏,一般情況下當(dāng)屏幕轉(zhuǎn)換時(shí)會(huì)重新創(chuàng)建Activity,按照我們的想法,老的Activity應(yīng)該會(huì)被銷(xiāo)毀才
48、對(duì),然而事實(shí)上并非如此。由于我們的線(xiàn)程是Activity的內(nèi)部類(lèi),所以MyThread中保存了Activity的一個(gè)引用,當(dāng)MyThread的run函數(shù)沒(méi)有結(jié)束時(shí),MyThread是不會(huì)被銷(xiāo)毀的,因此它所引用的老的Activity也不會(huì)被銷(xiāo)毀,因此就出現(xiàn)了內(nèi)存泄露的問(wèn)題。file:/C:/DOCUME1/ADMINI1/LOCALS1/Temp/ksohtml/wps_clip_image-6439.png有些人喜歡用Android提供的AsyncTask,但事實(shí)上AsyncTask的問(wèn)題更加嚴(yán)重,Thread只有在run函數(shù)不結(jié)束時(shí)才出現(xiàn)這種內(nèi)存泄露問(wèn)題,然而AsyncTask內(nèi)部的實(shí)現(xiàn)機(jī)制
49、是運(yùn)用了ThreadPoolExcutor,該類(lèi)產(chǎn)生的Thread對(duì)象的生命周期是不確定的,是應(yīng)用程序無(wú)法控制的,因此如果AsyncTask作為Activity的內(nèi)部類(lèi),就更容易出現(xiàn)內(nèi)存泄露的問(wèn)題。這種線(xiàn)程導(dǎo)致的內(nèi)存泄露問(wèn)題應(yīng)該如何解決呢?將線(xiàn)程的內(nèi)部類(lèi),改為靜態(tài)內(nèi)部類(lèi)。在線(xiàn)程內(nèi)部采用弱引用保存Context引用。解決的模型如下: 1 public abstract class WeakAsyncTask<Params, Progress, Result, WeakTarget> extends 2 AsyncTask<Params, Progress, Result>
50、 3 protected WeakReference<WeakTarget> mTarget; 4 5 public WeakAsyncTask(WeakTarget target) 6 mTarget = new WeakReference<WeakTarget>(target); 7 8 9 /* inheritDoc */ 10 Override 11 protected final void onPreExecute() 12 final WeakTarget target = mTarget.get(); 13 if (target != null) 14 t
51、his.onPreExecute(target); 15 16 17 18 /* inheritDoc */ 19 Override 20 protected final Result doInBackground(Params. params) 21 final WeakTarget target = mTarget.get(); 22 if (target != null) 23 return this.doInBackground(target, params); 24 else 25 return null; 26 27 28 29 /* inheritDoc */ 30 Overri
52、de 31 protected final void onPostExecute(Result result) 32 final WeakTarget target = mTarget.get(); 33 if (target != null) 34 this.onPostExecute(target, result); 35 36 37 38 protected void onPreExecute(WeakTarget target) 39 / No default action 40 41 42 protected abstract Result doInBackground(WeakTa
53、rget target, Params. params); 43 44 protected void onPostExecute(WeakTarget target, Result result) 45 / No default action 46 47 事實(shí)上,線(xiàn)程的問(wèn)題并不僅僅在于內(nèi)存泄露,還會(huì)帶來(lái)一些災(zāi)難性的問(wèn)題。由于本文討論的是內(nèi)存問(wèn)題,所以在此不做討論。由于51cto不讓我一次傳完,說(shuō)我的字?jǐn)?shù)太多了,所以分開(kāi)傳了。五、超級(jí)大胖子Bitmap可以說(shuō)出現(xiàn)OutOfMemory問(wèn)題的絕大多數(shù)人,都是因?yàn)锽itmap的問(wèn)題。因?yàn)锽itmap占用的內(nèi)存實(shí)在是太多了,它是一個(gè)“超級(jí)大胖子”,特別是分辨率大的圖片,如果要顯示多張那問(wèn)題就更顯著了。如何解決Bitmap帶給我們的內(nèi)存問(wèn)題?及時(shí)的銷(xiāo)毀。雖然,系統(tǒng)能夠確認(rèn)Bitmap分配的內(nèi)存最終會(huì)被銷(xiāo)毀,但是由于它占用的內(nèi)存過(guò)多,所以很可能會(huì)超過(guò)java堆的限制。因此,在用完Bitmap時(shí),要及時(shí)的recycle掉。recycle并不能確定立即就會(huì)將Bitmap釋放掉,但是會(huì)給虛擬機(jī)一個(gè)暗示:“該圖片可以
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 蘇科版八年級(jí)物理下冊(cè)《第八章力與運(yùn)動(dòng)》單元檢測(cè)卷及答案
- 人教版七年級(jí)數(shù)學(xué)下冊(cè)全冊(cè)導(dǎo)學(xué)案
- 《誡子書(shū)》復(fù)習(xí)課
- 中小學(xué)機(jī)房作品管理系統(tǒng)的開(kāi)發(fā)與應(yīng)用研究
- 高一化學(xué)二第二章第二節(jié)化學(xué)能與電能練習(xí)
- 2024屆安徽省巢湖市某中學(xué)高考仿真模擬化學(xué)試卷含解析
- 2024高中地理第3章地理信息技術(shù)應(yīng)用第4節(jié)數(shù)字地球精練含解析湘教版必修3
- 2024高中物理第二章交變電流第六節(jié)變壓器達(dá)標(biāo)作業(yè)含解析粵教版選修3-2
- 2024高中語(yǔ)文第一單元以意逆志知人論世湘夫人訓(xùn)練含解析新人教版選修中國(guó)古代詩(shī)歌散文欣賞
- 綿陽(yáng)市高中2022級(jí)(2025屆)高三第二次診斷性考試(二診)歷史試卷(含答案)
- 《視頻壓縮基礎(chǔ)》課件
- 2025南方財(cái)經(jīng)全媒體集團(tuán)校園招聘63人高頻重點(diǎn)提升(共500題)附帶答案詳解
- 《A機(jī)場(chǎng)公司人力資源管理工作實(shí)踐調(diào)研報(bào)告》2600字(論文)
- 社工人才培訓(xùn)計(jì)劃實(shí)施方案
- 四年級(jí)數(shù)學(xué)(上)計(jì)算題專(zhuān)項(xiàng)練習(xí)及答案
- 6、水平四+田徑18課時(shí)大單元計(jì)劃-《雙手頭上前擲實(shí)心球》
- 軍事理論(2024年版)學(xué)習(xí)通超星期末考試答案章節(jié)答案2024年
- 青島版科學(xué)四年級(jí)下冊(cè)課程綱要
- 部編人教版六年級(jí)下冊(cè)語(yǔ)文1-6單元作文課件
- NB/T 11434.5-2023煤礦膏體充填第5部分:膠凝材料技術(shù)要求
評(píng)論
0/150
提交評(píng)論