一線公司面試題寶典

國內一線互聯網公司內部面試題庫,從一個老碼農轉載的

以下面試題來自於百度、小米、樂視、美團、58、獵豹、360、新浪、搜狐內部題庫

熟悉本文中列出的知識點會大大增加通過前兩輪技術面試的機率。

歡迎一線公司員工提交內部面試題庫,歡迎star。

一、java基礎

1.接口的意義(百度)

規範、擴展、回調

2.抽象類的意義(樂視)

爲其子類提供一個公共的類型 封裝子類中得重複內容 定義抽象方法,子類雖然有不同的實現 但是定義是一致的

3.內部類的作用(百度,樂視)

內部類可以用多個實例,每個實例都有自己的狀態信息,並且與其他外圍對象的信息相互獨立。
在單個外圍類中,可以讓多個內部類以不同的方式實現同一個接口,或者繼承同一個類。
創建內部類對象的時刻並不依賴於外圍類對象的創建。
內部類並沒有令人迷惑的“is-a”關係,他就是一個獨立的實體。
內部類提供了更好的封裝,除了該外圍類,其他類都不能訪問
4.父類的靜態方法能否被子類重寫,爲什麼?(獵豹)

不能

子類繼承父類後,用相同的靜態方法和非靜態方法,這時非靜態方法覆蓋父類中的方法(即方法重寫),父類的該靜態方法被隱藏(如果對象是父類則調用該隱藏的方法),另外子類可繼承父類的靜態與非靜態方法,至於方法重載我覺得它其中一要素就是在同一類中,不能說父類中的什麼方法與子類裏的什麼方法是方法重載的體現

5.舉1-2個排序算法,並使用java代碼實現(美團)

http://blog.csdn.net/qy1387/article/details/7752973

6.列舉java的集合和繼承關係(百度、美團)

7.java虛擬機的特性(百度、樂視)

Java語言的一個非常重要的特點就是與平臺的無關性。而使用Java虛擬機是實現這一特點的關鍵。一般的高級語言如果要在不同的平臺上運行,至少需要編譯成不同的目標代碼。而引入Java語言虛擬機後,Java語言在不同平臺上運行時不需要重新編譯。Java語言使用模式Java虛擬機屏蔽了與具體平臺相關的信息,使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就可以在多種平臺上不加修改地運行。Java虛擬機在執行字節碼時,把字節碼解釋成具體平臺上的機器指令執行。

8.哪些情況下的對象會被垃圾回收機制處理掉(樂視、美團、小米)

Java 垃圾回收機制最基本的做法是分代回收。內存中的區域被劃分成不同的世代,對象根據其存活的時間被保存在對應世代的區域中。一般的實現是劃分成3個世代:年輕、年老和永久。內存的分配是發生在年輕世代中的。當一個對象存活時間足夠長的時候,它就會被複制到年老世代中。對於不同的世代可以使用不同的垃圾回收算法。進行世代劃分的出發點是對應用中對象存活時間進行研究之後得出的統計規律。一般來說,一個應用中的大部分對象的存活時間都很短。比如局部變量的存活時間就只在方法的執行過程中。基於這一點,對於年輕世代的垃圾回收算法就可以很有針對性。

9.進程和線程的區別(獵豹)

簡而言之,一個程序至少有一個進程,一個進程至少有一個線程。

線程的劃分尺度小於進程,使得多線程程序的併發性高。

另外,進程在執行過程中擁有獨立的內存單元,而多個線程共享內存,從而極大地提高了程序的運行效率。

線程在執行過程中與進程還是有區別的。每個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口。但是線程不能夠獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。

從邏輯角度來看,多線程的意義在於一個應用程序中,有多個執行部分可以同時執行。但操作系統並沒有將多個線程看做多個獨立的應用,來實現進程的調度和管理以及資源分配。這就是進程和線程的重要區別。

進程是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位.

線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源.

一個線程可以創建和撤銷另一個線程;同一個進程中的多個線程之間可以併發執行.

進程和線程的主要差別在於它們是不同的操作系統資源管理方式。進程有獨立的地址空間,一個進程崩潰後,在保護模式下不會對其它進程產生影響,而線程只是一個進程中的不同執行路徑。線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等於整個進程死掉,所以多進程的程序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對於一些要求同時進行並且又要共享某些變量的併發操作,只能用線程,不能用進程。如果有興趣深入的話,我建議你們看看《現代操作系統》或者《操作系統的設計與實現》。對就個問題說得比較清楚。

10.Java中==和equals的區別,equals和hashCode的區別(樂視)

http://blog.csdn.net/tiantiandjava/article/details/46988461

11.常見的排序算法時間複雜度(小米)

12.HashMap的實現原理(美團)

HashMap概述: HashMap是基於哈希表的Map接口的非同步實現。此實現提供所有可選的映射操作,並允許使用null值和null鍵。此類不保證映射的順序,特別是它不保證該順序恆久不變。
HashMap的數據結構: 在java編程語言中,最基本的結構就是兩種,一個是數組,另外一個是模擬指針(引用),所有的數據結構都可以用這兩個基本結構來構造的,HashMap也不例外。HashMap實際上是一個“鏈表散列”的數據結構,即數組和鏈表的結合體。

從上圖中可以看出,HashMap底層就是一個數組結構,數組中的每一項又是一個鏈表。當新建一個HashMap的時候,就會初始化一個數組。

13.java 狀態機

http://www.jdon.com/designpatterns/designpattern_State.htm

14.java中int char long各佔多少字節數

byte 位數 8 字節數 1

