1、java中==和equals和hashCode的區(qū)別
基本數(shù)據(jù)類型的==比較的值相等.
類的==比較的內(nèi)存的地址矾屯,即是否是同一個(gè)對(duì)象兼蕊,而equals()方法用于檢查對(duì)象的相等性。另一個(gè)不同的點(diǎn)是:如果==和equals()用于比較對(duì)象件蚕,當(dāng)兩個(gè)引用地址相同孙技,==返回true。而equals()可以返回true或者false主要取決于重寫(xiě)實(shí)現(xiàn),在不覆蓋equals的情況下排作,同比較內(nèi)存地址牵啦,原實(shí)現(xiàn)也為 == ,如String等重寫(xiě)了equals方法.
hashCode也是Object類的一個(gè)方法妄痪。返回一個(gè)離散的int型整數(shù)蕾久。在集合類操作中使用,為了提高查詢速度拌夏。(HashMap僧著,HashSet等比較是否為同一個(gè))
如果兩個(gè)對(duì)象equals,Java運(yùn)行時(shí)環(huán)境會(huì)認(rèn)為他們的hashcode一定相等障簿。
如果兩個(gè)對(duì)象不equals盹愚,他們的hashcode有可能相等。
如果兩個(gè)對(duì)象hashcode相等站故,他們不一定equals皆怕。
如果兩個(gè)對(duì)象hashcode不相等,他們一定不equals西篓。
2愈腾、int與integer的區(qū)別
int 基本類型
integer 對(duì)象 int的封裝類
3、String岂津、StringBuffer虱黄、StringBuilder區(qū)別
String:字符串常量 不適用于經(jīng)常要改變值得情況,每次改變相當(dāng)于生成一個(gè)新的對(duì)象
StringBuffer:字符串變量 (線程安全)
StringBuilder:字符串變量(線程不安全) 確保單線程下可用吮成,效率略高于StringBuffer
4橱乱、什么是內(nèi)部類??jī)?nèi)部類的作用
內(nèi)部類可直接訪問(wèn)外部類的屬性
Java中內(nèi)部類主要分為成員內(nèi)部類粱甫、局部?jī)?nèi)部類(嵌套在方法和作用域內(nèi))泳叠、匿名內(nèi)部類(沒(méi)構(gòu)造方法)、靜態(tài)內(nèi)部類(static修飾的類茶宵,不能使用任何外圍類的非static成員變量和方法危纫, 不依賴外圍類)
5、進(jìn)程和線程的區(qū)別
進(jìn)程是cpu資源分配的最小單位,線程是cpu調(diào)度的最小單位种蝶。
進(jìn)程之間不能共享資源契耿,而線程共享所在進(jìn)程的地址空間和其它資源。
一個(gè)進(jìn)程內(nèi)可擁有多個(gè)線程蛤吓,進(jìn)程可開(kāi)啟進(jìn)程宵喂,也可開(kāi)啟線程糠赦。
一個(gè)線程只能屬于一個(gè)進(jìn)程会傲,線程可直接使用同進(jìn)程的資源,線程依賴于進(jìn)程而存在。
6拙泽、final淌山,finally,finalize的區(qū)別
final:修飾類顾瞻、成員變量和成員方法泼疑,類不可被繼承,成員變量不可變荷荤,成員方法不可重寫(xiě)
finally:與try...catch...共同使用退渗,確保無(wú)論是否出現(xiàn)異常都能被調(diào)用到
finalize:類的方法,垃圾回收之前會(huì)調(diào)用此方法,子類可以重寫(xiě)finalize()方法實(shí)現(xiàn)對(duì)資源的回收
7、Serializable 和Parcelable 的區(qū)別
Serializable Java 序列化接口 在硬盤(pán)上讀寫(xiě) 讀寫(xiě)過(guò)程中有大量臨時(shí)變量的生成蕴纳,內(nèi)部執(zhí)行大量的i/o操作会油,效率很低。
Parcelable Android 序列化接口 效率高 使用麻煩 在內(nèi)存中讀寫(xiě)(AS有相關(guān)插件 一鍵生成所需方法) 古毛,對(duì)象不能保存到磁盤(pán)中
8翻翩、靜態(tài)屬性和靜態(tài)方法是否可以被繼承?是否可以被重寫(xiě)稻薇?以及原因嫂冻?
可繼承 不可重寫(xiě) 而是被隱藏
如果子類里面定義了靜態(tài)方法和屬性,那么這時(shí)候父類的靜態(tài)方法或?qū)傩苑Q之為"隱藏"塞椎。如果你想要調(diào)用父類的靜態(tài)方法和屬性桨仿,直接通過(guò)父類名.方法或變量名完成。
9案狠、成員內(nèi)部類蹬敲、靜態(tài)內(nèi)部類、局部?jī)?nèi)部類和匿名內(nèi)部類的理解莺戒,以及項(xiàng)目中的應(yīng)用
java中內(nèi)部類主要分為成員內(nèi)部類伴嗡、局部?jī)?nèi)部類(嵌套在方法和作用域內(nèi))、匿名內(nèi)部類(沒(méi)構(gòu)造方法)从铲、靜態(tài)內(nèi)部類(static修飾的類瘪校,不能使用任何外圍類的非static成員變量和方法, 不依賴外圍類)
使用內(nèi)部類最吸引人的原因是:每個(gè)內(nèi)部類都能獨(dú)立地繼承一個(gè)(接口的)實(shí)現(xiàn),所以無(wú)論外圍類是否已經(jīng)繼承了某個(gè)(接口的)實(shí)現(xiàn)阱扬,對(duì)于內(nèi)部類都沒(méi)有影響泣懊。
因?yàn)镴ava不支持多繼承,支持實(shí)現(xiàn)多個(gè)接口麻惶。但有時(shí)候會(huì)存在一些使用接口很難解決的問(wèn)題馍刮,這個(gè)時(shí)候我們可以利用內(nèi)部類提供的、可以繼承多個(gè)具體的或者抽象的類的能力來(lái)解決這些程序設(shè)計(jì)問(wèn)題窃蹋】▎可以這樣說(shuō),接口只是解決了部分問(wèn)題警没,而內(nèi)部類使得多重繼承的解決方案變得更加完整匈辱。
10、string 轉(zhuǎn)換成 integer的方式及原理
String ?integer Intrger.parseInt(string);
Integer?string Integer.toString();
原理
integer.parseInt(string str)方法調(diào)用Integer內(nèi)部的
parseInt(string str,10)方法,默認(rèn)基數(shù)為10杀迹,parseInt內(nèi)部首先
判斷字符串是否包含符號(hào)(-或者+)亡脸,則對(duì)相應(yīng)的negative和limit進(jìn)行
賦值,然后再循環(huán)字符串树酪,對(duì)單個(gè)char進(jìn)行數(shù)值計(jì)算Character.digit(char ch, int radix)
在這個(gè)方法中浅碾,函數(shù)肯定進(jìn)入到0-9字符的判斷(相對(duì)于string轉(zhuǎn)換到int),
否則會(huì)拋出異常续语,數(shù)字就是如上面進(jìn)行拼接然后生成的int類型數(shù)值垂谢。
11、哪些情況下的對(duì)象會(huì)被垃圾回收機(jī)制處理掉绵载?
1.所有實(shí)例都沒(méi)有活動(dòng)線程訪問(wèn)埂陆。
2.沒(méi)有被其他任何實(shí)例訪問(wèn)的循環(huán)引用實(shí)例。
3.Java 中有不同的引用類型娃豹。判斷實(shí)例是否符合垃圾收集的條件都依賴于它的引用類型焚虱。
要判斷怎樣的對(duì)象是沒(méi)用的對(duì)象。這里有2種方法:
1.采用標(biāo)記計(jì)數(shù)的方法:
給內(nèi)存中的對(duì)象給打上標(biāo)記懂版,對(duì)象被引用一次鹃栽,計(jì)數(shù)就加1,引用被釋放了躯畴,計(jì)數(shù)就減一民鼓,當(dāng)這個(gè)計(jì)數(shù)為0的時(shí)候,這個(gè)對(duì)象就可以被回收了蓬抄。當(dāng)然丰嘉,這也就引發(fā)了一個(gè)問(wèn)題:循環(huán)引用的對(duì)象是無(wú)法被識(shí)別出來(lái)并且被回收的。所以就有了第二種方法:
2.采用根搜索算法:
從一個(gè)根出發(fā)嚷缭,搜索所有的可達(dá)對(duì)象饮亏,這樣剩下的那些對(duì)象就是需要被回收的
14耍贾、Java中實(shí)現(xiàn)多態(tài)的機(jī)制是什么?
答:方法的重寫(xiě)Overriding和重載Overloading是Java多態(tài)性的不同表現(xiàn)
重寫(xiě)Overriding是父類與子類之間多態(tài)性的一種表現(xiàn)
重載Overloading是一個(gè)類中多態(tài)性的一種表現(xiàn).
16路幸、說(shuō)說(shuō)你對(duì)Java反射的理解
JAVA反射機(jī)制是在運(yùn)行狀態(tài)中, 對(duì)于任意一個(gè)類, 都能夠知道這個(gè)類的所有屬性和方法; 對(duì)于任意一個(gè)對(duì)象, 都能夠調(diào)用它的任意一個(gè)方法和屬性荐开。 從對(duì)象出發(fā),通過(guò)反射(Class類)可以取得取得類的完整信息(類名 Class類型简肴,所在包晃听、具有的所有方法 Method[]類型、某個(gè)方法的完整信息(包括修飾符砰识、返回值類型能扒、異常、參數(shù)類型)仍翰、所有屬性 Field[]赫粥、某個(gè)屬性的完整信息观话、構(gòu)造器 Constructors)予借,調(diào)用類的屬性或方法自己的總結(jié): 在運(yùn)行過(guò)程中獲得類、對(duì)象频蛔、方法的所有信息灵迫。
17、說(shuō)說(shuō)你對(duì)Java注解的理解
元注解
元注解的作用就是負(fù)責(zé)注解其他注解晦溪。java5.0的時(shí)候瀑粥,定義了4個(gè)標(biāo)準(zhǔn)的meta-annotation類型,它們用來(lái)提供對(duì)其他注解的類型作說(shuō)明三圆。
1.@Target
2.@Retention
3.@Documented
4.@Inherited
18狞换、Java中String的了解
在源碼中string是用final 進(jìn)行修飾,它是不可更改邮旷,不可繼承的常量蜂厅。
19喊巍、String為什么要設(shè)計(jì)成不可變的?
1黄琼、字符串池的需求
字符串池是方法區(qū)(Method Area)中的一塊特殊的存儲(chǔ)區(qū)域。當(dāng)一個(gè)字符串已經(jīng)被創(chuàng)建并且該字符串在 池 中整慎,該字符串的引用會(huì)立即返回給變量脏款,而不是重新創(chuàng)建一個(gè)字符串再將引用返回給變量。如果字符串不是不可變的裤园,那么改變一個(gè)引用(如: string2)的字符串將會(huì)導(dǎo)致另一個(gè)引用(如: string1)出現(xiàn)臟數(shù)據(jù)撤师。
2、允許字符串緩存哈希碼
在java中常常會(huì)用到字符串的哈希碼拧揽,例如: HashMap 剃盾。String的不變性保證哈希碼始終一,因此,他可以不用擔(dān)心變化的出現(xiàn)万俗。 這種方法意味著不必每次使用時(shí)都重新計(jì)算一次哈希碼——這樣湾笛,效率會(huì)高很多。
3闰歪、安全
String廣泛的用于java 類中的參數(shù)嚎研,如:網(wǎng)絡(luò)連接(Network connetion),打開(kāi)文件(opening files )等等库倘。如果String不是不可變的临扮,網(wǎng)絡(luò)連接、文件將會(huì)被改變——這將會(huì)導(dǎo)致一系列的安全威脅教翩。操作的方法本以為連接上了一臺(tái)機(jī)器杆勇,但實(shí)際上卻不是。由于反射中的參數(shù)都是字符串饱亿,同樣蚜退,也會(huì)引起一系列的安全問(wèn)題。
20彪笼、Object類的equal和hashCode方法重寫(xiě)钻注,為什么?
首先equals與hashcode間的關(guān)系是這樣的:
1配猫、如果兩個(gè)對(duì)象相同(即用equals比較返回true)幅恋,那么它們的hashCode值一定要相同;
2泵肄、如果兩個(gè)對(duì)象的hashCode相同捆交,它們并不一定相同(即用equals比較返回false)
由于為了提高程序的效率才實(shí)現(xiàn)了hashcode方法,先進(jìn)行hashcode的比較腐巢,如果不同品追,那沒(méi)就不必在進(jìn)行equals的比較了,這樣就大大減少了equals比較的次數(shù)系忙,這對(duì)比需要比較的數(shù)量很大的效率提高是很明顯的
21诵盼、List,Set,Map的區(qū)別
Set是最簡(jiǎn)單的一種集合。集合中的對(duì)象不按特定的方式排序银还,并且沒(méi)有重復(fù)對(duì)象风宁。 Set接口主要實(shí)現(xiàn)了兩個(gè)實(shí)現(xiàn)類:HashSet: HashSet類按照哈希算法來(lái)存取集合中的對(duì)象,存取速度比較快
TreeSet :TreeSet類實(shí)現(xiàn)了SortedSet接口蛹疯,能夠?qū)现械膶?duì)象進(jìn)行排序戒财。
List的特征是其元素以線性方式存儲(chǔ),集合中可以存放重復(fù)對(duì)象捺弦。
ArrayList() : 代表長(zhǎng)度可以改變得數(shù)組饮寞⌒⒖福可以對(duì)元素進(jìn)行隨機(jī)的訪問(wèn),向ArrayList()中插入與刪除元素的速度慢幽崩。
LinkedList(): 在實(shí)現(xiàn)中采用鏈表數(shù)據(jù)結(jié)構(gòu)苦始。插入和刪除速度快,訪問(wèn)速度慢慌申。
Map 是一種把鍵對(duì)象和值對(duì)象映射的集合陌选,它的每一個(gè)元素都包含一對(duì)鍵對(duì)象和值對(duì)象。 Map沒(méi)有繼承于Collection接口 從Map集合中檢索元素時(shí)蹄溉,只要給出鍵對(duì)象咨油,就會(huì)返回對(duì)應(yīng)的值對(duì)象。
HashMap:Map基于散列表的實(shí)現(xiàn)柒爵。插入和查詢“鍵值對(duì)”的開(kāi)銷(xiāo)是固定的役电。可以通過(guò)構(gòu)造器設(shè)置容量capacity和負(fù)載因子load factor棉胀,以調(diào)整容器的性能法瑟。
LinkedHashMap: 類似于HashMap,但是迭代遍歷它時(shí)膏蚓,取得“鍵值對(duì)”的順序是其插入次序瓢谢,或者是最近最少使用(LRU)的次序畸写。只比HashMap慢一點(diǎn)驮瞧。而在迭代訪問(wèn)時(shí)發(fā)而更快,因?yàn)樗褂面湵砭S護(hù)內(nèi)部次序枯芬。
TreeMap : 基于紅黑樹(shù)數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)论笔。查看“鍵”或“鍵值對(duì)”時(shí),它們會(huì)被排序(次序由Comparabel或Comparator決定)千所。TreeMap的特點(diǎn)在 于狂魔,你得到的結(jié)果是經(jīng)過(guò)排序的。TreeMap是唯一的帶有subMap()方法的Map淫痰,它可以返回一個(gè)子樹(shù)最楷。
WeakHashMao :弱鍵(weak key)Map,Map中使用的對(duì)象也被允許釋放: 這是為解決特殊問(wèn)題設(shè)計(jì)的待错。如果沒(méi)有map之外的引用指向某個(gè)“鍵”籽孙,則此“鍵”可以被垃圾收集器回收。
26火俄、ArrayMap和HashMap的對(duì)比
1犯建、存儲(chǔ)方式不同
HashMap內(nèi)部有一個(gè)HashMapEntry<K, V>[]對(duì)象,每一個(gè)鍵值對(duì)都存儲(chǔ)在這個(gè)對(duì)象里瓜客,當(dāng)使用put方法添加鍵值對(duì)時(shí)适瓦,就會(huì)new一個(gè)HashMapEntry對(duì)象竿开,
2、添加數(shù)據(jù)時(shí)擴(kuò)容時(shí)的處理不一樣玻熙,進(jìn)行了new操作否彩,重新創(chuàng)建對(duì)象,開(kāi)銷(xiāo)很大嗦随。ArrayMap用的是copy數(shù)據(jù)胳搞,所以效率相對(duì)要高。
3称杨、ArrayMap提供了數(shù)組收縮的功能肌毅,在clear或remove后,會(huì)重新收縮數(shù)組姑原,是否空間
4悬而、ArrayMap采用二分法查找;
29锭汛、HashMap和HashTable的區(qū)別
1 HashMap不是線程安全的笨奠,效率高一點(diǎn)、方法不是Synchronize的要提供外同步唤殴,有containsvalue和containsKey方法般婆。
hashtable是,線程安全朵逝,不允許有null的鍵和值蔚袍,效率稍低,方法是是Synchronize的配名。有contains方法方法啤咽。Hashtable 繼承于Dictionary 類
30、HashMap與HashSet的區(qū)別
hashMap:HashMap實(shí)現(xiàn)了Map接口,HashMap儲(chǔ)存鍵值對(duì),使用put()方法將元素放入map中,HashMap中使用鍵對(duì)象來(lái)計(jì)算hashcode值,HashMap比較快渠脉,因?yàn)槭鞘褂梦ㄒ坏逆I來(lái)獲取對(duì)象宇整。
HashSet實(shí)現(xiàn)了Set接口,HashSet僅僅存儲(chǔ)對(duì)象芋膘,使用add()方法將元素放入set中鳞青,HashSet使用成員對(duì)象來(lái)計(jì)算hashcode值,對(duì)于兩個(gè)對(duì)象來(lái)說(shuō)hashcode可能相同为朋,所以equals()方法用來(lái)判斷對(duì)象的相等性臂拓,如果兩個(gè)對(duì)象不同的話,那么返回false潜腻。HashSet較HashMap來(lái)說(shuō)比較慢埃儿。
31、HashSet與HashMap怎么判斷集合元素重復(fù)融涣?
HashSet不能添加重復(fù)的元素童番,當(dāng)調(diào)用add(Object)方法時(shí)候精钮,
首先會(huì)調(diào)用Object的hashCode方法判hashCode是否已經(jīng)存在,如不存在則直接插入元素剃斧;如果已存在則調(diào)用Object對(duì)象的equals方法判斷是否返回true轨香,如果為true則說(shuō)明元素已經(jīng)存在,如為false則插入元素幼东。
33臂容、ArrayList和LinkedList的區(qū)別,以及應(yīng)用場(chǎng)景
ArrayList是基于數(shù)組實(shí)現(xiàn)的根蟹,ArrayList線程不安全脓杉。
LinkedList是基于雙鏈表實(shí)現(xiàn)的:
使用場(chǎng)景:
(1)如果應(yīng)用程序?qū)Ω鱾€(gè)索引位置的元素進(jìn)行大量的存取或刪除操作,ArrayList對(duì)象要遠(yuǎn)優(yōu)于LinkedList對(duì)象简逮;
( 2 ) 如果應(yīng)用程序主要是對(duì)列表進(jìn)行循環(huán)球散,并且循環(huán)時(shí)候進(jìn)行插入或者刪除操作,LinkedList對(duì)象要遠(yuǎn)優(yōu)于ArrayList對(duì)象散庶;
34蕉堰、數(shù)組和鏈表的區(qū)別
數(shù)組:是將元素在內(nèi)存中連續(xù)存儲(chǔ)的;它的優(yōu)點(diǎn):因?yàn)閿?shù)據(jù)是連續(xù)存儲(chǔ)的悲龟,內(nèi)存地址連續(xù)屋讶,所以在查找數(shù)據(jù)的時(shí)候效率比較高;它的缺點(diǎn):在存儲(chǔ)之前须教,我們需要申請(qǐng)一塊連續(xù)的內(nèi)存空間皿渗,并且在編譯的時(shí)候就必須確定好它的空間的大小。在運(yùn)行的時(shí)候空間的大小是無(wú)法隨著你的需要進(jìn)行增加和減少而改變的没卸,當(dāng)數(shù)據(jù)兩比較大的時(shí)候羹奉,有可能會(huì)出現(xiàn)越界的情況,數(shù)據(jù)比較小的時(shí)候约计,又有可能會(huì)浪費(fèi)掉內(nèi)存空間。在改變數(shù)據(jù)個(gè)數(shù)時(shí)迁筛,增加煤蚌、插入、刪除數(shù)據(jù)效率比較低细卧。
鏈表:是動(dòng)態(tài)申請(qǐng)內(nèi)存空間尉桩,不需要像數(shù)組需要提前申請(qǐng)好內(nèi)存的大小,鏈表只需在用的時(shí)候申請(qǐng)就可以贪庙,根據(jù)需要來(lái)動(dòng)態(tài)申請(qǐng)或者刪除內(nèi)存空間蜘犁,對(duì)于數(shù)據(jù)增加和刪除以及插入比數(shù)組靈活。還有就是鏈表中數(shù)據(jù)在內(nèi)存中可以在任意的位置止邮,通過(guò)應(yīng)用來(lái)關(guān)聯(lián)數(shù)據(jù)(就是通過(guò)存在元素的指針來(lái)聯(lián)系)
35这橙、開(kāi)啟線程的三種方式奏窑?
ava有三種創(chuàng)建線程的方式,分別是繼承Thread類屈扎、實(shí)現(xiàn)Runable接口和使用線程池
36埃唯、線程和進(jìn)程的區(qū)別?
線程是進(jìn)程的子集鹰晨,一個(gè)進(jìn)程可以有很多線程墨叛,每條線程并行執(zhí)行不同的任務(wù)。不同的進(jìn)程使用不同的內(nèi)存空間模蜡,而所有的線程共享一片相同的內(nèi)存空間漠趁。別把它和棧內(nèi)存搞混,每個(gè)線程都擁有單獨(dú)的棧內(nèi)存用來(lái)存儲(chǔ)本地?cái)?shù)據(jù)忍疾。
38棚潦、run()和start()方法區(qū)別
這個(gè)問(wèn)題經(jīng)常被問(wèn)到,但還是能從此區(qū)分出面試者對(duì)Java線程模型的理解程度膝昆。start()方法被用來(lái)啟動(dòng)新創(chuàng)建的線程丸边,而且start()內(nèi)部調(diào)用了run()方法,這和直接調(diào)用run()方法的效果不一樣荚孵。當(dāng)你調(diào)用run()方法的時(shí)候妹窖,只會(huì)是在原來(lái)的線程中調(diào)用,沒(méi)有新的線程啟動(dòng)收叶,start()方法才會(huì)啟動(dòng)新線程骄呼。
39、如何控制某個(gè)方法允許并發(fā)訪問(wèn)線程的個(gè)數(shù)判没?
semaphore.acquire() 請(qǐng)求一個(gè)信號(hào)量蜓萄,這時(shí)候的信號(hào)量個(gè)數(shù)-1(一旦沒(méi)有可使用的信號(hào)量,也即信號(hào)量個(gè)數(shù)變?yōu)樨?fù)數(shù)時(shí)澄峰,再次請(qǐng)求的時(shí)候就會(huì)阻塞嫉沽,直到其他線程釋放了信號(hào)量)
semaphore.release() 釋放一個(gè)信號(hào)量,此時(shí)信號(hào)量個(gè)數(shù)+1
40俏竞、在Java中wait和seelp方法的不同绸硕;
Java程序中wait 和 sleep都會(huì)造成某種形式的暫停,它們可以滿足不同的需要魂毁。wait()方法用于線程間通信玻佩,如果等待條件為真且其它線程被喚醒時(shí)它會(huì)釋放鎖,而sleep()方法僅僅釋放CPU資源或者讓當(dāng)前線程停止執(zhí)行一段時(shí)間席楚,但不會(huì)釋放鎖咬崔。
41、談?wù)剋ait/notify關(guān)鍵字的理解
等待對(duì)象的同步鎖,需要獲得該對(duì)象的同步鎖才可以調(diào)用這個(gè)方法,否則編譯可以通過(guò)烦秩,但運(yùn)行時(shí)會(huì)收到一個(gè)異常:IllegalMonitorStateException垮斯。
調(diào)用任意對(duì)象的 wait() 方法導(dǎo)致該線程阻塞郎仆,該線程不可繼續(xù)執(zhí)行,并且該對(duì)象上的鎖被釋放甚脉。
喚醒在等待該對(duì)象同步鎖的線程(只喚醒一個(gè),如果有多個(gè)在等待),注意的是在調(diào)用此方法的時(shí)候丸升,并不能確切的喚醒某一個(gè)等待狀態(tài)的線程,而是由JVM確定喚醒哪個(gè)線程牺氨,而且不是按優(yōu)先級(jí)狡耻。
調(diào)用任意對(duì)象的notify()方法則導(dǎo)致因調(diào)用該對(duì)象的 wait()方法而阻塞的線程中隨機(jī)選擇的一個(gè)解除阻塞(但要等到獲得鎖后才真正可執(zhí)行)。
42猴凹、什么導(dǎo)致線程阻塞夷狰?線程如何關(guān)閉?
阻塞式方法是指程序會(huì)一直等待該方法完成期間不做其他事情郊霎,ServerSocket的accept()方法就是一直等待客戶端連接沼头。這里的阻塞是指調(diào)用結(jié)果返回之前,當(dāng)前線程會(huì)被掛起书劝,直到得到結(jié)果之后才會(huì)返回进倍。此外,還有異步和非阻塞式方法在任務(wù)完成前就返回购对。
一種是調(diào)用它里面的stop()方法
另一種就是你自己設(shè)置一個(gè)停止線程的標(biāo)記 (推薦這種)
43猾昆、如何保證線程安全?
1.synchronized骡苞;
2.Object方法中的wait,notify垂蜗;
3.ThreadLocal機(jī)制 來(lái)實(shí)現(xiàn)的。
4###4解幽、如何實(shí)現(xiàn)線程同步贴见?
1、synchronized關(guān)鍵字修改的方法躲株。2片部、synchronized關(guān)鍵字修飾的語(yǔ)句塊3、使用特殊域變量(volatile)實(shí)現(xiàn)線程同步
45徘溢、線程間操作List
List list = Collections.synchronizedList(new ArrayList());
46吞琐、談?wù)剬?duì)Synchronized關(guān)鍵字,類鎖然爆,方法鎖,重入鎖的理解
java的對(duì)象鎖和類鎖:java的對(duì)象鎖和類鎖在鎖的概念上基本上和內(nèi)置鎖是一致的黍图,但是曾雕,兩個(gè)鎖實(shí)際是有很大的區(qū)別的,對(duì)象鎖是用于對(duì)象實(shí)例方法助被,或者一個(gè)對(duì)象實(shí)例上的剖张,類鎖是用于類的靜態(tài)方法或者一個(gè)類的class對(duì)象上的切诀。我們知道,類的對(duì)象實(shí)例可以有很多個(gè)搔弄,但是每個(gè)類只有一個(gè)class對(duì)象幅虑,所以不同對(duì)象實(shí)例的對(duì)象鎖是互不干擾的,但是每個(gè)類只有一個(gè)類鎖顾犹。但是有一點(diǎn)必須注意的是倒庵,其實(shí)類鎖只是一個(gè)概念上的東西,并不是真實(shí)存在的炫刷,它只是用來(lái)幫助我們理解鎖定實(shí)例方法和靜態(tài)方法的區(qū)別的
49擎宝、synchronized 和volatile 關(guān)鍵字的區(qū)別
1.volatile本質(zhì)是在告訴jvm當(dāng)前變量在寄存器(工作內(nèi)存)中的值是不確定的,需要從主存中讀然肼辍绍申;synchronized則是鎖定當(dāng)前變量,只有當(dāng)前線程可以訪問(wèn)該變量顾彰,其他線程被阻塞住极阅。
2.volatile僅能使用在變量級(jí)別;synchronized則可以使用在變量涨享、方法筋搏、和類級(jí)別的
3.volatile僅能實(shí)現(xiàn)變量的修改可見(jiàn)性,不能保證原子性灰伟;而synchronized則可以保證變量的修改可見(jiàn)性和原子性
4.volatile不會(huì)造成線程的阻塞拆又;synchronized可能會(huì)造成線程的阻塞。
5.volatile標(biāo)記的變量不會(huì)被編譯器優(yōu)化栏账;synchronized標(biāo)記的變量可以被編譯器優(yōu)化
51帖族、ReentrantLock 、synchronized和volatile比較
ava在過(guò)去很長(zhǎng)一段時(shí)間只能通過(guò)synchronized關(guān)鍵字來(lái)實(shí)現(xiàn)互斥挡爵,它有一些缺點(diǎn)竖般。比如你不能擴(kuò)展鎖之外的方法或者塊邊界,嘗試獲取鎖時(shí)不能中途取消等茶鹃。Java 5 通過(guò)Lock接口提供了更復(fù)雜的控制來(lái)解決這些問(wèn)題涣雕。 ReentrantLock 類實(shí)現(xiàn)了 Lock,它擁有與 synchronized 相同的并發(fā)性和內(nèi)存語(yǔ)義且它還具有可擴(kuò)展性闭翩。
53挣郭、死鎖的四個(gè)必要條件?
死鎖產(chǎn)生的原因
- 系統(tǒng)資源的競(jìng)爭(zhēng)
系統(tǒng)資源的競(jìng)爭(zhēng)導(dǎo)致系統(tǒng)資源不足疗韵,以及資源分配不當(dāng)兑障,導(dǎo)致死鎖。
- 進(jìn)程運(yùn)行推進(jìn)順序不合適
互斥條件:一個(gè)資源每次只能被一個(gè)進(jìn)程使用,即在一段時(shí)間內(nèi)某 資源僅為一個(gè)進(jìn)程所占有流译。此時(shí)若有其他進(jìn)程請(qǐng)求該資源逞怨,則請(qǐng)求進(jìn)程只能等待。
請(qǐng)求與保持條件:進(jìn)程已經(jīng)保持了至少一個(gè)資源福澡,但又提出了新的資源請(qǐng)求叠赦,而該資源 已被其他進(jìn)程占有,此時(shí)請(qǐng)求進(jìn)程被阻塞革砸,但對(duì)自己已獲得的資源保持不放除秀。
不可剝奪條件:進(jìn)程所獲得的資源在未使用完畢之前,不能被其他進(jìn)程強(qiáng)行奪走业岁,即只能 由獲得該資源的進(jìn)程自己來(lái)釋放(只能是主動(dòng)釋放)鳞仙。
循環(huán)等待條件: 若干進(jìn)程間形成首尾相接循環(huán)等待資源的關(guān)系
這四個(gè)條件是死鎖的必要條件,只要系統(tǒng)發(fā)生死鎖笔时,這些條件必然成立棍好,而只要上述條件之一不滿足,就不會(huì)發(fā)生死鎖允耿。
死鎖的避免與預(yù)防:
死鎖避免的基本思想:
系統(tǒng)對(duì)進(jìn)程發(fā)出每一個(gè)系統(tǒng)能夠滿足的資源申請(qǐng)進(jìn)行動(dòng)態(tài)檢查,并根據(jù)檢查結(jié)果決定是否分配資源,如果分配后系統(tǒng)可能發(fā)生死鎖,則不予分配,否則予以分配借笙。這是一種保證系統(tǒng)不進(jìn)入死鎖狀態(tài)的動(dòng)態(tài)策略。
理解了死鎖的原因较锡,尤其是產(chǎn)生死鎖的四個(gè)必要條件业稼,就可以最大可能地避免族檬、預(yù)防和解除死鎖翘魄。所以杂靶,在系統(tǒng)設(shè)計(jì)怎静、進(jìn)程調(diào)度等方面注意如何讓這四個(gè)必要條件不成立,如何確定資源的合理分配算法淡喜,避免進(jìn)程永久占據(jù)系統(tǒng)資源依痊。此外素跺,也要防止進(jìn)程在處于等待狀態(tài)的情況下占用資源鸟整。因此引镊,對(duì)資源的分配要給予合理的規(guī)劃。
死鎖避免和死鎖預(yù)防的區(qū)別:
死鎖預(yù)防是設(shè)法至少破壞產(chǎn)生死鎖的四個(gè)必要條件之一,嚴(yán)格的防止死鎖的出現(xiàn),而死鎖避免則不那么嚴(yán)格的限制產(chǎn)生死鎖的必要條件的存在,因?yàn)榧词顾梨i的必要條件存在,也不一定發(fā)生死鎖篮条。死鎖避免是在系統(tǒng)運(yùn)行過(guò)程中注意避免死鎖的最終發(fā)生弟头。
56、什么是線程池涉茧,如何使用?
創(chuàng)建線程要花費(fèi)昂貴的資源和時(shí)間赴恨,如果任務(wù)來(lái)了才創(chuàng)建線程那么響應(yīng)時(shí)間會(huì)變長(zhǎng),而且一個(gè)進(jìn)程能創(chuàng)建的線程數(shù)有限伴栓。為了避免這些問(wèn)題嘱支,在程序啟動(dòng)的時(shí)候就創(chuàng)建若干線程來(lái)響應(yīng)處理蚓胸,它們被稱為線程池挣饥,里面的線程叫工作線程除师。從JDK1.5開(kāi)始,Java API提供了Executor框架讓你可以創(chuàng)建不同的線程池扔枫。比如單線程池汛聚,每次處理一個(gè)任務(wù);數(shù)目固定的線程池或者是緩存線程池(一個(gè)適合很多生存期短的任務(wù)的程序的可擴(kuò)展線程池)短荐。
57倚舀、Java中堆和棧有什么不同?
為什么把這個(gè)問(wèn)題歸類在多線程和并發(fā)面試題里忍宋?因?yàn)闂J且粔K和線程緊密相關(guān)的內(nèi)存區(qū)域痕貌。每個(gè)線程都有自己的棧內(nèi)存,用于存儲(chǔ)本地變量舵稠,方法參數(shù)和棧調(diào)用,一個(gè)線程中存儲(chǔ)的變量對(duì)其它線程是不可見(jiàn)的入宦。而堆是所有線程共享的一片公用內(nèi)存區(qū)域哺徊。對(duì)象都在堆里創(chuàng)建,為了提升效率線程會(huì)從堆中弄一個(gè)緩存到自己的棧乾闰,如果多個(gè)線程使用該變量就可能引發(fā)問(wèn)題落追,這時(shí)volatile 變量就可以發(fā)揮作用了,它要求線程從主存中讀取變量的值涯肩。
58轿钠、有三個(gè)線程T1,T2病苗,T3疗垛,怎么確保它們按順序執(zhí)行?
在多線程中有多種方法讓線程按特定順序執(zhí)行铅乡,你可以用線程類的join()方法在一個(gè)線程中啟動(dòng)另一個(gè)線程继谚,另外一個(gè)線程完成該線程繼續(xù)執(zhí)行。為了確保三個(gè)線程的順序你應(yīng)該先啟動(dòng)最后一個(gè)(T3調(diào)用T2阵幸,T2調(diào)用T1)花履,這樣T1就會(huì)先完成而T3最后完成。
線程間通信
我們知道線程是CPU調(diào)度的最小單位挚赊。在Android中主線程是不能夠做耗時(shí)操作的诡壁,子線程是不能夠更新UI的。而線程間通信的方式有很多荠割,比如廣播妹卿,Eventbus旺矾,接口回掉,在Android中主要是使用handler夺克。handler通過(guò)調(diào)用sendmessage方法箕宙,將保存消息的Message發(fā)送到Messagequeue中,而looper對(duì)象不斷的調(diào)用loop方法铺纽,從messageueue中取出message柬帕,交給handler處理,從而完成線程間通信狡门。
線程池
Android中常見(jiàn)的線程池有四種陷寝,F(xiàn)ixedThreadPool、CachedThreadPool其馏、ScheduledThreadPool凤跑、SingleThreadExecutor。
FixedThreadPool線程池是通過(guò)Executors的new FixedThreadPool方法來(lái)創(chuàng)建叛复。它的特點(diǎn)是該線程池中的線程數(shù)量是固定的仔引。即使線程處于閑置的狀態(tài),它們也不會(huì)被回收致扯,除非線程池被關(guān)閉肤寝。當(dāng)所有的線程都處于活躍狀態(tài)的時(shí)候,新任務(wù)就處于隊(duì)列中等待線程來(lái)處理抖僵。注意鲤看,F(xiàn)ixedThreadPool只有核心線程,沒(méi)有非核心線程耍群。
CachedThreadPool線程池是通過(guò)Executors的newCachedThreadPool進(jìn)行創(chuàng)建的义桂。它是一種線程數(shù)目不固定的線程池,它沒(méi)有核心線程蹈垢,只有非核心線程慷吊,當(dāng)線程池中的線程都處于活躍狀態(tài),就會(huì)創(chuàng)建新的線程來(lái)處理新的任務(wù)曹抬。否則就會(huì)利用閑置的線程來(lái)處理新的任務(wù)溉瓶。線程池中的線程都有超時(shí)機(jī)制,這個(gè)超時(shí)機(jī)制時(shí)長(zhǎng)是60s谤民,超過(guò)這個(gè)時(shí)間堰酿,閑置的線程就會(huì)被回收。這種線程池適合處理大量并且耗時(shí)較少的任務(wù)张足。這里得說(shuō)一下触创,CachedThreadPool的任務(wù)隊(duì)列,基本都是空的为牍。
ScheduledThreadPool線程池是通過(guò)Executors的newScheduledThreadPool進(jìn)行創(chuàng)建的哼绑,它的核心線程是固定的岩馍,但是非核心線程數(shù)是不固定的,并且當(dāng)非核心線程一處于空閑狀態(tài)抖韩,就立即被回收蛀恩。這種線程適合執(zhí)行定時(shí)任務(wù)和具有固定周期的重復(fù)任務(wù)。
SingleThreadExecutor線程池是通過(guò)Executors的newSingleThreadExecutor方法來(lái)創(chuàng)建的帽蝶,這類線程池中只有一個(gè)核心線程赦肋,也沒(méi)有非核心線程,這就確保了所有任務(wù)能夠在同一個(gè)線程并且按照順序來(lái)執(zhí)行励稳,這樣就不需要考慮線程同步的問(wèn)題。
AsyncTask的工作原理
AsyncTask是Android本身提供的一種輕量級(jí)的異步任務(wù)類囱井。它可以在線程池中執(zhí)行后臺(tái)任務(wù)驹尼,然后把執(zhí)行的進(jìn)度和最終的結(jié)果傳遞給主線程更新UI。實(shí)際上庞呕,AsyncTask內(nèi)部是封裝了Thread和Handler新翎。雖然AsyncTask很方便的執(zhí)行后臺(tái)任務(wù),以及在主線程上更新UI住练,但是地啰,AsyncTask并不合適進(jìn)行特別耗時(shí)的后臺(tái)操作,對(duì)于特別耗時(shí)的任務(wù)讲逛,個(gè)人還是建議使用線程池亏吝。
AsyncTask提供有4個(gè)核心方法:
1、onPreExecute():該方法在主線程中執(zhí)行盏混,在執(zhí)行異步任務(wù)之前會(huì)被調(diào)用蔚鸥,一般用于一些準(zhǔn)備工作。
2许赃、doInBackground(String... params):這個(gè)方法是在線程池中執(zhí)行止喷,此方法用于執(zhí)行異步任務(wù)。在這個(gè)方法中可以通過(guò)publishProgress方法來(lái)更新任務(wù)的進(jìn)度混聊,publishProgress方法會(huì)調(diào)用onProgressUpdate方法弹谁,另外,任務(wù)的結(jié)果返回給onPostExecute方法句喜。
3预愤、onProgressUpdate(Object... values):該方法在主線程中執(zhí)行,主要用于任務(wù)進(jìn)度更新的時(shí)候藤滥,該方法會(huì)被調(diào)用鳖粟。
4、onPostExecute(Long aLong):在主線程中執(zhí)行拙绊,在異步任務(wù)執(zhí)行完畢之后向图,該方法會(huì)被調(diào)用泳秀,該方法的參數(shù)及為后臺(tái)的返回結(jié)果。
除了這幾個(gè)方法之外還有一些不太常用的方法榄攀,如onCancelled(),在異步任務(wù)取消的情況下嗜傅,該方法會(huì)被調(diào)用。
源碼可以知道從上面的execute方法內(nèi)部調(diào)用的是executeOnExecutor()方法檩赢,即executeOnExecutor(sDefaultExecutor, params);而sDefaultExecutor實(shí)際上是一個(gè)串行的線程池吕嘀。而onPreExecute()方法在這里就會(huì)被調(diào)用了。接著看這個(gè)線程池贞瞒。AsyncTask的執(zhí)行是排隊(duì)執(zhí)行的偶房,因?yàn)橛嘘P(guān)鍵字synchronized,而AsyncTask的Params參數(shù)就封裝成為FutureTask類军浆,F(xiàn)utureTask這個(gè)類是一個(gè)并發(fā)類棕洋,在這里它充當(dāng)了Runnable的作用。接著FutureTask會(huì)交給SerialExecutor的execute方法去處理乒融,而SerialExecutor的executor方法首先就會(huì)將FutureTask添加到mTasks隊(duì)列中掰盘,如果這個(gè)時(shí)候沒(méi)有任務(wù),就會(huì)調(diào)用scheduleNext()方法赞季,執(zhí)行下一個(gè)任務(wù)愧捕。如果有任務(wù)的話,則執(zhí)行完畢后最后在調(diào)用 scheduleNext();執(zhí)行下一個(gè)任務(wù)申钩。直到所有任務(wù)被執(zhí)行完畢次绘。而AsyncTask的構(gòu)造方法中有一個(gè)call()方法,而這個(gè)方法由于會(huì)被FutureTask的run方法執(zhí)行典蜕。所以最終這個(gè)call方法會(huì)在線程池中執(zhí)行断盛。而doInBackground這個(gè)方法就是在這里被調(diào)用的。我們好好研究一下這個(gè)call()方法愉舔。mTaskInvoked.set(true);表示當(dāng)前任務(wù)已經(jīng)執(zhí)行過(guò)了钢猛。接著執(zhí)行doInBackground方法,最后將結(jié)果通過(guò)postResult(result);方法進(jìn)行傳遞轩缤。postResult()方法中通過(guò)sHandler來(lái)發(fā)送消息命迈,sHandler的中通過(guò)消息的類型來(lái)判斷一個(gè)MESSAGE_POST_RESULT,這種情況就是調(diào)用onPostExecute(result)方法或者是onCancelled(result)火的。另一種消息類型是MESSAGE_POST_PROGRESS則調(diào)用更新進(jìn)度onProgressUpdate壶愤。
Binder的工作機(jī)制
直觀來(lái)說(shuō),Binder是Android中的一個(gè)類馏鹤,它實(shí)現(xiàn)了IBinder接口征椒,從IPC的角度來(lái)說(shuō),Binder是Android中的一種跨進(jìn)程通信的一種方式湃累,同時(shí)還可以理解為是一種虛擬的物理設(shè)備勃救,它的設(shè)備驅(qū)動(dòng)是/dev/binder/碍讨。從Framework角度來(lái)說(shuō),Binder是ServiceManager的橋梁蒙秒。從應(yīng)用層來(lái)說(shuō)勃黍,Binder是客戶端和服務(wù)端進(jìn)行通信的媒介。
我們先來(lái)了解一下這個(gè)類中每個(gè)方法的含義:
DESCRIPTOR:Binder的唯一標(biāo)識(shí)晕讲,一般用于當(dāng)前Binder的類名表示覆获。
asInterface(android.os.IBinder obj):用于將服務(wù)端的Binder對(duì)象轉(zhuǎn)換成客戶端所需的AIDL接口類型的對(duì)象,這種轉(zhuǎn)化過(guò)程是區(qū)分進(jìn)程的瓢省,如果客戶端和服務(wù)端位于同一個(gè)進(jìn)程弄息,那么這個(gè)方法返回的是服務(wù)端的stub對(duì)象本身,否則返回的是系統(tǒng)封裝后的Stub.proxy對(duì)象净捅。
asBinder():用于返回當(dāng)前Binder對(duì)象疑枯。
onTransact:該方法運(yùn)行在服務(wù)端的Binder線程池中,當(dāng)客戶端發(fā)起跨進(jìn)程通信請(qǐng)求的時(shí)候蛔六,遠(yuǎn)程請(qǐng)求通過(guò)系統(tǒng)底層封裝后交給該方法處理。注意這個(gè)方法public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)废亭,服務(wù)端通過(guò)code可以確定客戶端所請(qǐng)求的目標(biāo)方法是什么国章,接著從data中取出目標(biāo)方法所需的參數(shù),然后執(zhí)行目標(biāo)方法豆村。當(dāng)目標(biāo)方法執(zhí)行完畢后液兽,就像reply中寫(xiě)入返回值。這個(gè)方法的執(zhí)行過(guò)程就是這樣的掌动。如果這個(gè)方法返回false四啰,客戶端是會(huì)請(qǐng)求失敗的,所以我們可以在這個(gè)方法中做一些安全驗(yàn)證粗恢。
Binder的工作機(jī)制但是要注意一些問(wèn)題:1柑晒、當(dāng)客戶端發(fā)起請(qǐng)求時(shí),由于當(dāng)前線程會(huì)被掛起眷射,直到服務(wù)端返回?cái)?shù)據(jù)匙赞,如果這個(gè)遠(yuǎn)程方法很耗時(shí)的話,那么是不能夠在UI線程妖碉,也就是主線程中發(fā)起這個(gè)遠(yuǎn)程請(qǐng)求的涌庭。
2、由于Service的Binder方法運(yùn)行在線程池中欧宜,所以Binder方法不管是耗時(shí)還是不耗時(shí)都應(yīng)該采用同步的方式坐榆,因?yàn)樗呀?jīng)運(yùn)行在一個(gè)線程中了。
view的事件分發(fā)和view的工作原理
Android自定義view冗茸,我們都知道實(shí)現(xiàn)有三部曲席镀,onMeasure(),onLayout(),onDraw()匹中。View的繪制流程是從viewRoot的perfromTraversal方法開(kāi)始的。它經(jīng)過(guò)measure愉昆,layout职员,draw方法才能夠?qū)iew繪制出來(lái)。其中measure是測(cè)量寬高的跛溉,layout是確定view在父容器上的擺布位置的焊切,draw是將view繪制到屏幕上的。
Measure:
view的測(cè)量是需要MeasureSpc(測(cè)量規(guī)格)芳室,它代表一個(gè)32位int值专肪,高2位代表SpecMode(測(cè)量模式),低(30)位的代表SpecSize(某種測(cè)量模式下的規(guī)格大小)堪侯。而一組SpecMode和SpeSize可以打包為一個(gè)MeasureSpec,反之嚎尤,MeasureSpec可以解包得到SpecMode和SpeSize的值。SpecMode有三類:
unSpecified:父容器不對(duì)view有任何限制伍宦,要多大有多大芽死。一般系統(tǒng)用這個(gè)多。
Exactly:父容器已經(jīng)檢測(cè)出view所需要的精確大小次洼,這個(gè)時(shí)候关贵,view的大小就是SpecSize所指定的值,它對(duì)應(yīng)者layout布局中的math_parent或者是具體的數(shù)值
At_most:父容器指定了一個(gè)可用大小的SpecSize,view的大小不能夠大于這個(gè)值卖毁,它對(duì)應(yīng)這布局中的wrao_content.
對(duì)于普通的view揖曾,它的MeasureSpec是由父容器的MeasureSpec和自身的layoutParam共同決定的,一旦MeasureSpec確定后亥啦,onMeasure就可以確定view的寬高了炭剪。
View的measure過(guò)程:
onMeasure方法中有個(gè)setMeasureDimenSion方法來(lái)設(shè)置view的寬高測(cè)量值,而setMeasureDimenSion有個(gè)getDefaultSize()方法作為參數(shù)翔脱。一般情況下奴拦,我們只需要關(guān)注at_most和exactly兩種情況,getDefaultSize的返回值就是measureSpec中的SpecSize,而這個(gè)值基本就是view測(cè)量后的大小碍侦。而UnSpecified這種情況粱坤,一般是系統(tǒng)內(nèi)部的測(cè)量過(guò)程,它是需要考慮view的背景這些因素的瓷产。
前面說(shuō)的是view的測(cè)量過(guò)程站玄,而viewGroup的measure過(guò)程:
對(duì)于viewGroup來(lái)說(shuō),除了完成自己的measure過(guò)程以外濒旦,還要遍歷去調(diào)用子類的measure方法株旷,各個(gè)子元素在遞歸執(zhí)行這個(gè)過(guò)程,viewGroup是一個(gè)抽象的類,沒(méi)有提供有onMeasure方法晾剖,但是提供了一個(gè)measureChildren的方法锉矢。measureChild方法的思想就是取出子元素的layoutParams,然后通過(guò)getChildMeasureSpec來(lái)常見(jiàn)子元素的MeasureSpec,然后子元素在電泳measure方法進(jìn)行測(cè)量。由于viewGroup子類有不同的布局方式齿尽,導(dǎo)致他們的測(cè)量細(xì)節(jié)不一樣沽损,所以viewGroup不能象view一樣調(diào)用onMeasure方法進(jìn)行測(cè)量。
注意:在activity的生命周期中是沒(méi)有辦法正確的獲取view的寬高的循头,原因就是view沒(méi)有測(cè)量完绵估。
在onWindowFocuschanged方法中獲取 ----改方法含義是view已經(jīng)初始化完畢
View.post()方法,將潤(rùn)那邊了投遞到消息隊(duì)列的尾部卡骂。
使用viewTreeObserver的回調(diào)來(lái)完成国裳。
通過(guò)view.measure方式手動(dòng)測(cè)量。
onLayout
普通的view的話全跨,可以通過(guò)setFrame方法來(lái)的到view四個(gè)頂點(diǎn)的位置缝左,也就確定了view在父容器的位置,接著就調(diào)用onLayout方法浓若,該方法是父容器確定子元素的位置渺杉。
onDraw
該方法就是將view繪制到屏幕上。分以下幾步
繪制背景挪钓,
繪制自己少办,
繪制child,
繪制裝飾诵原。
Android中性能優(yōu)化
由于手機(jī)硬件的限制,內(nèi)存和CPU都無(wú)法像pc一樣具有超大的內(nèi)存挽放,Android手機(jī)上绍赛,過(guò)多的使用內(nèi)存,會(huì)容易導(dǎo)致oom辑畦,過(guò)多的使用CPU資源吗蚌,會(huì)導(dǎo)致手機(jī)卡頓,甚至導(dǎo)致anr纯出。我主要是從一下幾部分進(jìn)行優(yōu)化:
布局優(yōu)化蚯妇,繪制優(yōu)化,內(nèi)存泄漏優(yōu)化暂筝,響應(yīng)速度優(yōu)化箩言,listview優(yōu)化,bitmap優(yōu)化焕襟,線程優(yōu)化
布局優(yōu)化:工具 hierarchyviewer陨收,解決方式:
1、刪除無(wú)用的空間和層級(jí)。
2务漩、選擇性能較低的viewgroup拄衰,如Relativelayout,如果可以選擇Relativelayout也可以使用LinearLayout,就優(yōu)先使用LinearLayout饵骨,因?yàn)橄鄬?duì)來(lái)說(shuō)Relativelayout功能較為復(fù)雜翘悉,會(huì)占用更多的CPU資源。
3居触、使用標(biāo)簽<include/>重用布局妖混,<Merge/>減少層級(jí),<viewStub/>進(jìn)行預(yù)加載饼煞,使用的時(shí)候才加載源葫。
繪制優(yōu)化
繪制優(yōu)化指view在ondraw方法中避免大量的耗時(shí)操作,由于ondraw方法可能會(huì)被頻繁的調(diào)用砖瞧。
1息堂、ondraw方法中不要?jiǎng)?chuàng)建新的局部變量,ondraw方法被頻繁的調(diào)用块促,很容易引起GC荣堰。
2、ondraw方法不要做耗時(shí)操作竭翠。
內(nèi)存優(yōu)化:參考內(nèi)存泄漏振坚。
響應(yīng)優(yōu)化:主線程不能做耗時(shí)操作,觸摸事件5s,廣播10s斋扰,service20s渡八。
listview優(yōu)化:
1、getview方法中避免耗時(shí)操作传货。
2屎鳍、view的復(fù)用和viewholder的使用。
3问裕、滑動(dòng)不適合開(kāi)啟異步加載逮壁。
4、分頁(yè)處理數(shù)據(jù)粮宛。
5窥淆、圖片使用三級(jí)緩存。
Bitmap優(yōu)化:
1巍杈、等比例壓縮圖片忧饭。
2、不用的圖片秉氧,及時(shí)recycler掉
線程優(yōu)化
線程優(yōu)化的思想是使用線程池來(lái)管理和復(fù)用線程眷昆,避免程序中有大量的Thread,同時(shí)可以控制線程的并發(fā)數(shù),避免相互搶占資源而導(dǎo)致線程阻塞。
其他優(yōu)化
1、少用枚舉架馋,枚舉占用空間大。
2纸泡、使用Android特有的數(shù)據(jù)結(jié)構(gòu),如SparseArray來(lái)代替hashMap赖瞒。
3女揭、適當(dāng)?shù)氖褂密浺煤腿跻谩?/p>
加密算法(base64、MD5栏饮、對(duì)稱加密和非對(duì)稱加密)和使用場(chǎng)景吧兔。
什么是Rsa加密?
RSA算法是最流行的公鑰密碼算法袍嬉,使用長(zhǎng)度可以變化的密鑰境蔼。RSA是第一個(gè)既能用于數(shù)據(jù)加密也能用于數(shù)字簽名的算法。
RSA算法原理如下:
1.隨機(jī)選擇兩個(gè)大質(zhì)數(shù)p和q伺通,p不等于q箍土,計(jì)算N=pq;
2.選擇一個(gè)大于1小于N的自然數(shù)e罐监,e必須與(p-1)(q-1)互素吴藻。
3.用公式計(jì)算出d:d×e = 1 (mod (p-1)(q-1)) 。
4.銷(xiāo)毀p和q弓柱。
最終得到的N和e就是“公鑰”沟堡,d就是“私鑰”,發(fā)送方使用N去加密數(shù)據(jù)矢空,接收方只有使用d才能解開(kāi)數(shù)據(jù)內(nèi)容弦叶。
RSA的安全性依賴于大數(shù)分解,小于1024位的N已經(jīng)被證明是不安全的妇多,而且由于RSA算法進(jìn)行的都是大數(shù)計(jì)算,使得RSA最快的情況也比DES慢上倍燕侠,這是RSA最大的缺陷者祖,因此通常只能用于加密少量數(shù)據(jù)或者加密密鑰,但RSA仍然不失為一種高強(qiáng)度的算法绢彤。
使用場(chǎng)景:項(xiàng)目中除了登陸七问,支付等接口采用rsa非對(duì)稱加密,之外的采用aes對(duì)稱加密茫舶,今天我們來(lái)認(rèn)識(shí)一下aes加密械巡。
什么是MD5加密?
MD5英文全稱“Message-Digest Algorithm 5”,翻譯過(guò)來(lái)是“消息摘要算法5”讥耗,由MD2有勾、MD3、MD4演變過(guò)來(lái)的古程,是一種單向加密算法蔼卡,是不可逆的一種的加密方式。
MD5加密有哪些特點(diǎn)挣磨?
壓縮性:任意長(zhǎng)度的數(shù)據(jù)雇逞,算出的MD5值長(zhǎng)度都是固定的。
容易計(jì)算:從原數(shù)據(jù)計(jì)算出MD5值很容易茁裙。
抗修改性:對(duì)原數(shù)據(jù)進(jìn)行任何改動(dòng)塘砸,哪怕只修改1個(gè)字節(jié),所得到的MD5值都有很大區(qū)別晤锥。
強(qiáng)抗碰撞:已知原數(shù)據(jù)和其MD5值掉蔬,想找到一個(gè)具有相同MD5值的數(shù)據(jù)(即偽造數(shù)據(jù))是非常困難的。
MD5應(yīng)用場(chǎng)景:
一致性驗(yàn)證
數(shù)字簽名
安全訪問(wèn)認(rèn)證
什么是aes加密查近?
高級(jí)加密標(biāo)準(zhǔn)(英語(yǔ):Advanced Encryption Standard眉踱,縮寫(xiě):AES),在密碼學(xué)中又稱Rijndael加密法霜威,是美國(guó)聯(lián)邦政府采用的一種區(qū)塊加密標(biāo)準(zhǔn)谈喳。這個(gè)標(biāo)準(zhǔn)用來(lái)替代原先的DES,已經(jīng)被多方分析且廣為全世界所使用戈泼。
HashMap的實(shí)現(xiàn)原理:
HashMap是基于哈希表的map接口的非同步實(shí)現(xiàn)婿禽,它允許使用null值作為key和value。在Java編程語(yǔ)言中最基本的結(jié)構(gòu)就是兩種大猛,一種是數(shù)組扭倾,另一種是模擬指針(引用)。所有的數(shù)據(jù)結(jié)構(gòu)都可以用這兩個(gè)基本的結(jié)構(gòu)來(lái)構(gòu)造挽绩,HashMap也不例外膛壹。HashMap實(shí)際上是一個(gè)“鏈表散列”的數(shù)據(jù)結(jié)構(gòu)。即數(shù)組和鏈表的結(jié)合體唉堪。
HashMap底層就是一個(gè)數(shù)據(jù)結(jié)構(gòu)模聋,數(shù)組中的每一項(xiàng)又是一個(gè)鏈表。
沖突:
HashMap中調(diào)用Hashcode()方法計(jì)算Hashclde值唠亚,由于Java中兩個(gè)不同的對(duì)象可能有一樣的Hashcode链方。就導(dǎo)致了沖突的產(chǎn)生。
解決:
HashMap在put時(shí)候灶搜,底層源碼可以看出祟蚀,當(dāng)程序試圖將一個(gè)key-value對(duì)象放入到HashMap中工窍,首先根據(jù)該key的hashCode()返回值決定該Entry的存儲(chǔ)位置,如果兩個(gè)Entry的key的hashCode()方法返回值相同前酿,那他們的存儲(chǔ)位置相同患雏,如果這兩個(gè)Entry的key通過(guò)equals比較返回true,新添加的Entry的value將會(huì)覆蓋原來(lái)的Entry的value薪者,但是key不會(huì)被覆蓋纵苛,反之,如果返回false言津,新添加的Entry將與集合中原有的Entry形成Entry鏈攻人,新添加的位于頭部,舊的位于尾部
HashMap的實(shí)現(xiàn)原理:
利用key的hashCode重新hash計(jì)算出當(dāng)前對(duì)象的元素在數(shù)組中的下標(biāo)悬槽。
存儲(chǔ)時(shí)如果出現(xiàn)hash值相同的key怀吻,分兩種情況:1、如果key相同初婆,則覆蓋原來(lái)的值蓬坡。2、如果key不同(出現(xiàn)沖突)磅叛,則放在鏈表中屑咳。
獲取時(shí),直接找到hash值對(duì)應(yīng)的下標(biāo)弊琴,再進(jìn)一步判斷key是否相同兆龙,從而拿到對(duì)應(yīng)的值。
Hashmap的核心就是使用數(shù)組進(jìn)行存儲(chǔ)敲董,出現(xiàn)key沖突的時(shí)候紫皇,就存放在鏈表中。
===========================
1腋寨、Activity生命周期聪铺?
onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDetroy()
2、Service生命周期萄窜?
service 啟動(dòng)方式有兩種铃剔,一種是通過(guò)startService()方式進(jìn)行啟動(dòng),另一種是通過(guò)bindService()方式進(jìn)行啟動(dòng)查刻。不同的啟動(dòng)方式他們的生命周期是不一樣.
通過(guò)startService()這種方式啟動(dòng)的service番宁,生命周期是這樣:調(diào)用startService() --> onCreate()--> onStartConmon()--> onDestroy()。這種方式啟動(dòng)的話赖阻,需要注意一下幾個(gè)問(wèn)題,第一:當(dāng)我們通過(guò)startService被調(diào)用以后踱蠢,多次在調(diào)用startService(),onCreate()方法也只會(huì)被調(diào)用一次火欧,而onStartConmon()會(huì)被多次調(diào)用當(dāng)我們調(diào)用stopService()的時(shí)候棋电,onDestroy()就會(huì)被調(diào)用,從而銷(xiāo)毀服務(wù)苇侵。第二:當(dāng)我們通過(guò)startService啟動(dòng)時(shí)候赶盔,通過(guò)intent傳值,在onStartConmon()方法中獲取值的時(shí)候榆浓,一定要先判斷intent是否為null于未。
通過(guò)bindService()方式進(jìn)行綁定,這種方式綁定service陡鹃,生命周期走法:bindService-->onCreate()-->onBind()-->unBind()-->onDestroy() bingservice 這種方式進(jìn)行啟動(dòng)service好處是更加便利activity中操作service烘浦,比如加入service中有幾個(gè)方法,a,b 萍鲸,如果要在activity中調(diào)用闷叉,在需要在activity獲取ServiceConnection對(duì)象,通過(guò)ServiceConnection來(lái)獲取service中內(nèi)部類的類對(duì)象脊阴,然后通過(guò)這個(gè)類對(duì)象就可以調(diào)用類中的方法握侧,當(dāng)然這個(gè)類需要繼承Binder對(duì)象
3、Activity的啟動(dòng)過(guò)程(不要回答生命周期)
app啟動(dòng)的過(guò)程有兩種情況嘿期,第一種是從桌面launcher上點(diǎn)擊相應(yīng)的應(yīng)用圖標(biāo)品擎,第二種是在activity中通過(guò)調(diào)用startActivity來(lái)啟動(dòng)一個(gè)新的activity。
我們創(chuàng)建一個(gè)新的項(xiàng)目备徐,默認(rèn)的根activity都是MainActivity萄传,而所有的activity都是保存在堆棧中的,我們啟動(dòng)一個(gè)新的activity就會(huì)放在上一個(gè)activity上面坦喘,而我們從桌面點(diǎn)擊應(yīng)用圖標(biāo)的時(shí)候盲再,由于launcher本身也是一個(gè)應(yīng)用,當(dāng)我們點(diǎn)擊圖標(biāo)的時(shí)候瓣铣,系統(tǒng)就會(huì)調(diào)用startActivitySately(),一般情況下答朋,我們所啟動(dòng)的activity的相關(guān)信息都會(huì)保存在intent中,比如action棠笑,category等等梦碗。我們?cè)诎惭b這個(gè)應(yīng)用的時(shí)候,系統(tǒng)也會(huì)啟動(dòng)一個(gè)PackaManagerService的管理服務(wù)蓖救,這個(gè)管理服務(wù)會(huì)對(duì)AndroidManifest.xml文件進(jìn)行解析洪规,從而得到應(yīng)用程序中的相關(guān)信息,比如service循捺,activity斩例,Broadcast等等,然后獲得相關(guān)組件的信息从橘。當(dāng)我們點(diǎn)擊應(yīng)用圖標(biāo)的時(shí)候念赶,就會(huì)調(diào)用startActivitySately()方法础钠,而這個(gè)方法內(nèi)部則是調(diào)用startActivty(),而startActivity()方法最終還是會(huì)調(diào)用startActivityForResult()這個(gè)方法。而在startActivityForResult()這個(gè)方法叉谜。因?yàn)閟tartActivityForResult()方法是有返回結(jié)果的旗吁,所以系統(tǒng)就直接給一個(gè)-1,就表示不需要結(jié)果返回了停局。而startActivityForResult()這個(gè)方法實(shí)際是通過(guò)Instrumentation類中的execStartActivity()方法來(lái)啟動(dòng)activity很钓,Instrumentation這個(gè)類主要作用就是監(jiān)控程序和系統(tǒng)之間的交互。而在這個(gè)execStartActivity()方法中會(huì)獲取ActivityManagerService的代理對(duì)象董栽,通過(guò)這個(gè)代理對(duì)象進(jìn)行啟動(dòng)activity码倦。啟動(dòng)會(huì)就會(huì)調(diào)用一個(gè)checkStartActivityResult()方法,如果說(shuō)沒(méi)有在配置清單中配置有這個(gè)組件裆泳,就會(huì)在這個(gè)方法中拋出異常了叹洲。當(dāng)然最后是調(diào)用的是Application.scheduleLaunchActivity()進(jìn)行啟動(dòng)activity,而這個(gè)方法中通過(guò)獲取得到一個(gè)ActivityClientRecord對(duì)象工禾,而這個(gè)ActivityClientRecord通過(guò)handler來(lái)進(jìn)行消息的發(fā)送运提,系統(tǒng)內(nèi)部會(huì)將每一個(gè)activity組件使用ActivityClientRecord對(duì)象來(lái)進(jìn)行描述,而ActivityClientRecord對(duì)象中保存有一個(gè)LoaderApk對(duì)象闻葵,通過(guò)這個(gè)對(duì)象調(diào)用handleLaunchActivity來(lái)啟動(dòng)activity組件民泵,而頁(yè)面的生命周期方法也就是在這個(gè)方法中進(jìn)行調(diào)用。
4槽畔、Broadcast注冊(cè)方式與區(qū)別
此處延伸:什么情況下用動(dòng)態(tài)注冊(cè)
Broadcast廣播栈妆,注冊(cè)方式主要有兩種.
第一種是靜態(tài)注冊(cè),也可成為常駐型廣播厢钧,這種廣播需要在Androidmanifest.xml中進(jìn)行注冊(cè)鳞尔,這中方式注冊(cè)的廣播,不受頁(yè)面生命周期的影響早直,即使退出了頁(yè)面寥假,也可以收到廣播這種廣播一般用于想開(kāi)機(jī)自啟動(dòng)啊等等,由于這種注冊(cè)的方式的廣播是常駐型廣播霞扬,所以會(huì)占用CPU的資源糕韧。
第二種是動(dòng)態(tài)注冊(cè),而動(dòng)態(tài)注冊(cè)的話喻圃,是在代碼中注冊(cè)的萤彩,這種注冊(cè)方式也叫非常駐型廣播,收到生命周期的影響斧拍,退出頁(yè)面后雀扶,就不會(huì)收到廣播,我們通常運(yùn)用在更新UI方面肆汹。這種注冊(cè)方式優(yōu)先級(jí)較高愚墓。最后需要解綁窍侧,否會(huì)會(huì)內(nèi)存泄露
廣播是分為有序廣播和無(wú)序廣播。
5转绷、HttpClient與HttpUrlConnection的區(qū)別
此處延伸:Volley里用的哪種請(qǐng)求方式(2.3前HttpClient,2.3后HttpUrlConnection)
首先HttpClient和HttpUrlConnection 這兩種方式都支持Https協(xié)議硼啤,都是以流的形式進(jìn)行上傳或者下載數(shù)據(jù)议经,也可以說(shuō)是以流的形式進(jìn)行數(shù)據(jù)的傳輸,還有ipv6,以及連接池等功能谴返。HttpClient這個(gè)擁有非常多的API煞肾,所以如果想要進(jìn)行擴(kuò)展的話,并且不破壞它的兼容性的話嗓袱,很難進(jìn)行擴(kuò)展籍救,也就是這個(gè)原因,Google在Android6.0的時(shí)候渠抹,直接就棄用了這個(gè)HttpClient.
而HttpUrlConnection相對(duì)來(lái)說(shuō)就是比較輕量級(jí)了蝙昙,API比較少,容易擴(kuò)展梧却,并且能夠滿足Android大部分的數(shù)據(jù)傳輸奇颠。比較經(jīng)典的一個(gè)框架volley,在2.3版本以前都是使用HttpClient,在2.3以后就使用了HttpUrlConnection放航。
6烈拒、java虛擬機(jī)和Dalvik虛擬機(jī)的區(qū)別
Java虛擬機(jī):
1、java虛擬機(jī)基于棧广鳍。 基于棧的機(jī)器必須使用指令來(lái)載入和操作棧上數(shù)據(jù)荆几,所需指令更多更多蛋叼。
2暴浦、java虛擬機(jī)運(yùn)行的是java字節(jié)碼纷铣。(java類會(huì)被編譯成一個(gè)或多個(gè)字節(jié)碼.class文件)
Dalvik虛擬機(jī):
1、dalvik虛擬機(jī)是基于寄存器的
2、Dalvik運(yùn)行的是自定義的.dex字節(jié)碼格式浪默。(java類被編譯成.class文件后牡直,會(huì)通過(guò)一個(gè)dx工具將所有的.class文件轉(zhuǎn)換成一個(gè).dex文件,然后dalvik虛擬機(jī)會(huì)從其中讀取指令和數(shù)據(jù)
3纳决、常量池已被修改為只使用32位的索引碰逸,以 簡(jiǎn)化解釋器。
4阔加、一個(gè)應(yīng)用饵史,一個(gè)虛擬機(jī)實(shí)例,一個(gè)進(jìn)程(所有android應(yīng)用的線程都是對(duì)應(yīng)一個(gè)linux線程,都運(yùn)行在自己的沙盒中胳喷,不同的應(yīng)用在不同的進(jìn)程中運(yùn)行湃番。每個(gè)android dalvik應(yīng)用程序都被賦予了一個(gè)獨(dú)立的linux PID(app_*))
7、進(jìn)程笨月叮活(不死進(jìn)程)
此處延伸:進(jìn)程的優(yōu)先級(jí)是什么
當(dāng)前業(yè)界的Android進(jìn)程狈痛椋活手段主要分為** 黑、白讲竿、灰 **三種纬向,其大致的實(shí)現(xiàn)思路如下:
黑色保活:不同的app進(jìn)程戴卜,用廣播相互喚醒(包括利用系統(tǒng)提供的廣播進(jìn)行喚醒)
白色保活:?jiǎn)?dòng)前臺(tái)Service
灰色弊裂遥活:利用系統(tǒng)的漏洞啟動(dòng)前臺(tái)Service
黑色蓖栋活
所謂黑色保活担孔,就是利用不同的app進(jìn)程使用廣播來(lái)進(jìn)行相互喚醒江锨。舉個(gè)3個(gè)比較常見(jiàn)的場(chǎng)景:
場(chǎng)景1:開(kāi)機(jī),網(wǎng)絡(luò)切換糕篇、拍照啄育、拍視頻時(shí)候,利用系統(tǒng)產(chǎn)生的廣播喚醒a(bǔ)pp
場(chǎng)景2:接入第三方SDK也會(huì)喚醒相應(yīng)的app進(jìn)程拌消,如微信sdk會(huì)喚醒微信挑豌,支付寶sdk會(huì)喚醒支付寶。由此發(fā)散開(kāi)去墩崩,就會(huì)直接觸發(fā)了下面的 場(chǎng)景3
場(chǎng)景3:假如你手機(jī)里裝了支付寶氓英、淘寶、天貓鹦筹、UC等阿里系的app铝阐,那么你打開(kāi)任意一個(gè)阿里系的app后,有可能就順便把其他阿里系的app給喚醒了铐拐。(只是拿阿里打個(gè)比方徘键,其實(shí)BAT系都差不多)
白色保活
白色北轶活手段非常簡(jiǎn)單吹害,就是調(diào)用系統(tǒng)api啟動(dòng)一個(gè)前臺(tái)的Service進(jìn)程,這樣會(huì)在系統(tǒng)的通知欄生成一個(gè)Notification匿值,用來(lái)讓用戶知道有這樣一個(gè)app在運(yùn)行著赠制,哪怕當(dāng)前的app退到了后臺(tái)。如下方的LBE和QQ音樂(lè)這樣:
灰色保活
灰色敝有活烟号,這種保活手段是應(yīng)用范圍最廣泛政恍。它是利用系統(tǒng)的漏洞來(lái)啟動(dòng)一個(gè)前臺(tái)的Service進(jìn)程汪拥,與普通的啟動(dòng)方式區(qū)別在于,它不會(huì)在系統(tǒng)通知欄處出現(xiàn)一個(gè)Notification篙耗,看起來(lái)就如同運(yùn)行著一個(gè)后臺(tái)Service進(jìn)程一樣迫筑。這樣做帶來(lái)的好處就是,用戶無(wú)法察覺(jué)到你運(yùn)行著一個(gè)前臺(tái)進(jìn)程(因?yàn)榭床坏絅otification),但你的進(jìn)程優(yōu)先級(jí)又是高于普通后臺(tái)進(jìn)程的宗弯。那么如何利用系統(tǒng)的漏洞呢脯燃,大致的實(shí)現(xiàn)思路和代碼如下:
思路一:API < 18,啟動(dòng)前臺(tái)Service時(shí)直接傳入new Notification()蒙保;
思路二:API >= 18辕棚,同時(shí)啟動(dòng)兩個(gè)id相同的前臺(tái)Service,然后再將后啟動(dòng)的Service做stop處理
熟悉Android系統(tǒng)的童鞋都知道邓厕,系統(tǒng)出于體驗(yàn)和性能上的考慮逝嚎,app在退到后臺(tái)時(shí)系統(tǒng)并不會(huì)真正的kill掉這個(gè)進(jìn)程,而是將其緩存起來(lái)详恼。打開(kāi)的應(yīng)用越多补君,后臺(tái)緩存的進(jìn)程也越多。在系統(tǒng)內(nèi)存不足的情況下昧互,系統(tǒng)開(kāi)始依據(jù)自身的一套進(jìn)程回收機(jī)制來(lái)判斷要kill掉哪些進(jìn)程挽铁,以騰出內(nèi)存來(lái)供給需要的app。這套殺進(jìn)程回收內(nèi)存的機(jī)制就叫 Low Memory Killer 敞掘,它是基于Linux內(nèi)核的 OOM Killer(Out-Of-Memory killer)機(jī)制誕生屿储。
進(jìn)程的重要性,劃分5級(jí):
前臺(tái)進(jìn)程 (Foreground process)
可見(jiàn)進(jìn)程 (Visible process)
服務(wù)進(jìn)程 (Service process)
后臺(tái)進(jìn)程 (Background process)
空進(jìn)程 (Empty process)
了解完 Low Memory Killer渐逃,再科普一下oom_adj够掠。什么是oom_adj?它是linux內(nèi)核分配給每個(gè)系統(tǒng)進(jìn)程的一個(gè)值茄菊,代表進(jìn)程的優(yōu)先級(jí)疯潭,進(jìn)程回收機(jī)制就是根據(jù)這個(gè)優(yōu)先級(jí)來(lái)決定是否進(jìn)行回收。對(duì)于oom_adj的作用面殖,你只需要記住以下幾點(diǎn)即可:
進(jìn)程的oom_adj越大竖哩,表示此進(jìn)程優(yōu)先級(jí)越低,越容易被殺回收脊僚;越小相叁,表示進(jìn)程優(yōu)先級(jí)越高遵绰,越不容易被殺回收
普通app進(jìn)程的oom_adj>=0,系統(tǒng)進(jìn)程的oom_adj才可能<0
有些手機(jī)廠商把這些知名的app放入了自己的白名單中,保證了進(jìn)程不死來(lái)提高用戶體驗(yàn)(如微信增淹、QQ椿访、陌陌都在小米的白名單中)。如果從白名單中移除虑润,他們終究還是和普通app一樣躲避不了被殺的命運(yùn)成玫,為了盡量避免被殺,還是老老實(shí)實(shí)去做好優(yōu)化工作吧拳喻。
所以哭当,進(jìn)程保活的根本方案終究還是回到了性能優(yōu)化上冗澈,進(jìn)程永生不死終究是個(gè)徹頭徹尾的偽命題钦勘!
8、講解一下Context
Context是一個(gè)抽象基類亚亲。在翻譯為上下文个盆,也可以理解為環(huán)境,是提供一些程序的運(yùn)行環(huán)境基礎(chǔ)信息朵栖。Context下有兩個(gè)子類,ContextWrapper是上下文功能的封裝類柴梆,而ContextImpl則是上下文功能的實(shí)現(xiàn)類陨溅。而ContextWrapper又有三個(gè)直接的子類, ContextThemeWrapper绍在、Service和Application门扇。其中,ContextThemeWrapper是一個(gè)帶主題的封裝類偿渡,而它有一個(gè)直接子類就是Activity臼寄,所以Activity和Service以及Application的Context是不一樣的,只有Activity需要主題溜宽,Service不需要主題吉拳。Context一共有三種類型,分別是Application适揉、Activity和Service留攒。這三個(gè)類雖然分別各種承擔(dān)著不同的作用,但它們都屬于Context的一種嫉嘀,而它們具體Context的功能則是由ContextImpl類去實(shí)現(xiàn)的炼邀,因此在絕大多數(shù)場(chǎng)景下,Activity剪侮、Service和Application這三種類型的Context都是可以通用的拭宁。不過(guò)有幾種場(chǎng)景比較特殊,比如啟動(dòng)Activity,還有彈出Dialog杰标。出于安全原因的考慮兵怯,Android是不允許Activity或Dialog憑空出現(xiàn)的,一個(gè)Activity的啟動(dòng)必須要建立在另一個(gè)Activity的基礎(chǔ)之上在旱,也就是以此形成的返回棧摇零。而Dialog則必須在一個(gè)Activity上面彈出(除非是System Alert類型的Dialog),因此在這種場(chǎng)景下桶蝎,我們只能使用Activity類型的Context驻仅,否則將會(huì)出錯(cuò)。
getApplicationContext()和getApplication()方法得到的對(duì)象都是同一個(gè)application對(duì)象登渣,只是對(duì)象的類型不一樣噪服。
Context數(shù)量 = Activity數(shù)量 + Service數(shù)量 + 1 (1為Application)
9、理解Activity,View,Window三者關(guān)系
這個(gè)問(wèn)題真的很不好回答话侄。所以這里先來(lái)個(gè)算是比較恰當(dāng)?shù)谋扔鱽?lái)形容下它們的關(guān)系吧卵佛。Activity像一個(gè)工匠(控制單元),Window像窗戶(承載模型)雹顺,View像窗花(顯示視圖)LayoutInflater像剪刀,Xml配置像窗花圖紙廊遍。
1:Activity構(gòu)造的時(shí)候會(huì)初始化一個(gè)Window嬉愧,準(zhǔn)確的說(shuō)是PhoneWindow。
2:這個(gè)PhoneWindow有一個(gè)“ViewRoot”喉前,這個(gè)“ViewRoot”是一個(gè)View或者說(shuō)ViewGroup没酣,是最初始的根視圖。
3:“ViewRoot”通過(guò)addView方法來(lái)一個(gè)個(gè)的添加View卵迂。比如TextView裕便,Button等
4:這些View的事件監(jiān)聽(tīng),是由WindowManagerService來(lái)接受消息见咒,并且回調(diào)Activity函數(shù)偿衰。比如onClickListener,onKeyDown等改览。
10哎垦、四種LaunchMode及其使用場(chǎng)景
此處延伸:棧(First In Last Out)與隊(duì)列(First In First Out)的區(qū)別
棧與隊(duì)列的區(qū)別:
- 隊(duì)列先進(jìn)先出,棧先進(jìn)后出
- 對(duì)插入和刪除操作的"限定"恃疯。 棧是限定只能在表的一端進(jìn)行插入和刪除操作的線性表漏设。 隊(duì)列是限定只能在表的一端進(jìn)行插入和在另一端進(jìn)行刪除操作的線性表。
- 遍歷數(shù)據(jù)速度不同
standard 模式
這是默認(rèn)模式今妄,每次激活A(yù)ctivity時(shí)都會(huì)創(chuàng)建Activity實(shí)例郑口,并放入任務(wù)棧中鸳碧。使用場(chǎng)景:大多數(shù)Activity。
singleTop 模式
如果在任務(wù)的棧頂正好存在該Activity的實(shí)例犬性,就重用該實(shí)例( 會(huì)調(diào)用實(shí)例的 onNewIntent() )瞻离,否則就會(huì)創(chuàng)建新的實(shí)例并放入棧頂,即使棧中已經(jīng)存在該Activity的實(shí)例乒裆,只要不在棧頂套利,都會(huì)創(chuàng)建新的實(shí)例。使用場(chǎng)景如新聞?lì)惢蛘唛喿x類App的內(nèi)容頁(yè)面鹤耍。
singleTask 模式
如果在棧中已經(jīng)有該Activity的實(shí)例肉迫,就重用該實(shí)例(會(huì)調(diào)用實(shí)例的 onNewIntent() )。重用時(shí)稿黄,會(huì)讓該實(shí)例回到棧頂喊衫,因此在它上面的實(shí)例將會(huì)被移出棧。如果棧中不存在該實(shí)例杆怕,將會(huì)創(chuàng)建新的實(shí)例放入棧中族购。使用場(chǎng)景如瀏覽器的主界面。不管從多少個(gè)應(yīng)用啟動(dòng)瀏覽器陵珍,只會(huì)啟動(dòng)主界面一次寝杖,其余情況都會(huì)走onNewIntent,并且會(huì)清空主界面上面的其他頁(yè)面互纯。
singleInstance 模式
在一個(gè)新棧中創(chuàng)建該Activity的實(shí)例瑟幕,并讓多個(gè)應(yīng)用共享該棧中的該Activity實(shí)例。一旦該模式的Activity實(shí)例已經(jīng)存在于某個(gè)棧中伟姐,任何應(yīng)用再激活該Activity時(shí)都會(huì)重用該棧中的實(shí)例( 會(huì)調(diào)用實(shí)例的 onNewIntent() )。其效果相當(dāng)于多個(gè)應(yīng)用共享一個(gè)應(yīng)用亿卤,不管誰(shuí)激活該 Activity 都會(huì)進(jìn)入同一個(gè)應(yīng)用中愤兵。使用場(chǎng)景如鬧鈴提醒,將鬧鈴提醒與鬧鈴設(shè)置分離排吴。singleInstance不要用于中間頁(yè)面秆乳,如果用于中間頁(yè)面,跳轉(zhuǎn)會(huì)有問(wèn)題钻哩,比如:A -> B (singleInstance) -> C屹堰,完全退出后,在此啟動(dòng)街氢,首先打開(kāi)的是B扯键。
11、View的繪制流程
自定義控件:
1珊肃、組合控件荣刑。這種自定義控件不需要我們自己繪制馅笙,而是使用原生控件組合成的新控件。如標(biāo)題欄厉亏。
2董习、繼承原有的控件。這種自定義控件在原生控件提供的方法外爱只,可以自己添加一些方法皿淋。如制作圓角,圓形圖片恬试。
3窝趣、完全自定義控件:這個(gè)View上所展現(xiàn)的內(nèi)容全部都是我們自己繪制出來(lái)的。比如說(shuō)制作水波紋進(jìn)度條忘渔。
View的繪制流程:OnMeasure()——>OnLayout()——>OnDraw()
第一步:OnMeasure():測(cè)量視圖大小高帖。從頂層父View到子View遞歸調(diào)用measure方法,measure方法又回調(diào)OnMeasure畦粮。
第二步:OnLayout():確定View位置散址,進(jìn)行頁(yè)面布局。從頂層父View向子View的遞歸調(diào)用view.layout方法的過(guò)程宣赔,即父View根據(jù)上一步measure子View所得到的布局大小和布局參數(shù)预麸,將子View放在合適的位置上。
第三步:OnDraw():繪制視圖儒将。ViewRoot創(chuàng)建一個(gè)Canvas對(duì)象吏祸,然后調(diào)用OnDraw()。六個(gè)步驟:①钩蚊、繪制視圖的背景贡翘;②、保存畫(huà)布的圖層(Layer)砰逻;③鸣驱、繪制View的內(nèi)容;④蝠咆、繪制View子視圖踊东,如果沒(méi)有就不用;
⑤刚操、還原圖層(Layer)闸翅;⑥、繪制滾動(dòng)條菊霜。
12坚冀、View,ViewGroup事件分
- Touch事件分發(fā)中只有兩個(gè)主角:ViewGroup和View鉴逞。ViewGroup包含onInterceptTouchEvent遗菠、dispatchTouchEvent联喘、onTouchEvent三個(gè)相關(guān)事件。View包含dispatchTouchEvent辙纬、onTouchEvent兩個(gè)相關(guān)事件豁遭。其中ViewGroup又繼承于View。
2.ViewGroup和View組成了一個(gè)樹(shù)狀結(jié)構(gòu)贺拣,根節(jié)點(diǎn)為Activity內(nèi)部包含的一個(gè)ViwGroup蓖谢。
3.觸摸事件由Action_Down、Action_Move譬涡、Aciton_UP組成闪幽,其中一次完整的觸摸事件中,Down和Up都只有一個(gè)涡匀,Move有若干個(gè)盯腌,可以為0個(gè)。
4.當(dāng)Acitivty接收到Touch事件時(shí)陨瘩,將遍歷子View進(jìn)行Down事件的分發(fā)腕够。ViewGroup的遍歷可以看成是遞歸的。分發(fā)的目的是為了找到真正要處理本次完整觸摸事件的View舌劳,這個(gè)View會(huì)在onTouchuEvent結(jié)果返回true帚湘。
5.當(dāng)某個(gè)子View返回true時(shí),會(huì)中止Down事件的分發(fā)甚淡,同時(shí)在ViewGroup中記錄該子View大诸。接下去的Move和Up事件將由該子View直接進(jìn)行處理。由于子View是保存在ViewGroup中的贯卦,多層ViewGroup的節(jié)點(diǎn)結(jié)構(gòu)時(shí)资柔,上級(jí)ViewGroup保存的會(huì)是真實(shí)處理事件的View所在的ViewGroup對(duì)象:如ViewGroup0-ViewGroup1-TextView的結(jié)構(gòu)中,TextView返回了true撵割,它將被保存在ViewGroup1中贿堰,而ViewGroup1也會(huì)返回true,被保存在ViewGroup0中睁枕。當(dāng)Move和UP事件來(lái)時(shí)官边,會(huì)先從ViewGroup0傳遞至ViewGroup1沸手,再由ViewGroup1傳遞至TextView外遇。
6.當(dāng)ViewGroup中所有子View都不捕獲Down事件時(shí),將觸發(fā)ViewGroup自身的onTouch事件契吉。觸發(fā)的方式是調(diào)用super.dispatchTouchEvent函數(shù)跳仿,即父類View的dispatchTouchEvent方法。在所有子View都不處理的情況下捐晶,觸發(fā)Acitivity的onTouchEvent方法菲语。
7.onInterceptTouchEvent有兩個(gè)作用:1.攔截Down事件的分發(fā)妄辩。2.中止Up和Move事件向目標(biāo)View傳遞,使得目標(biāo)View所在的ViewGroup捕獲Up和Move事件山上。
13眼耀、保存Activity狀態(tài)
onSaveInstanceState(Bundle)會(huì)在activity轉(zhuǎn)入后臺(tái)狀態(tài)之前被調(diào)用,也就是onStop()方法之前佩憾,onPause方法之后被調(diào)用哮伟;
14、Android中的幾種動(dòng)畫(huà)
幀動(dòng)畫(huà):指通過(guò)指定每一幀的圖片和播放時(shí)間妄帘,有序的進(jìn)行播放而形成動(dòng)畫(huà)效果楞黄,比如想聽(tīng)的律動(dòng)條。
補(bǔ)間動(dòng)畫(huà):指通過(guò)指定View的初始狀態(tài)抡驼、變化時(shí)間鬼廓、方式,通過(guò)一系列的算法去進(jìn)行圖形變換致盟,從而形成動(dòng)畫(huà)效果碎税,主要有Alpha、Scale勾邦、Translate蚣录、Rotate四種效果。注意:只是在視圖層實(shí)現(xiàn)了動(dòng)畫(huà)效果眷篇,并沒(méi)有真正改變View的屬性萎河,比如滑動(dòng)列表,改變標(biāo)題欄的透明度蕉饼。
屬性動(dòng)畫(huà):在Android3.0的時(shí)候才支持虐杯,通過(guò)不斷的改變View的屬性,不斷的重繪而形成動(dòng)畫(huà)效果昧港。相比于視圖動(dòng)畫(huà)擎椰,View的屬性是真正改變了。比如view的旋轉(zhuǎn)创肥,放大达舒,縮小。
15叹侄、Android中跨進(jìn)程通訊的幾種方式
Android 跨進(jìn)程通信巩搏,像intent,contentProvider,廣播趾代,service都可以跨進(jìn)程通信贯底。
intent:這種跨進(jìn)程方式并不是訪問(wèn)內(nèi)存的形式,它需要傳遞一個(gè)uri,比如說(shuō)打電話撒强。
contentProvider:這種形式禽捆,是使用數(shù)據(jù)共享的形式進(jìn)行數(shù)據(jù)共享笙什。
service:遠(yuǎn)程服務(wù),aidl
廣播
16胚想、AIDL理解
此處延伸:簡(jiǎn)述Binder
AIDL: 每一個(gè)進(jìn)程都有自己的Dalvik VM實(shí)例琐凭,都有自己的一塊獨(dú)立的內(nèi)存,都在自己的內(nèi)存上存儲(chǔ)自己的數(shù)據(jù)浊服,執(zhí)行著自己的操作淘正,都在自己的那片狹小的空間里過(guò)完自己的一生。而aidl就類似與兩個(gè)進(jìn)程之間的橋梁臼闻,使得兩個(gè)進(jìn)程之間可以進(jìn)行數(shù)據(jù)的傳輸鸿吆,跨進(jìn)程通信有多種選擇,比如 BroadcastReceiver , Messenger 等述呐,但是 BroadcastReceiver 占用的系統(tǒng)資源比較多惩淳,如果是頻繁的跨進(jìn)程通信的話顯然是不可取的;Messenger 進(jìn)行跨進(jìn)程通信時(shí)請(qǐng)求隊(duì)列是同步進(jìn)行的乓搬,無(wú)法并發(fā)執(zhí)行思犁。
Binde機(jī)制簡(jiǎn)單理解:
大角度來(lái)說(shuō)為啥要用進(jìn)程通訊:
進(jìn)程間,用戶空間的數(shù)據(jù)不可共享进肯,所以用戶空間 = 不可共享空間
進(jìn)程間激蹲,內(nèi)核空間的數(shù)據(jù)可共享,所以內(nèi)核空間 = 可共享空間 江掩。
在Android系統(tǒng)的Binder機(jī)制中学辱,是有Client,Service,ServiceManager,Binder驅(qū)動(dòng)程序組成的,其中Client环形,service策泣,Service Manager運(yùn)行在用戶空間,Binder驅(qū)動(dòng)程序是運(yùn)行在內(nèi)核空間的抬吟。而B(niǎo)inder就是把這4種組件粘合在一塊的粘合劑萨咕,其中核心的組件就是Binder驅(qū)動(dòng)程序,Service Manager提供輔助管理的功能火本,而Client和Service正是在Binder驅(qū)動(dòng)程序和Service Manager提供的基礎(chǔ)設(shè)施上實(shí)現(xiàn)C/S 之間的通信危队。其中Binder驅(qū)動(dòng)程序提供設(shè)備文件/dev/binder與用戶控件進(jìn)行交互,
Client茫陆、Service盅弛,Service Manager通過(guò)open和ioctl文件操作相應(yīng)的方法與Binder驅(qū)動(dòng)程序進(jìn)行通信钱骂。而Client和Service之間的進(jìn)程間通信是通過(guò)Binder驅(qū)動(dòng)程序間接實(shí)現(xiàn)的叔锐。而B(niǎo)inder Manager是一個(gè)守護(hù)進(jìn)程挪鹏,用來(lái)管理Service,并向Client提供查詢Service接口的能力愉烙。
17讨盒、Handler的原理
Android中主線程是不能進(jìn)行耗時(shí)操作的,子線程是不能進(jìn)行更新UI的步责。所以就有了handler返顺,它的作用就是實(shí)現(xiàn)線程之間的通信。
handler整個(gè)流程中蔓肯,主要有四個(gè)對(duì)象遂鹊,handler,Message,MessageQueue,Looper蔗包。當(dāng)應(yīng)用創(chuàng)建的時(shí)候秉扑,就會(huì)在主線程中創(chuàng)建handler對(duì)象,
我們通過(guò)要傳送的消息保存到Message中调限,handler通過(guò)調(diào)用sendMessage方法將Message發(fā)送到MessageQueue中舟陆,Looper對(duì)象就會(huì)不斷的調(diào)用loop()方法
不斷的從MessageQueue中取出Message交給handler進(jìn)行處理。從而實(shí)現(xiàn)線程之間的通信耻矮。
19秦躯、熱修復(fù)的原理
我們知道Java虛擬機(jī) —— JVM 是加載類的class文件的,而Android虛擬機(jī)——Dalvik/ART VM 是加載類的dex文件裆装,
而他們加載類的時(shí)候都需要ClassLoader,ClassLoader有一個(gè)子類BaseDexClassLoader踱承,而B(niǎo)aseDexClassLoader下有一個(gè)
數(shù)組——DexPathList,是用來(lái)存放dex文件哨免,當(dāng)BaseDexClassLoader通過(guò)調(diào)用findClass方法時(shí)勾扭,實(shí)際上就是遍歷數(shù)組,
找到相應(yīng)的dex文件铁瞒,找到妙色,則直接將它return。而熱修復(fù)的解決方法就是將新的dex添加到該集合中慧耍,并且是在舊的dex的前面身辨,
所以就會(huì)優(yōu)先被取出來(lái)并且return返回。
20芍碧、Android內(nèi)存泄露及管理
(1)內(nèi)存溢出(OOM)和內(nèi)存泄露(對(duì)象無(wú)法被回收)的區(qū)別煌珊。
(2)引起內(nèi)存泄露的原因
(3) 內(nèi)存泄露檢測(cè)工具 ------>LeakCanary
內(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)存溢出。內(nèi)存溢出通俗的講就是內(nèi)存不夠用蔬浙。
內(nèi)存泄露 memory leak:是指程序在申請(qǐng)內(nèi)存后猪落,無(wú)法釋放已申請(qǐng)的內(nèi)存空間,一次內(nèi)存泄露危害可以忽略畴博,但內(nèi)存泄露堆積后果很?chē)?yán)重笨忌,無(wú)論多少內(nèi)存,遲早會(huì)被占光
內(nèi)存泄露原因:
一、Handler 引起的內(nèi)存泄漏俱病。
解決:將Handler聲明為靜態(tài)內(nèi)部類官疲,就不會(huì)持有外部類SecondActivity的引用,其生命周期就和外部類無(wú)關(guān)亮隙,
如果Handler里面需要context的話途凫,可以通過(guò)弱引用方式引用外部類
二、單例模式引起的內(nèi)存泄漏溢吻。
解決:Context是ApplicationContext颖榜,由于ApplicationContext的生命周期是和app一致的,不會(huì)導(dǎo)致內(nèi)存泄漏
三煤裙、非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實(shí)例引起的內(nèi)存泄漏掩完。
解決:把內(nèi)部類修改為靜態(tài)的就可以避免內(nèi)存泄漏了
四、非靜態(tài)匿名內(nèi)部類引起的內(nèi)存泄漏硼砰。
解決:將匿名內(nèi)部類設(shè)置為靜態(tài)的且蓬。
五、注冊(cè)/反注冊(cè)未成對(duì)使用引起的內(nèi)存泄漏题翰。
注冊(cè)廣播接受器恶阴、EventBus等,記得解綁豹障。
六冯事、資源對(duì)象沒(méi)有關(guān)閉引起的內(nèi)存泄漏。
在這些資源不使用的時(shí)候血公,記得調(diào)用相應(yīng)的類似close()昵仅、destroy()、recycler()累魔、release()等方法釋放摔笤。
七、集合對(duì)象沒(méi)有及時(shí)清理引起的內(nèi)存泄漏垦写。
通常會(huì)把一些對(duì)象裝入到集合中吕世,當(dāng)不使用的時(shí)候一定要記得及時(shí)清理集合,讓相關(guān)對(duì)象不再被引用梯投。
21命辖、Fragment與Fragment况毅、Activity通信的方式
1.直接在一個(gè)Fragment中調(diào)用另外一個(gè)Fragment中的方法
2.使用接口回調(diào)
3.使用廣播
4.Fragment直接調(diào)用Activity中的public方法
23、app優(yōu)化
app優(yōu)化:(工具:Hierarchy Viewer 分析布局 工具:TraceView 測(cè)試分析耗時(shí)的)
App啟動(dòng)優(yōu)化
布局優(yōu)化
響應(yīng)優(yōu)化
內(nèi)存優(yōu)化
電池使用優(yōu)化
網(wǎng)絡(luò)優(yōu)化
App啟動(dòng)優(yōu)化(針對(duì)冷啟動(dòng))
App啟動(dòng)的方式有三種:
冷啟動(dòng):App沒(méi)有啟動(dòng)過(guò)或App進(jìn)程被killed, 系統(tǒng)中不存在該App進(jìn)程, 此時(shí)啟動(dòng)App即為冷啟動(dòng)尔艇。
熱啟動(dòng):熱啟動(dòng)意味著你的App進(jìn)程只是處于后臺(tái), 系統(tǒng)只是將其從后臺(tái)帶到前臺(tái), 展示給用戶尔许。
介于冷啟動(dòng)和熱啟動(dòng)之間, 一般來(lái)說(shuō)在以下兩種情況下發(fā)生:
(1)用戶back退出了App, 然后又啟動(dòng). App進(jìn)程可能還在運(yùn)行, 但是activity需要重建。
(2)用戶退出App后, 系統(tǒng)可能由于內(nèi)存原因?qū)pp殺死, 進(jìn)程和activity都需要重啟, 但是可以在onCreate中將被動(dòng)殺死鎖保存的狀態(tài)(saved instance state)恢復(fù)漓帚。
優(yōu)化:
Application的onCreate(特別是第三方SDK初始化),首屏Activity的渲染都不要進(jìn)行耗時(shí)操作午磁,如果有尝抖,就可以放到子線程或者IntentService中
布局優(yōu)化
盡量不要過(guò)于復(fù)雜的嵌套⊙富剩可以使用<include>昧辽,<merge>,<ViewStub>
響應(yīng)優(yōu)化
Android系統(tǒng)每隔16ms會(huì)發(fā)出VSYNC信號(hào)重繪我們的界面(Activity)登颓。
頁(yè)面卡頓的原因:
(1)過(guò)于復(fù)雜的布局.
(2)UI線程的復(fù)雜運(yùn)算
(3)頻繁的GC,導(dǎo)致頻繁GC有兩個(gè)原因:1搅荞、內(nèi)存抖動(dòng), 即大量的對(duì)象被創(chuàng)建又在短時(shí)間內(nèi)馬上被釋放.2、瞬間產(chǎn)生大量的對(duì)象會(huì)嚴(yán)重占用內(nèi)存區(qū)域框咙。
內(nèi)存優(yōu)化:參考內(nèi)存泄露和內(nèi)存溢出部分
電池使用優(yōu)化(使用工具:Batterystats & bugreport)
(1)優(yōu)化網(wǎng)絡(luò)請(qǐng)求
(2)定位中使用GPS, 請(qǐng)記得及時(shí)關(guān)閉
網(wǎng)絡(luò)優(yōu)化(網(wǎng)絡(luò)連接對(duì)用戶的影響:流量,電量,用戶等待)可在Android studio下方logcat旁邊那個(gè)工具Network Monitor檢測(cè)
API設(shè)計(jì):App與Server之間的API設(shè)計(jì)要考慮網(wǎng)絡(luò)請(qǐng)求的頻次, 資源的狀態(tài)等. 以便App可以以較少的請(qǐng)求來(lái)完成業(yè)務(wù)需求和界面的展示.
Gzip壓縮:使用Gzip來(lái)壓縮request和response, 減少傳輸數(shù)據(jù)量, 從而減少流量消耗.
圖片的Size:可以在獲取圖片時(shí)告知服務(wù)器需要的圖片的寬高, 以便服務(wù)器給出合適的圖片, 避免浪費(fèi).
網(wǎng)絡(luò)緩存:適當(dāng)?shù)木彺? 既可以讓我們的應(yīng)用看起來(lái)更快, 也能避免一些不必要的流量消耗.
24咕痛、圖片優(yōu)化
(1)對(duì)圖片本身進(jìn)行操作。盡量不要使用setImageBitmap喇嘱、setImageResource茉贡、BitmapFactory.decodeResource來(lái)設(shè)置一張大圖,因?yàn)檫@些方法在完成decode后者铜,
最終都是通過(guò)java層的createBitmap來(lái)完成的腔丧,需要消耗更多內(nèi)存.
(2)圖片進(jìn)行縮放的比例,SDK中建議其值是2的指數(shù)值,值越大會(huì)導(dǎo)致圖片不清晰作烟。
(3)不用的圖片記得調(diào)用圖片的recycle()方法
25愉粤、HybridApp WebView和JS交互
Android與JS通過(guò)WebView互相調(diào)用方法,實(shí)際上是:
Android去調(diào)用JS的代碼
- 通過(guò)WebView的loadUrl(),使用該方法比較簡(jiǎn)潔拿撩,方便衣厘。但是效率比較低,獲取返回值比較困難压恒。
- 通過(guò)WebView的evaluateJavascript(),該方法效率高头滔,但是4.4以上的版本才支持,4.4以下版本不支持涎显。所以建議兩者混合使用坤检。
JS去調(diào)用Android的代碼 - 通過(guò)WebView的addJavascriptInterface()進(jìn)行對(duì)象映射 ,該方法使用簡(jiǎn)單期吓,僅將Android對(duì)象和JS對(duì)象映射即可早歇,但是存在比較大的漏洞倾芝。
漏洞產(chǎn)生原因是:當(dāng)JS拿到Android這個(gè)對(duì)象后,就可以調(diào)用這個(gè)Android對(duì)象中所有的方法箭跳,包括系統(tǒng)類(java.lang.Runtime 類)晨另,從而進(jìn)行任意代碼執(zhí)行。
解決方式:
(1)Google 在Android 4.2 版本中規(guī)定對(duì)被調(diào)用的函數(shù)以 @JavascriptInterface進(jìn)行注解從而避免漏洞攻擊谱姓。
(2)在Android 4.2版本之前采用攔截prompt()進(jìn)行漏洞修復(fù)借尿。
- 通過(guò) WebViewClient 的shouldOverrideUrlLoading ()方法回調(diào)攔截 url 。這種方式的優(yōu)點(diǎn):不存在方式1的漏洞屉来;缺點(diǎn):JS獲取Android方法的返回值復(fù)雜路翻。(ios主要用的是這個(gè)方式)
(1)Android通過(guò) WebViewClient 的回調(diào)方法shouldOverrideUrlLoading ()攔截 url
(2)解析該 url 的協(xié)議
(3)如果檢測(cè)到是預(yù)先約定好的協(xié)議,就調(diào)用相應(yīng)方法
- 通過(guò) WebChromeClient 的onJsAlert()茄靠、onJsConfirm()茂契、onJsPrompt()方法回調(diào)攔截JS對(duì)話框alert()、confirm()慨绳、prompt() 消息
這種方式的優(yōu)點(diǎn):不存在方式1的漏洞掉冶;缺點(diǎn):JS獲取Android方法的返回值復(fù)雜。
26脐雪、JAVA GC原理
垃圾收集算法的核心思想是:對(duì)虛擬機(jī)可用內(nèi)存空間厌小,即堆空間中的對(duì)象進(jìn)行識(shí)別,如果對(duì)象正在被引用战秋,那么稱其為存活對(duì)象
召锈,反之,如果對(duì)象不再被引用获询,則為垃圾對(duì)象涨岁,可以回收其占據(jù)的空間,用于再分配吉嚣。垃圾收集算法的選擇和垃圾收集系統(tǒng)參數(shù)的合理調(diào)節(jié)直接影響著系統(tǒng)性能梢薪。
27、ANR
ANR全名Application Not Responding, 也就是"應(yīng)用無(wú)響應(yīng)". 當(dāng)操作在一段時(shí)間內(nèi)系統(tǒng)無(wú)法處理時(shí), 系統(tǒng)層面會(huì)彈出上圖那樣的ANR對(duì)話框.
產(chǎn)生原因:
(1)5s內(nèi)無(wú)法響應(yīng)用戶輸入事件(例如鍵盤(pán)輸入, 觸摸屏幕等).
(2)BroadcastReceiver在10s內(nèi)無(wú)法結(jié)束
(3)Service 20s內(nèi)無(wú)法結(jié)束(低概率)
解決方式:
(1)不要在主線程中做耗時(shí)的操作尝哆,而應(yīng)放在子線程中來(lái)實(shí)現(xiàn)秉撇。如onCreate()和onResume()里盡可能少的去做創(chuàng)建操作。
(2)應(yīng)用程序應(yīng)該避免在BroadcastReceiver里做耗時(shí)的操作或計(jì)算秋泄。
(3)避免在Intent Receiver里啟動(dòng)一個(gè)Activity琐馆,因?yàn)樗鼤?huì)創(chuàng)建一個(gè)新的畫(huà)面,并從當(dāng)前用戶正在運(yùn)行的程序上搶奪焦點(diǎn)恒序。
(4)service是運(yùn)行在主線程的瘦麸,所以在service中做耗時(shí)操作,必須要放在子線程中歧胁。
32滋饲、JNI
(1)安裝和下載Cygwin厉碟,下載 Android NDK
(2)在ndk項(xiàng)目中JNI接口的設(shè)計(jì)
(3)使用C/C++實(shí)現(xiàn)本地方法
(4)JNI生成動(dòng)態(tài)鏈接庫(kù).so文件
(5)將動(dòng)態(tài)鏈接庫(kù)復(fù)制到j(luò)ava工程,在java工程中調(diào)用屠缭,運(yùn)行java工程即可
33箍鼓、RecyclerView和ListView的區(qū)別
RecyclerView可以完成ListView,GridView的效果,還可以完成瀑布流的效果呵曹。同時(shí)還可以設(shè)置列表的滾動(dòng)方向(垂直或者水平)款咖;
RecyclerView中view的復(fù)用不需要開(kāi)發(fā)者自己寫(xiě)代碼,系統(tǒng)已經(jīng)幫封裝完成了奄喂。
RecyclerView可以進(jìn)行局部刷新铐殃。
RecyclerView提供了API來(lái)實(shí)現(xiàn)item的動(dòng)畫(huà)效果。
在性能上:
如果需要頻繁的刷新數(shù)據(jù)砍聊,需要添加動(dòng)畫(huà)背稼,則RecyclerView有較大的優(yōu)勢(shì)贰军。
如果只是作為列表展示玻蝌,則兩者區(qū)別并不是很大。
34词疼、Universal-ImageLoader俯树,Picasso,F(xiàn)resco贰盗,Glide對(duì)比
Fresco 是 Facebook 推出的開(kāi)源圖片緩存工具许饿,主要特點(diǎn)包括:兩個(gè)內(nèi)存緩存加上 Native 緩存構(gòu)成了三級(jí)緩存烁试,
優(yōu)點(diǎn):
圖片存儲(chǔ)在安卓系統(tǒng)的匿名共享內(nèi)存, 而不是虛擬機(jī)的堆內(nèi)存中, 圖片的中間緩沖數(shù)據(jù)也存放在本地堆內(nèi)存, 所以, 應(yīng)用程序有更多的內(nèi)存使用, 不會(huì)因?yàn)閳D片加載而導(dǎo)致oom, 同時(shí)也減少垃圾回收器頻繁調(diào)用回收 Bitmap 導(dǎo)致的界面卡頓, 性能更高榛丢。
漸進(jìn)式加載 JPEG 圖片, 支持圖片從模糊到清晰加載寞奸。
圖片可以以任意的中心點(diǎn)顯示在 ImageView, 而不僅僅是圖片的中心嘁信。
JPEG 圖片改變大小也是在 native 進(jìn)行的, 不是在虛擬機(jī)的堆內(nèi)存, 同樣減少 OOM促绵。
很好的支持 GIF 圖片的顯示罢杉。
缺點(diǎn):
- 框架較大, 影響 Apk 體積
- 使用較繁瑣
Universal-ImageLoader:(估計(jì)由于HttpClient被Google放棄饱亿,作者就放棄維護(hù)這個(gè)框架)
優(yōu)點(diǎn):
1.支持下載進(jìn)度監(jiān)聽(tīng)
2.可以在 View 滾動(dòng)中暫停圖片加載修己,通過(guò) PauseOnScrollListener 接口可以在 View 滾動(dòng)中暫停圖片加載赴蝇。
3.默認(rèn)實(shí)現(xiàn)多種內(nèi)存緩存算法 這幾個(gè)圖片緩存都可以配置緩存算法菩浙,不過(guò) ImageLoader 默認(rèn)實(shí)現(xiàn)了較多緩存算法,如 Size 最大先刪除句伶、使用最少先刪除劲蜻、最近最少使用、先進(jìn)先刪除考余、時(shí)間最長(zhǎng)先刪除等先嬉。
4.支持本地緩存文件名規(guī)則定義
Picasso 優(yōu)點(diǎn)
- 自帶統(tǒng)計(jì)監(jiān)控功能。支持圖片緩存使用的監(jiān)控楚堤,包括緩存命中率坝初、已使用內(nèi)存大小浸剩、節(jié)省的流量等。
2.支持優(yōu)先級(jí)處理鳄袍。每次任務(wù)調(diào)度前會(huì)選擇優(yōu)先級(jí)高的任務(wù)绢要,比如 App 頁(yè)面中 Banner 的優(yōu)先級(jí)高于 Icon 時(shí)就很適用。
3.支持延遲到圖片尺寸計(jì)算完成加載
4.支持飛行模式拗小、并發(fā)線程數(shù)根據(jù)網(wǎng)絡(luò)類型而變重罪。 手機(jī)切換到飛行模式或網(wǎng)絡(luò)類型變換時(shí)會(huì)自動(dòng)調(diào)整線程池最大并發(fā)數(shù),比如 wifi 最大并發(fā)為 4哀九,4g 為 3剿配,3g 為 2。 這里 Picasso 根據(jù)網(wǎng)絡(luò)類型來(lái)決定最大并發(fā)數(shù)阅束,而不是 CPU 核數(shù)呼胚。
5.“無(wú)”本地緩存。無(wú)”本地緩存息裸,不是說(shuō)沒(méi)有本地緩存蝇更,而是 Picasso 自己沒(méi)有實(shí)現(xiàn),交給了 Square 的另外一個(gè)網(wǎng)絡(luò)庫(kù) okhttp 去實(shí)現(xiàn)呼盆,這樣的好處是可以通過(guò)請(qǐng)求 Response Header 中的 Cache-Control 及 Expired 控制圖片的過(guò)期時(shí)間年扩。
Glide 優(yōu)點(diǎn)
不僅僅可以進(jìn)行圖片緩存還可以緩存媒體文件。Glide 不僅是一個(gè)圖片緩存访圃,它支持 Gif厨幻、WebP、縮略圖腿时。甚至是 Video况脆,所以更該當(dāng)做一個(gè)媒體緩存。
支持優(yōu)先級(jí)處理批糟。
與 Activity/Fragment 生命周期一致格了,支持 trimMemory。Glide 對(duì)每個(gè) context 都保持一個(gè) RequestManager跃赚,通過(guò) FragmentTransaction 保持與 Activity/Fragment 生命周期一致笆搓,并且有對(duì)應(yīng)的 trimMemory 接口實(shí)現(xiàn)可供調(diào)用。
支持 okhttp纬傲、Volley满败。Glide 默認(rèn)通過(guò) UrlConnection 獲取數(shù)據(jù),可以配合 okhttp 或是 Volley 使用叹括。實(shí)際 ImageLoader算墨、Picasso 也都支持 okhttp、Volley汁雷。
內(nèi)存友好净嘀。Glide 的內(nèi)存緩存有個(gè) active 的設(shè)計(jì)报咳,從內(nèi)存緩存中取數(shù)據(jù)時(shí),不像一般的實(shí)現(xiàn)用 get挖藏,而是用 remove暑刃,再將這個(gè)緩存數(shù)據(jù)放到一個(gè) value 為軟引用的 activeResources map 中,并計(jì)數(shù)引用數(shù)膜眠,在圖片加載完成后進(jìn)行判斷岩臣,如果引用計(jì)數(shù)為空則回收掉。內(nèi)存緩存更小圖片宵膨,Glide 以 url架谎、view_width、view_height辟躏、屏幕的分辨率等做為聯(lián)合 key谷扣,將處理后的圖片緩存在內(nèi)存緩存中,而不是原始圖片以節(jié)省大小與 Activity/Fragment 生命周期一致捎琐,支持 trimMemory会涎。圖片默認(rèn)使用默認(rèn) RGB_565 而不是 ARGB_888,雖然清晰度差些野哭,但圖片更小在塔,也可配置到 ARGB_888幻件。
6.Glide 可以通過(guò) signature 或不使用本地緩存支持 url 過(guò)期
Java
1拨黔、線程中sleep和wait的區(qū)別
(1)這兩個(gè)方法來(lái)自不同的類,sleep是來(lái)自Thread绰沥,wait是來(lái)自O(shè)bject篱蝇;
(2)sleep方法沒(méi)有釋放鎖,而wait方法釋放了鎖徽曲。
(3)wait,notify,notifyAll只能在同步控制方法或者同步控制塊里面使用零截,而sleep可以在任何地方使用。
2秃臣、Thread中的start()和run()方法有什么區(qū)別
start()方法是用來(lái)啟動(dòng)新創(chuàng)建的線程涧衙,而start()內(nèi)部調(diào)用了run()方法,這和直接調(diào)用run()方法是不一樣的奥此,如果直接調(diào)用run()方法弧哎,
則和普通的方法沒(méi)有什么區(qū)別。
3稚虎、關(guān)鍵字final和static是怎么使用的撤嫩。
final:
1、final變量即為常量蠢终,只能賦值一次序攘。
2茴她、final方法不能被子類重寫(xiě)。
3程奠、final類不能被繼承丈牢。
static:
1、static變量:對(duì)于靜態(tài)變量在內(nèi)存中只有一個(gè)拷貝(節(jié)省內(nèi)存)瞄沙,JVM只為靜態(tài)分配一次內(nèi)存赡麦,
在加載類的過(guò)程中完成靜態(tài)變量的內(nèi)存分配,可用類名直接訪問(wèn)(方便)帕识,當(dāng)然也可以通過(guò)對(duì)象來(lái)訪問(wèn)(但是這是不推薦的)泛粹。
2、static代碼塊
static代碼塊是類加載時(shí)肮疗,初始化自動(dòng)執(zhí)行的晶姊。
3、static方法
static方法可以直接通過(guò)類名調(diào)用伪货,任何的實(shí)例也都可以調(diào)用们衙,因此static方法中不能用this和super關(guān)鍵字,
不能直接訪問(wèn)所屬類的實(shí)例變量和實(shí)例方法(就是不帶static的成員變量和成員成員方法)碱呼,只能訪問(wèn)所屬類的靜態(tài)成員變量和成員方法蒙挑。
4、String,StringBuffer,StringBuilder區(qū)別
1愚臀、三者在執(zhí)行速度上:StringBuilder > StringBuffer > String (由于String是常量忆蚀,不可改變,拼接時(shí)會(huì)重新創(chuàng)建新的對(duì)象)姑裂。
2馋袜、StringBuffer是線程安全的,StringBuilder是線程不安全的舶斧。(由于StringBuffer有緩沖區(qū))
5欣鳖、Java中重載和重寫(xiě)的區(qū)別:
1、重載:一個(gè)類中可以有多個(gè)相同方法名的茴厉,但是參數(shù)類型和個(gè)數(shù)都不一樣泽台。這是重載。
2矾缓、重寫(xiě):子類繼承父類怀酷,則子類可以通過(guò)實(shí)現(xiàn)父類中的方法,從而新的方法把父類舊的方法覆蓋而账。
6胰坟、Http https區(qū)別
此處延伸:https的實(shí)現(xiàn)原理
1、https協(xié)議需要到ca申請(qǐng)證書(shū),一般免費(fèi)證書(shū)較少笔横,因而需要一定費(fèi)用竞滓。
2、http是超文本傳輸協(xié)議吹缔,信息是明文傳輸商佑,https則是具有安全性的ssl加密傳輸協(xié)議。
3厢塘、http和https使用的是完全不同的連接方式茶没,用的端口也不一樣,前者是80晚碾,后者是443抓半。
4、http的連接很簡(jiǎn)單格嘁,是無(wú)狀態(tài)的笛求;HTTPS協(xié)議是由SSL+HTTP協(xié)議構(gòu)建的可進(jìn)行加密傳輸、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議糕簿,比http協(xié)議安全探入。
https實(shí)現(xiàn)原理:
(1)客戶使用https的URL訪問(wèn)Web服務(wù)器,要求與Web服務(wù)器建立SSL連接懂诗。
(2)Web服務(wù)器收到客戶端請(qǐng)求后蜂嗽,會(huì)將網(wǎng)站的證書(shū)信息(證書(shū)中包含公鑰)傳送一份給客戶端。
(3)客戶端的瀏覽器與Web服務(wù)器開(kāi)始協(xié)商SSL連接的安全等級(jí)殃恒,也就是信息加密的等級(jí)植旧。
(4)客戶端的瀏覽器根據(jù)雙方同意的安全等級(jí),建立會(huì)話密鑰芋类,然后利用網(wǎng)站的公鑰將會(huì)話密鑰加密隆嗅,并傳送給網(wǎng)站界阁。
(5)Web服務(wù)器利用自己的私鑰解密出會(huì)話密鑰侯繁。
(6)Web服務(wù)器利用會(huì)話密鑰加密與客戶端之間的通信。
7泡躯、Http位于TCP/IP模型中的第幾層贮竟?為什么說(shuō)Http是可靠的數(shù)據(jù)傳輸協(xié)議?
tcp/ip的五層模型:
從下到上:物理層->數(shù)據(jù)鏈路層->網(wǎng)絡(luò)層->傳輸層->應(yīng)用層
其中tcp/ip位于模型中的網(wǎng)絡(luò)層较剃,處于同一層的還有ICMP(網(wǎng)絡(luò)控制信息協(xié)議)咕别。http位于模型中的應(yīng)用層
由于tcp/ip是面向連接的可靠協(xié)議,而http是在傳輸層基于tcp/ip協(xié)議的写穴,所以說(shuō)http是可靠的數(shù)據(jù)傳輸協(xié)議惰拱。
8、HTTP鏈接的特點(diǎn)
HTTP連接最顯著的特點(diǎn)是客戶端發(fā)送的每次請(qǐng)求都需要服務(wù)器回送響應(yīng)啊送,在請(qǐng)求結(jié)束后偿短,會(huì)主動(dòng)釋放連接欣孤。
從建立連接到關(guān)閉連接的過(guò)程稱為“一次連接”。
9昔逗、TCP和UDP的區(qū)別
tcp是面向連接的降传,由于tcp連接需要三次握手,所以能夠最低限度的降低風(fēng)險(xiǎn)勾怒,保證連接的可靠性婆排。
udp 不是面向連接的,udp建立連接前不需要與對(duì)象建立連接笔链,無(wú)論是發(fā)送還是接收段只,都沒(méi)有發(fā)送確認(rèn)信號(hào)。所以說(shuō)udp是不可靠的鉴扫。
由于udp不需要進(jìn)行確認(rèn)連接翼悴,使得UDP的開(kāi)銷(xiāo)更小,傳輸速率更高幔妨,所以實(shí)時(shí)行更好鹦赎。
10、Socket建立網(wǎng)絡(luò)連接的步驟
建立Socket連接至少需要一對(duì)套接字误堡,其中一個(gè)運(yùn)行與客戶端--ClientSocket古话,一個(gè)運(yùn)行于服務(wù)端--ServiceSocket
1、服務(wù)器監(jiān)聽(tīng):服務(wù)器端套接字并不定位具體的客戶端套接字锁施,而是處于等待連接的狀態(tài)陪踩,實(shí)時(shí)監(jiān)控網(wǎng)絡(luò)狀態(tài),等待客戶端的連接請(qǐng)求悉抵。
2肩狂、客戶端請(qǐng)求:指客戶端的套接字提出連接請(qǐng)求,要連接的目標(biāo)是服務(wù)器端的套接字姥饰。注意:客戶端的套接字必須描述他要連接的服務(wù)器的套接字傻谁,
指出服務(wù)器套接字的地址和端口號(hào),然后就像服務(wù)器端套接字提出連接請(qǐng)求列粪。
3审磁、連接確認(rèn):當(dāng)服務(wù)器端套接字監(jiān)聽(tīng)到客戶端套接字的連接請(qǐng)求時(shí),就響應(yīng)客戶端套接字的請(qǐng)求岂座,建立一個(gè)新的線程态蒂,把服務(wù)器端套接字的描述
發(fā)給客戶端,一旦客戶端確認(rèn)了此描述费什,雙方就正式建立連接钾恢。而服務(wù)端套接字則繼續(xù)處于監(jiān)聽(tīng)狀態(tài),繼續(xù)接收其他客戶端套接字的連接請(qǐng)求。