short 16 2

int 32 4

long 64 8

float 32 4

double 64 8

char 16 2

15.java int與integer的區別

http://www.cnblogs.com/shenliang ... /10/27/2226903.html

16.string stringbuffer stringbuilder 區別(小米、樂視、百度)

String 字符串常量

StringBuffer 字符串變量(線程安全)

StringBuilder 字符串變量(非線程安全)

簡要的說, String 類型和 StringBuffer 類型的主要性能區別其實在於 String 是不可變的對象, 因此在每次對 String 類型進行改變的時候其實都等同於生成了一個新的 String 對象,然後將指針指向新的 String 對象,所以經常改變內容的字符串最好不要用String ,因爲每次生成對象都會對系統性能產生影響,特別當內存中無引用對象多了以後,JVM 的 GC 就會開始工作,那速度是一定會相當慢的。

而如果是使用 StringBuffer 類則結果就不一樣了,每次結果都會對 StringBuffer 對象本身進行操作,而不是生成新的對象,再改變對象引用。所以在一般情況下我們推薦使用 StringBuffer ,特別是字符串對象經常改變的情況下。而在某些特別情況下, String 對象的字符串拼接其實是被 JVM 解釋成了 StringBuffer 對象的拼接,所以這些時候 String 對象的速度並不會比 StringBuffer 對象慢,而特別是以下的字符串對象生成中, String 效率是遠要比 StringBuffer 快的:

String S1 = “This is only a” + “ simple” + “ test”;

StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”); 你會很驚訝的發現,生成 String S1 對象的速度簡直太快了,而這個時候 StringBuffer 居然速度上根本一點都不佔優勢。其實這是 JVM 的一個把戲,在 JVM 眼裏,這個 String S1 = “This is only a” + “ simple” + “test”; 其實就是: String S1 = “This is only a simple test”; 所以當然不需要太多的時間了。但大家這裏要注意的是,如果你的字符串是來自另外的 String 對象的話,速度就沒那麼快了,譬如: String S2 = “This is only a”; String S3 = “ simple”; String S4 = “ test”; String S1 = S2 +S3 + S4; 這時候 JVM 會規規矩矩的按照原來的方式去做

在大部分情況下 StringBuffer > String

StringBuffer

Java.lang.StringBuffer線程安全的可變字符序列。一個類似於 String 的字符串緩衝區,但不能修改。雖然在任意時間點上它都包含某種特定的字符序列,但通過某些方法調用可以改變該序列的長度和內容。

可將字符串緩衝區安全地用於多個線程。可以在必要時對這些方法進行同步,因此任意特定實例上的所有操作就好像是以串行順序發生的,該順序與所涉及的每個線程進行的方法調用順序一致。

StringBuffer 上的主要操作是 append 和 insert 方法,可重載這些方法,以接受任意類型的數據。每個方法都能有效地將給定的數據轉換成字符串,然後將該字符串的字符追加或插入到字符串緩衝區中。append 方法始終將這些字符添加到緩衝區的末端;而 insert 方法則在指定的點添加字符。

例如,如果 z 引用一個當前內容是“start”的字符串緩衝區對象,則此方法調用 z.append("le") 會使字符串緩衝區包含“startle”,而 z.insert(4, "le") 將更改字符串緩衝區,使之包含“starlet”。

在大部分情況下 StringBuilder > StringBuffer

java.lang.StringBuilder

java.lang.StringBuilder一個可變的字符序列是5.0新增的。此類提供一個與 StringBuffer 兼容的 API,但不保證同步。該類被設計用作 StringBuffer 的一個簡易替換,用在字符串緩衝區被單個線程使用的時候(這種情況很普遍)。如果可能,建議優先採用該類,因爲在大多數實現中,它比 StringBuffer 要快。兩者的方法基本相同

17.Java多態(樂視)

Java多態性理解

Java中多態性的實現

什麼是多態

面向對象的三大特性:封裝、繼承、多態。從一定角度來看,封裝和繼承幾乎都是爲多態而準備的。這是我們最後一個概念,也是最重要的知識點。

多態的定義:指允許不同類的對象對同一消息做出響應。即同一消息可以根據發送對象的不同而採用多種不同的行爲方式。(發送消息就是函數調用)

實現多態的技術稱爲:動態綁定(dynamic binding),是指在執行期間判斷所引用對象的實 際類型,根據其實際的類型調用其相應的方法。

多態的作用:消除類型之間的耦合關係。

現實中,關於多態的例子不勝枚舉。比方說按下 F1 鍵這個動作,如果當前在 Flash 界面下彈出的就是 AS 3 的幫助文檔;如果當前在 Word 下彈出的就是 Word 幫助;在 Windows 下彈出的就是 Windows 幫助和支持。同一個事件發生在不同的對象上會產生不同的結果。 下面是多態存在的三個必要條件,要求大家做夢時都能背出來!

多態存在的三個必要條件 一、要有繼承; 二、要有重寫; 三、父類引用指向子類對象。

多態的好處:

1.可替換性(substitutability)。多態對已存在代碼具有可替換性。例如,多態對圓Circle類工作,對其他任何圓形幾何體,如圓環,也同樣工作。

2.可擴充性(extensibility)。多態對代碼具有可擴充性。增加新的子類不影響已存在類的多態性、繼承性,以及其他特性的運行和操作。實際上新加子類更容易獲得多態功能。例如,在實現了圓錐、半圓錐以及半球體的多態基礎上,很容易增添球體類的多態性。

3.接口性(interface-ability)。多態是超類通過方法簽名,向子類提供了一個共同接口,由子類來完善或者覆蓋它而實現的。如圖8.3 所示。圖中超類Shape規定了兩個實現多態的接口方法,computeArea()以及computeVolume()。子類,如Circle和Sphere爲了實現多態,完善或者覆蓋這兩個接口方法。

4.靈活性(flexibility)。它在應用中體現了靈活多樣的操作,提高了使用效率。

5.簡化性(simplicity)。多態簡化對應用軟件的代碼編寫和修改過程,尤其在處理大量對象的運算和操作時,這個特點尤爲突出和重要。

Java中多態的實現方式:接口實現,繼承父類進行方法重寫,同一個類中進行方法重載。

18.什麼導致線程阻塞(58、美團)

線程的阻塞

爲了解決對共享存儲區的訪問衝突,Java 引入了同步機制,現在讓我們來考察多個線程對共享資源的訪問,顯然同步機制已經不夠了,因爲在任意時刻所要求的資源不一定已經準備好了被訪問,反過來,同一時刻準備好了的資源也可能不止一個。爲了解決這種情況下的訪問控制問題,Java 引入了對阻塞機制的支持.

阻塞指的是暫停一個線程的執行以等待某個條件發生(如某資源就緒),學過操作系統的同學對它一定已經很熟悉了。Java 提供了大量方法來支持阻塞,下面讓我們逐一分析。

sleep() 方法:sleep() 允許 指定以毫秒爲單位的一段時間作爲參數,它使得線程在指定的時間內進入阻塞狀態,不能得到CPU 時間,指定的時間一過,線程重新進入可執行狀態。 典型地,sleep() 被用在等待某個資源就緒的情形:測試發現條件不滿足後,讓線程阻塞一段時間後重新測試,直到條件滿足爲止。
suspend() 和 resume() 方法:兩個方法配套使用,suspend()使得線程進入阻塞狀態,並且不會自動恢復,必須其對應的resume() 被調用,才能使得線程重新進入可執行狀態。典型地,suspend() 和 resume() 被用在等待另一個線程產生的結果的情形:測試發現結果還沒有產生後,讓線程阻塞,另一個線程產生了結果後,調用 resume() 使其恢復。
yield() 方法:yield() 使得線程放棄當前分得的 CPU 時間,但是不使線程阻塞,即線程仍處於可執行狀態,隨時可能再次分得 CPU 時間。調用 yield() 的效果等價於調度程序認爲該線程已執行了足夠的時間從而轉到另一個線程.
wait() 和 notify() 方法:兩個方法配套使用,wait() 使得線程進入阻塞狀態,它有兩種形式,一種允許 指定以毫秒爲單位的一段時間作爲參數,另一種沒有參數,前者當對應的 notify() 被調用或者超出指定時間時線程重新進入可執行狀態,後者則必須對應的 notify() 被調用.
初看起來它們與 suspend() 和 resume() 方法對沒有什麼分別,但是事實上它們是截然不同的。區別的核心在於,前面敘述的所有方法,阻塞時都不會釋放佔用的鎖(如果佔用了的話),而這一對方法則相反。

上述的核心區別導致了一系列的細節上的區別。

首先,前面敘述的所有方法都隸屬於 Thread 類,但是這一對卻直接隸屬於 Object 類,也就是說,所有對象都擁有這一對方法。初看起來這十分不可思議,但是實際上卻是很自然的,因爲這一對方法阻塞時要釋放佔用的鎖,而鎖是任何對象都具有的,調用任意對象的 wait() 方法導致線程阻塞,並且該對象上的鎖被釋放。而調用 任意對象的notify()方法則導致因調用該對象的 wait() 方法而阻塞的線程中隨機選擇的一個解除阻塞(但要等到獲得鎖後才真正可執行)。

其次,前面敘述的所有方法都可在任何位置調用,但是這一對方法卻必須在 synchronized 方法或塊中調用,理由也很簡單,只有在synchronized 方法或塊中當前線程才佔有鎖,纔有鎖可以釋放。同樣的道理,調用這一對方法的對象上的鎖必須爲當前線程所擁有,這樣纔有鎖可以釋放。因此,這一對方法調用必須放置在這樣的 synchronized 方法或塊中,該方法或塊的上鎖對象就是調用這一對方法的對象。若不滿足這一條件,則程序雖然仍能編譯,但在運行時會出現IllegalMonitorStateException 異常。

wait() 和 notify() 方法的上述特性決定了它們經常和synchronized 方法或塊一起使用,將它們和操作系統的進程間通信機制作一個比較就會發現它們的相似性:synchronized方法或塊提供了類似於操作系統原語的功能,它們的執行不會受到多線程機制的干擾,而這一對方法則相當於 block 和wakeup 原語(這一對方法均聲明爲 synchronized)。它們的結合使得我們可以實現操作系統上一系列精妙的進程間通信的算法(如信號量算法),並用於解決各種複雜的線程間通信問題。

關於 wait() 和 notify() 方法最後再說明兩點:

第一:調用 notify() 方法導致解除阻塞的線程是從因調用該對象的 wait() 方法而阻塞的線程中隨機選取的,我們無法預料哪一個線程將會被選擇,所以編程時要特別小心,避免因這種不確定性而產生問題。

第二:除了 notify(),還有一個方法 notifyAll() 也可起到類似作用,唯一的區別在於,調用 notifyAll() 方法將把因調用該對象的 wait() 方法而阻塞的所有線程一次性全部解除阻塞。當然,只有獲得鎖的那一個線程才能進入可執行狀態。

談到阻塞,就不能不談一談死鎖,略一分析就能發現,suspend() 方法和不指定超時期限的 wait() 方法的調用都可能產生死鎖。遺憾的是,Java 並不在語言級別上支持死鎖的避免,我們在編程中必須小心地避免死鎖。

以上我們對 Java 中實現線程阻塞的各種方法作了一番分析,我們重點分析了 wait() 和 notify() 方法,因爲它們的功能最強大,使用也最靈活,但是這也導致了它們的效率較低,較容易出錯。實際使用中我們應該靈活使用各種方法,以便更好地達到我們的目的。

19.抽象類接口區別(360)

默認的方法實現 抽象類可以有默認的方法實現完全是抽象的。接口根本不存在方法的實現

實現 子類使用extends關鍵字來繼承抽象類。如果子類不是抽象類的話,它需要提供抽象類中所有聲明的方法的實現。
子類使用關鍵字implements來實現接口。它需要提供接口中所有聲明的方法的實現

構造器
抽象類可以有構造器 接口不能有構造器

與正常Java類的區別
除了你不能實例化抽象類之外,它和普通Java類沒有任何區 接口是完全不同的類型

訪問修飾符
抽象方法可以有public、protected和default這些修飾符 接口方法默認修飾符是public。你不可以使用其它修飾符。

main方法
抽象方法可以有main方法並且我們可以運行它
接口沒有main方法,因此我們不能運行它。

多繼承
抽象類在java語言中所表示的是一種繼承關係,一個子類只能存在一個父類,但是可以存在多個接口。

速度
它比接口速度要快
接口是稍微有點慢的,因爲它需要時間去尋找在類中實現的方法。

添加新方法
如果你往抽象類中添加新的方法,你可以給它提供默認的實現。因此你不需要改變你現在的代碼。
如果你往接口中添加方法,那麼你必須改變實現該接口的類。

20.容器類之間的區別(樂視、美團)

http://www.cnblogs.com/yuanermen/archive/2009/08/05/1539917.html http://alexyyek.github.io/2015/04/06/Collection/http://tianmaying.com/tutorial/java_collection

21.java 內部類(小米)

http://www.cnblogs.com/chenssy/p/3388487.html

22.Java中hashmap和hashtable的區別(樂視、小米)

http://www.233.com/ncre2/JAVA/jichu/20100717/084230917.html

23.ArrayMap VS HashMap

http://lvable.com/?p=217

二、android基礎

1.數據庫的操作類型有哪些,如何導入外部數據庫?

把原數據庫包括在項目源碼的 res/raw

android系統下數據庫應該存放在 /data/data/com..(package name)/ 目錄下,所以我們需要做的是把已有的數據庫傳入那個目錄下.操作方法是用FileInputStream讀取原數據庫,再用FileOutputStream把讀取到的東西寫入到那個目錄.

2.是否使用過本地廣播,和全局廣播有什麼差別?

因廣播數據在本應用範圍內傳播,不用擔心隱私數據泄露的問題。 不用擔心別的應用僞造廣播,造成安全隱患。 相比在系統內發送全局廣播,它更高效。

3.是否使用過intentServer,作用是什麼,AIDL解決了什麼問題?(小米)

生成一個默認的且與主線程互相獨立的工作者線程來執行所有傳送至onStartCommand() 方法的Intetnt。

生成一個工作隊列來傳送Intent對象給你的onHandleIntent()方法,同一時刻只傳送一個Intent對象,這樣一來,你就不必擔心多線程的問題。在所有的請求(Intent)都被執行完以後會自動停止服務,所以,你不需要自己去調用stopSelf()方法來停止。

該服務提供了一個onBind()方法的默認實現,它返回null

提供了一個onStartCommand()方法的默認實現,它將Intent先傳送至工作隊列,然後從工作隊列中每次取出一個傳送至onHandleIntent()方法,在該方法中對Intent對相應的處理。

AIDL (Android Interface Definition Language) 是一種IDL 語言,用於生成可以在Android設備上兩個進程之間進行進程間通信(interprocess communication, IPC)的代碼。如果在一個進程中(例如Activity)要調用另一個進程中(例如Service)對象的操作,就可以使用AIDL生成可序列化的參數。 AIDL IPC機制是面向接口的,像COM或Corba一樣,但是更加輕量級。它是使用代理類在客戶端和實現端傳遞數據。

4.Activity、Window、View三者的差別,fragment的特點?(360)

Activity像一個工匠(控制單元),Window像窗戶(承載模型),View像窗花(顯示視圖) LayoutInflater像剪刀,Xml配置像窗花圖紙。

在Activity中調用attach,創建了一個Window
創建的window是其子類PhoneWindow,在attach中創建PhoneWindow
在Activity中調用setContentView(R.layout.xxx)
其中實際上是調用的getWindow().setContentView()
調用PhoneWindow中的setContentView方法
創建ParentView:
作爲ViewGroup的子類,實際是創建的DecorView(作爲FramLayout的子類)
將指定的R.layout.xxx進行填充
通過佈局填充器進行填充【其中的parent指的就是DecorView】
調用到ViewGroup
調用ViewGroup的removeAllView(),先將所有的view移除掉
添加新的view:addView()
fragment 特點

Fragment可以作爲Activity界面的一部分組成出現;
可以在一個Activity中同時出現多個Fragment,並且一個Fragment也可以在多個Activity中使用;
在Activity運行過程中,可以添加、移除或者替換Fragment;
Fragment可以響應自己的輸入事件,並且有自己的生命週期,它們的生命週期會受宿主Activity的生命週期影響。
5.描述一次網絡請求的流程(新浪)



6.Handler、Thread和HandlerThread的差別(小米)

http://blog.csdn.net/guolin_blog/article/details/9991569

http://droidyue.com/blog/2015/11/08/make-use-of-handlerthread/

從Android中Thread(java.lang.Thread -> java.lang.Object)描述可以看出,Android的Thread沒有對Java的Thread做任何封裝,但是Android提供了一個繼承自Thread的類HandlerThread(android.os.HandlerThread -> java.lang.Thread),這個類對Java的Thread做了很多便利Android系統的封裝。

android.os.Handler可以通過Looper對象實例化,並運行於另外的線程中,Android提供了讓Handler運行於其它線程的線程實現,也是就HandlerThread。HandlerThread對象start後可以獲得其Looper對象,並且使用這個Looper對象實例Handler。

7.低版本SDK實現高版本api(小米)

自己實現或@TargetApi annotation

8.Ubuntu編譯安卓系統(百度)

進入源碼根目錄
. build/envsetup.sh
lunch
full(編譯全部)
userdebug(選擇編譯版本)
make -j8(開啓8個線程編譯)
9.launch mode應用場景(百度、小米、樂視)

standard,創建一個新的Activity。

singleTop,棧頂不是該類型的Activity,創建一個新的Activity。否則,onNewIntent。

singleTask,回退棧中沒有該類型的Activity,創建Activity,否則,onNewIntent+ClearTop。

注意:

設置了"singleTask"啓動模式的Activity,它在啓動的時候,會先在系統中查找屬性值affinity等於它的屬性值taskAffinity的Task存在; 如果存在這樣的Task,它就會在這個Task中啓動,否則就會在新的任務棧中啓動。因此, 如果我們想要設置了"singleTask"啓動模式的Activity在新的任務中啓動,就要爲它設置一個獨立的taskAffinity屬性值。
如果設置了"singleTask"啓動模式的Activity不是在新的任務中啓動時,它會在已有的任務中查看是否已經存在相應的Activity實例, 如果存在,就會把位於這個Activity實例上面的Activity全部結束掉,即最終這個Activity 實例會位於任務的Stack頂端中。
在一個任務棧中只有一個”singleTask”啓動模式的Activity存在。他的上面可以有其他的Activity。這點與singleInstance是有區別的。
singleInstance,回退棧中,只有這一個Activity,沒有其他Activity。

singleTop適合接收通知啓動的內容顯示頁面。

例如,某個新聞客戶端的新聞內容頁面,如果收到10個新聞推送,每次都打開一個新聞內容頁面是很煩人的。

singleTask適合作爲程序入口點。

例如瀏覽器的主界面。不管從多少個應用啓動瀏覽器,只會啓動主界面一次,其餘情況都會走onNewIntent,並且會清空主界面上面的其他頁面。

singleInstance應用場景:

鬧鈴的響鈴界面。 你以前設置了一個鬧鈴:上午6點。在上午5點58分,你啓動了鬧鈴設置界面,並按 Home 鍵回桌面;在上午5點59分時,你在微信和朋友聊天;在6點時,鬧鈴響了,並且彈出了一個對話框形式的 Activity(名爲 AlarmAlertActivity) 提示你到6點了(這個 Activity 就是以 SingleInstance 加載模式打開的),你按返回鍵,回到的是微信的聊天界面,這是因爲 AlarmAlertActivity 所在的 Task 的棧只有他一個元素, 因此退出之後這個 Task 的棧空了。如果是以 SingleTask 打開 AlarmAlertActivity,那麼當鬧鈴響了的時候,按返回鍵應該進入鬧鈴設置界面。

10.touch 事件傳遞流程(小米)

http://hanhailong.com/2015/09/24 ... %E6%9C%BA%E5%88%B6/

11.view繪製流程(百度)

http://www.codekk.com/blogs/detail/54cfab086c4761e5001b253f

12.多線程(360)

Activity.runOnUiThread(Runnable)
View.post(Runnable),View.postDelay(Runnable,long)
Handler
AsyncTask
13.線程同步(百度)

http://www.itzhai.com/java-based ... hods.html#read-more

http://www.juwends.com/tech/andr ... er-thread-comm.html

單例

public class Singleton{
private volatile static Singleton mSingleton;
private Singleton(){
}
public static Singleton getInstance(){
if(mSingleton == null){\A
synchronized(Singleton.class){\C
if(mSingleton == null)
mSingleton = new Singleton();\B
}
}
return mSingleton;
}
}
14.什麼情況導致內存泄漏(美團)

1.資源對象沒關閉造成的內存泄漏

描述: 資源性對象比如(Cursor,File文件等)往往都用了一些緩衝,我們在不使用的時候,應該及時關閉它們,以便它們的緩衝及時回收內存。它們的緩衝不僅存在於 java虛擬機內,還存在於java虛擬機外。如果我們僅僅是把它的引用設置爲null,而不關閉它們,往往會造成內存泄漏。因爲有些資源性對象,比如 SQLiteCursor(在析構函數finalize(),如果我們沒有關閉它,它自己會調close()關閉),如果我們沒有關閉它,系統在回收它時也會關閉它,但是這樣的效率太低了。因此對於資源性對象在不使用的時候,應該調用它的close()函數,將其關閉掉,然後才置爲null.在我們的程序退出時一定要確保我們的資源性對象已經關閉。 程序中經常會進行查詢數據庫的操作,但是經常會有使用完畢Cursor後沒有關閉的情況。如果我們的查詢結果集比較小,對內存的消耗不容易被發現,只有在常時間大量操作的情況下才會復現內存問題,這樣就會給以後的測試和問題排查帶來困難和風險。

2.構造Adapter時,沒有使用緩存的convertView

描述: 以構造ListView的BaseAdapter爲例,在BaseAdapter中提供了方法: public View getView(int position, ViewconvertView, ViewGroup parent) 來向ListView提供每一個item所需要的view對象。初始時ListView會從BaseAdapter中根據當前的屏幕布局實例化一定數量的 view對象,同時ListView會將這些view對象緩存起來。當向上滾動ListView時,原先位於最上面的list item的view對象會被回收,然後被用來構造新出現的最下面的list item。這個構造過程就是由getView()方法完成的,getView()的第二個形參View convertView就是被緩存起來的list item的view對象(初始化時緩存中沒有view對象則convertView是null)。由此可以看出,如果我們不去使用 convertView,而是每次都在getView()中重新實例化一個View對象的話,即浪費資源也浪費時間,也會使得內存佔用越來越大。 ListView回收list item的view對象的過程可以查看: android.widget.AbsListView.java --> voidaddScrapView(View scrap) 方法。 示例代碼:

public View getView(int position, ViewconvertView, ViewGroup parent) {
View view = new Xxx(...);
... ...
return view;
}
修正示例代碼:

public View getView(int position, ViewconvertView, ViewGroup parent) {
View view = null;
if (convertView != null) {
view = convertView;
populate(view, getItem(position));
...
} else {
view = new Xxx(...);
...
}
return view;
}
3.Bitmap對象不在使用時調用recycle()釋放內存

描述: 有時我們會手工的操作Bitmap對象,如果一個Bitmap對象比較佔內存,當它不在被使用的時候,可以調用Bitmap.recycle()方法回收此對象的像素所佔用的內存,但這不是必須的,視情況而定。可以看一下代碼中的註釋:

/* •Free up the memory associated with thisbitmap's pixels, and mark the •bitmap as "dead", meaning itwill throw an exception if getPixels() or •setPixels() is called, and will drawnothing. This operation cannot be •reversed, so it should only be called ifyou are sure there are no •further uses for the bitmap. This is anadvanced call, and normally need •not be called, since the normal GCprocess will free up this memory when •there are no more references to thisbitmap. /

4.試着使用關於application的context來替代和activity相關的context

這是一個很隱晦的內存泄漏的情況。有一種簡單的方法來避免context相關的內存泄漏。最顯著地一個是避免context逃出他自己的範圍之外。使用Application context。這個context的生存週期和你的應用的生存週期一樣長,而不是取決於activity的生存週期。如果你想保持一個長期生存的對象,並且這個對象需要一個context,記得使用application對象。你可以通過調用 Context.getApplicationContext() or Activity.getApplication()來獲得。更多的請看這篇文章如何避免 Android內存泄漏。

5.註冊沒取消造成的內存泄漏

一些Android程序可能引用我們的Anroid程序的對象(比如註冊機制)。即使我們的Android程序已經結束了,但是別的引用程序仍然還有對我們的Android程序的某個對象的引用,泄漏的內存依然不能被垃圾回收。調用registerReceiver後未調用unregisterReceiver。 比如:假設我們希望在鎖屏界面(LockScreen)中,監聽系統中的電話服務以獲取一些信息(如信號強度等),則可以在LockScreen中定義一個 PhoneStateListener的對象,同時將它註冊到TelephonyManager服務中。對於LockScreen對象,當需要顯示鎖屏界面的時候就會創建一個LockScreen對象,而當鎖屏界面消失的時候LockScreen對象就會被釋放掉。 但是如果在釋放 LockScreen對象的時候忘記取消我們之前註冊的PhoneStateListener對象,則會導致LockScreen無法被垃圾回收。如果不斷的使鎖屏界面顯示和消失,則最終會由於大量的LockScreen對象沒有辦法被回收而引起OutOfMemory,使得system_process 進程掛掉。 雖然有些系統程序,它本身好像是可以自動取消註冊的(當然不及時),但是我們還是應該在我們的程序中明確的取消註冊,程序結束時應該把所有的註冊都取消掉。

6.集合中對象沒清理造成的內存泄漏

我們通常把一些對象的引用加入到了集合中,當我們不需要該對象時,並沒有把它的引用從集合中清理掉,這樣這個集合就會越來越大。如果這個集合是static的話,那情況就更嚴重了。

15.ANR定位和修正

如果開發機器上出現問題,我們可以通過查看/data/anr/traces.txt即可,最新的ANR信息在最開始部分。

主線程被IO操作(從4.0之後網絡IO不允許在主線程中)阻塞。
主線程中存在耗時的計算
主線程中錯誤的操作,比如Thread.wait或者Thread.sleep等 Android系統會監控程序的響應狀況,一旦出現下面兩種情況,則彈出ANR對話框
應用在5秒內未響應用戶的輸入事件(如按鍵或者觸摸)
BroadcastReceiver未在10秒內完成相關的處理
Service在特定的時間內無法處理完成 20秒

使用AsyncTask處理耗時IO操作。

使用Thread或者HandlerThread時,調用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)設置優先級,否則仍然會降低程序響應,因爲默認Thread的優先級和主線程相同。
使用Handler處理工作線程結果,而不是使用Thread.wait()或者Thread.sleep()來阻塞主線程。
Activity的onCreate和onResume回調中儘量避免耗時的代碼
BroadcastReceiver中onReceive代碼也要儘量減少耗時,建議使用IntentService處理。
16.什麼情況導致oom(樂視、美團)

http://www.jcodecraeer.com/a/anz ... 2015/0920/3478.html

1)使用更加輕量的數據結構 2)Android裏面使用Enum 3)Bitmap對象的內存佔用 4)更大的圖片 5)onDraw方法裏面執行對象的創建 6)StringBuilder

17.Android Service與Activity之間通信的幾種方式

通過Binder對象
通過broadcast(廣播)的形式
18.Android各個版本API的區別

http://blog.csdn.net/lijun952048910/article/details/7980562

Android代碼中實現WAP方式聯網(360)
http://blog.csdn.net/asce1885/article/details/7844159

20.如何保證service在後臺不被kill

一、onStartCommand方法,返回START_STICKY

START_STICKY 在運行onStartCommand後service進程被kill後,那將保留在開始狀態,但是不保留那些傳入的intent。不久後service就會再次嘗試重新創建,因爲保留在開始狀態,在創建 service後將保證調用onstartCommand。如果沒有傳遞任何開始命令給service,那將獲取到null的intent。

START_NOT_STICKY 在運行onStartCommand後service進程被kill後,並且沒有新的intent傳遞給它。Service將移出開始狀態,並且直到新的明顯的方法(startService)調用才重新創建。因爲如果沒有傳遞任何未決定的intent那麼service是不會啓動,也就是期間onstartCommand不會接收到任何null的intent。

START_REDELIVER_INTENT 在運行onStartCommand後service進程被kill後,系統將會再次啓動service,並傳入最後一個intent給onstartCommand。直到調用stopSelf(int)才停止傳遞intent。如果在被kill後還有未處理好的intent,那被kill後服務還是會自動啓動。因此onstartCommand不會接收到任何null的intent。

二、提升service優先級

在AndroidManifest.xml文件中對於intent-filter可以通過android:priority = "1000"這個屬性設置最高優先級,1000是最高值,如果數字越小則優先級越低,同時適用於廣播。

三、提升service進程優先級

Android中的進程是託管的,當系統進程空間緊張的時候,會依照優先級自動進行進程的回收。Android將進程分爲6個等級,它們按優先級順序由高到低依次是:

前臺進程( FOREGROUND_APP)
可視進程(VISIBLE_APP )
次要服務進程(SECONDARY_SERVER )
後臺進程 (HIDDEN_APP)
內容供應節點(CONTENT_PROVIDER)
空進程(EMPTY_APP)
當service運行在低內存的環境時,將會kill掉一些存在的進程。因此進程的優先級將會很重要,可以使用startForeground 將service放到前臺狀態。這樣在低內存時被kill的機率會低一些。

四、onDestroy方法裏重啓service

service +broadcast 方式,就是當service走ondestory的時候,發送一個自定義的廣播,當收到廣播的時候,重新啓動service;

五、Application加上Persistent屬性

六、監聽系統廣播判斷Service狀態

通過系統的一些廣播,比如:手機重啓、界面喚醒、應用狀態改變等等監聽並捕獲到,然後判斷我們的Service是否還存活,別忘記加權限啊。

21.Requestlayout,onlayout,onDraw,DrawChild區別與聯繫(獵豹)

requestLayout()方法 :會導致調用measure()過程 和 layout()過程 。 說明:只是對View樹重新佈局layout過程包括measure()和layout()過程,不會調用draw()過程,但不會重新繪製 任何視圖包括該調用者本身。

onLayout()方法(如果該View是ViewGroup對象,需要實現該方法,對每個子視圖進行佈局)

調用onDraw()方法繪製視圖本身 (每個View都需要重載該方法,ViewGroup不需要實現該方法)

drawChild()去重新回調每個子視圖的draw()方法

22.invalidate()和postInvalidate() 的區別及使用(百度)

http://blog.csdn.net/mars2639/article/details/6650876

23.Android動畫框架實現原理

Animation框架定義了透明度,旋轉,縮放和位移幾種常見的動畫,而且控制的是整個View,實現原理是每次繪製視圖時View所在的ViewGroup中的drawChild函數獲取該View的Animation的Transformation值,然後調用canvas.concat(transformToApply.getMatrix()),通過矩陣運算完成動畫幀,如果動畫沒有完成,繼續調用invalidate()函數,啓動下次繪製來驅動動畫,動畫過程中的幀之間間隙時間是繪製函數所消耗的時間,可能會導致動畫消耗比較多的CPU資源,最重要的是,動畫改變的只是顯示,並不能相應事件。

24.Android爲每個應用程序分配的內存大小是多少?(美團)

android程序內存一般限制在16M,也有的是24M

25.Android View刷新機制(百度、美團)

由ViewRoot對象的performTraversals()方法調用draw()方法發起繪製該View樹,值得注意的是每次發起繪圖時,並不會重新繪製每個View樹的視圖,而只會重新繪製那些“需要重繪”的視圖,View類內部變量包含了一個標誌位DRAWN,當該視圖需要重繪時,就會爲該View添加該標誌位。

調用流程 :

mView.draw()開始繪製,draw()方法實現的功能如下:

繪製該View的背景
爲顯示漸變框做一些準備操作(見5,大多數情況下,不需要改漸變框)
調用onDraw()方法繪製視圖本身 (每個View都需要重載該方法,ViewGroup不需要實現該方法)
調用dispatchDraw ()方法繪製子視圖(如果該View類型不爲ViewGroup,即不包含子視圖,不需要重載該方法)值得說明的是,ViewGroup類已經爲我們重寫了dispatchDraw ()的功能實現,應用程序一般不需要重寫該方法,但可以重載父類函數實現具體的功能。
26.LinearLayout對比RelativeLayout(百度)

RelativeLayout會讓子View調用2次onMeasure,LinearLayout 在有weight時,也會調用子View2次onMeasure
RelativeLayout的子View如果高度和RelativeLayout不同,則會引發效率問題,當子View很複雜時,這個問題會更加嚴重。如果可以,儘量使用padding代替margin。
在不影響層級深度的情況下,使用LinearLayout和FrameLayout而不是RelativeLayout。
最後再思考一下文章開頭那個矛盾的問題,爲什麼Google給開發者默認新建了個RelativeLayout,而自己卻在DecorView中用了個LinearLayout。因爲DecorView的層級深度是已知而且固定的,上面一個標題欄,下面一個內容欄。採用RelativeLayout並不會降低層級深度,所以此時在根節點上用LinearLayout是效率最高的。而之所以給開發者默認新建了個RelativeLayout是希望開發者能採用儘量少的View層級來表達佈局以實現性能最優,因爲複雜的View嵌套對性能的影響會更大一些。

27.優化自定義view(百度、樂視、小米)

爲了加速你的view,對於頻繁調用的方法,需要儘量減少不必要的代碼。先從onDraw開始,需要特別注意不應該在這裏做內存分配的事情,因爲它會導致GC,從而導致卡頓。在初始化或者動畫間隙期間做分配內存的動作。不要在動畫正在執行的時候做內存分配的事情。

你還需要儘可能的減少onDraw被調用的次數,大多數時候導致onDraw都是因爲調用了invalidate().因此請儘量減少調用invaildate()的次數。如果可能的話,儘量調用含有4個參數的invalidate()方法而不是沒有參數的invalidate()。沒有參數的invalidate會強制重繪整個view。

另外一個非常耗時的操作是請求layout。任何時候執行requestLayout(),會使得Android UI系統去遍歷整個View的層級來計算出每一個view的大小。如果找到有衝突的值,它會需要重新計算好幾次。另外需要儘量保持View的層級是扁平化的,這樣對提高效率很有幫助。

如果你有一個複雜的UI,你應該考慮寫一個自定義的ViewGroup來執行他的layout操作。與內置的view不同,自定義的view可以使得程序僅僅測量這一部分,這避免了遍歷整個view的層級結構來計算大小。這個PieChart 例子展示瞭如何繼承ViewGroup作爲自定義view的一部分。PieChart 有子views,但是它從來不測量它們。而是根據他自身的layout法則,直接設置它們的大小。

28.ContentProvider(樂視)

http://blog.csdn.net/coder_pig/article/details/47858489

29.fragment生命週期

30.volley解析(美團、樂視)

http://a.codekk.com/detail/Andro ... 1%E8%A7%A3%E6%9E%90

31.Android Glide源碼解析

http://www.lightskystreet.com/2015/10/12/glide_source_analysis/ http://frodoking.github.io/2015/10/10/android-glide/

32.Android 設計模式

http://blog.csdn.net/bboyfeiyu/article/details/44563871

33.架構設計(搜狐)

http://www.tianmaying.com/tutorial/AndroidMVC

34.Android屬性動畫特性(樂視、小米)

如果你的需求中只需要對View進行移動、縮放、旋轉和淡入淡出操作,那麼補間動畫確實已經足夠健全了。但是很顯然,這些功能是不足以覆蓋所有的場景的,一旦我們的需求超出了移動、縮放、旋轉和淡入淡出這四種對View的操作,那麼補間動畫就不能再幫我們忙了,也就是說它在功能和可擴展方面都有相當大的侷限性,那麼下面我們就來看看補間動畫所不能勝任的場景。

注意上面我在介紹補間動畫的時候都有使用“對View進行操作”這樣的描述,沒錯,補間動畫是隻能夠作用在View上的。也就是說,我們可以對一個Button、TextView、甚至是LinearLayout、或者其它任何繼承自View的組件進行動畫操作,但是如果我們想要對一個非View的對象進行動畫操作,抱歉,補間動畫就幫不上忙了。可能有的朋友會感到不能理解,我怎麼會需要對一個非View的對象進行動畫操作呢?這裏我舉一個簡單的例子,比如說我們有一個自定義的View,在這個View當中有一個Point對象用於管理座標,然後在onDraw()方法當中就是根據這個Point對象的座標值來進行繪製的。也就是說,如果我們可以對Point對象進行動畫操作,那麼整個自定義View的動畫效果就有了。顯然,補間動畫是不具備這個功能的,這是它的第一個缺陷。

然後補間動畫還有一個缺陷,就是它只能夠實現移動、縮放、旋轉和淡入淡出這四種動畫操作,那如果我們希望可以對View的背景色進行動態地改變呢?很遺憾,我們只能靠自己去實現了。說白了,之前的補間動畫機制就是使用硬編碼的方式來完成的,功能限定死就是這些,基本上沒有任何擴展性可言。

最後,補間動畫還有一個致命的缺陷,就是它只是改變了View的顯示效果而已,而不會真正去改變View的屬性。什麼意思呢?比如說,現在屏幕的左上角有一個按鈕,然後我們通過補間動畫將它移動到了屏幕的右下角,現在你可以去嘗試點擊一下這個按鈕,點擊事件是絕對不會觸發的,因爲實際上這個按鈕還是停留在屏幕的左上角,只不過補間動畫將這個按鈕繪製到了屏幕的右下角而已。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章