天天看點

Android面試題集錦(持續更新)

一、java

熟練掌握java是很關鍵的,大公司不僅僅要求你會使用幾個api,更多的是要你熟悉源碼實作原理,甚至要你知道有哪些不足,怎麼改進,還有一些java有關的一些算法,設計模式等等。

(一)java基礎面試知識點

  1. java中==和equals和hashCode的差別

== 在用關系操作符 == 比較的是值本身;equals 比較兩個對象的引用是否相等,即 是否指向同一個對象;hashCode 用來鑒定兩個對象是否相等,Object類中的hashCode方法傳回對象在記憶體中位址轉換成的一個int值,是以如果沒有重寫hashCode方法,任何對象的hashCode方法是不相等的。

  1. int、char、long各占多少位元組數

4、1或2或4、8

  1. int與integer的差別

int 是我們常說的整形數字,是 Java 的 8 個原始資料類型之一。Integer 是 int 對應的包裝類,它有一個 int 類型的字段存儲資料,并且提供了基本操作,比如數學運算、int 和字元串之間轉換等。

  1. 談談對java多态的了解

所謂多态就是指程式中定義的引用變量所指向的具體類型和通過該引用變量發出的方法調用在程式設計時并不确定,而是在程式運作期間才确定,即一個引用變量到底會指向哪個類的執行個體對象,該引用變量發出的方法調用到底是哪個類中實作的方法,必須在由程式運作期間才能決定。因為在程式運作時才确定具體的類,這樣,不用修改源程式代碼,就可以讓引用變量綁定到各種不同的類實作上,進而導緻該引用變量調用的具體方法随之改變,即不修改程式代碼就可以改變程式運作時所綁定的具體代碼,讓程式可以選擇多個運作狀态,這就是多态性。實作形式 在Java中有兩種形式可以實作多态。繼承和接口。

  1. String、StringBuffer、StringBuilder差別

String 是 Java 語言非常基礎和重要的類,提供了構造和管理字元串的各種基本邏輯。它是典型的 Immutable 類,被聲明成為 final class,所有屬性也都是 final 的。也由于它的不可變性,類似拼接、裁剪字元串等動作,都會産生新的 String 對象。由于字元串操作的普遍性,是以相關操作的效率往往對應用性能有明顯影響。StringBuffer 是為解決上面提到拼接産生太多中間對象的問題而提供的一個類,我們可以用 append 或者 add 方法,把字元串添加到已有序列的末尾或者指定位置。StringBuffer 本質是一個線程安全的可修改字元序列,它保證了線程安全,也随之帶來了額外的性能開銷,是以除非有線程安全的需要,不然還是推薦使用它的後繼者,也就是 StringBuilder。StringBuilder 是 Java 1.5 中新增的,在能力上和 StringBuffer 沒有本質差別,但是它去掉了線程安全的部分,有效減小了開銷,是絕大部分情況下進行字元串拼接的首選。

  1. 什是内部類?内部類的作用
  • 定義在類中的類
  • 内部類方法可以通路該類定義所在作用域中的資料,包括被 private 修飾的私有資料
  • 内部類可以對同一包中的其他類隐藏起來
  • 内部類可以解決 java 單繼承的缺陷
  • 當我們想要定義一個回調函數卻不想寫大量代碼的時候我們可以選擇使用匿名内部類來實作
  • 但是容易記憶體洩露,因為持有外部對象。
    1. 抽象類和接口差別

接口是對行為的抽象,他是抽象方法的集合,利用接口可以達到API定義和實作分離的目的。接口,不能執行個體化;不能包含任何非常量成員,任何field都是隐含着public static final的意義;同時沒有非靜态方法實作,也就是說要麼是抽象方法,要麼是靜态方法。

抽象類是不能執行個體化的類,有abstract關鍵字修飾class,其目的主要是代碼重用。除了不能執行個體化,形式上和一般的Java類并沒有太大差別,可以有一個和多個抽象方法,也可以沒有抽象方法。抽象類大多用于抽取相關Java類的共用方法實作或者是共同成員變量,然後通過繼承的方式達到代碼重用的目的。

  1. 泛型中extends和super的差別

泛型中extends的主要作用是設定類型通配符的上限,<? extends Fruit>代表的是上界通配符,也就是說這個List中存放的對象都是Fruit以及其子類的對象,這樣我們就不用因為輸入的List中類型的不同而改變代碼了。

super與extends是完全相反的,其定義的是下界通配符。List<? super Fruit>也就是說List中存放的都是Fruit和它的父類的對象

  1. 父類的靜态方法能否被子類重寫

不能,父類的靜态方法能夠被子類繼承,但是不能夠被子類重寫,即使子類中的靜态方法與父類中的靜态方法完全一樣,也是兩個完全不同的方法。

  1. 程序和線程的差別
  • 程序是資源配置設定的最小機關,線程是資源排程的最小機關。
  • 程序有自己的獨立位址空間,每啟動一個程序,系統就會為它配置設定位址空間,建立資料表來維護代碼段、堆棧段和資料段,這種操作非常昂貴。
  • 而線程是共享程序中的資料的,使用相同的位址空間,是以CPU切換一個線程的花費遠比程序要小很多,同時建立一個線程的開銷也比程序要小很多。
  • 線程之間的通信更友善,同一程序下的線程共享全局變量、靜态變量等資料,而程序之間的通信需要以通信的方式(IPC)進行。
  1. final,finally,finalize的差別

final 可以用來修飾類、方法、變量,分别有不同的意義,final 修飾的 class 代表不可以繼承擴充,final 的變量是不可以修改的,而 final 的方法也是不可以重寫的(override)。finally 則是 Java 保證重點代碼一定要被執行的一種機制。我們可以使用 try-finally 或者 try-catch-finally 來進行類似關閉 JDBC 連接配接、保證 unlock 鎖等動作。finalize 是基礎類 java.lang.Object 的一個方法,它的設計目的是保證對象在被垃圾收集前完成特定資源的回收。

  1. 序列化的方式
  • 實作Serializable接口(隐式序列化)
  • 實作Externalizable接口(顯示序列化)
  • 實作Serializable接口+添加writeObject和readObject方法(顯+隐序列化)
  1. Serializable 和Parcelable 的差別

Serializable的作用是為了儲存對象的屬性到本地檔案、資料庫、網絡流等以友善資料傳輸,Android的Parcelable的設計初衷是因為Serializable效率過慢。

記憶體間資料傳輸時推薦使用Parcelable,如activity間傳輸資料,而Serializable可将資料持久化友善儲存,因為android不同版本Parcelable可能不同,是以不推薦使用Parcelable進行資料持久化。

  1. 靜态屬性和靜态方法是否可以被繼承?是否可以被重寫?以及原因?

父類的靜态屬性和方法可以被子類繼承

不可以被子類重寫

因為靜态方法從程式開始運作後就已經配置設定了記憶體,也就是說已經寫死了。所有引用到該方法的對象(父類的對象也好子類的對象也好)所指向的都是同一塊記憶體中的資料,也就是該靜态方法。子類中如果定義了相同名稱的靜态方法,并不會重寫,而應該是在記憶體中又配置設定了一塊給子類的靜态方法,沒有重寫這一說。

  1. 靜态内部類的設計意圖

非靜态内部類在編譯完成之後會隐含地儲存着一個引用,該引用是指向建立它的外圍類,但是靜态内部類卻沒有。沒有這個引用就意味着:它的建立是不需要依賴于外圍類的。它不能使用任何外圍類的非static成員變量和方法。

  1. 成員内部類、靜态内部類、局部内部類和匿名内部類的了解,以及項目中的應用

https://www.cnblogs.com/ldl326308/p/9477566.html

https://blog.csdn.net/nobody_1/article/details/90886330

  1. string 轉換成 integer的方式及原理

預設轉成十進制

(二)java深入源碼級的面試題(有難度)

  1. 哪些情況下的對象會被垃圾回收機制處理掉?
  2. 講一下常見編碼方式?
  • ASCII編碼:用來表示英文,它使用1個位元組表示,其中第一位規定為0,其他7位存儲資料,一共可以表示128個字元。
  • 拓展ASCII編碼:用于表示更多的歐洲文字,用8個位存儲資料,一共可以表示256個字元
  • GBK/GB2312/GB18030:表示漢字。GBK/GB2312表示簡體中文,GB18030表示繁體中文。
  • Unicode編碼:包含世界上所有的字元,是一個字元集。
  • UTF-8:是Unicode字元的實作方式之一,它使用1-4個字元表示一個符号,根據不同的符号而變化位元組長度。
  1. utf-8編碼中的中文占幾個位元組;int型幾個位元組?

數字占1個位元組,英文字母占1個位元組,少數是漢字每個占用3個位元組,多數占用4個位元組。

  1. 靜态代理和動态代理的差別,什麼場景使用?

動态代理是一種友善運作時動态建構代理、動态處理代理方法調用的機制,很多場景都是利用類似機制做到的,比如用來包裝 RPC 調用、面向切面的程式設計(AOP)。實作動态代理的方式很多,比如 JDK 自身提供的動态代理,就是主要利用了上面提到的反射機制。還有其他的實作方式,比如利用傳說中更高性能的位元組碼操作機制,類似 ASM、cglib(基于 ASM)、Javassist 等。通過代理可以讓調用者與實作者之間解耦。

  1. Java的異常體系

Exception 和 Error 都是繼承了 Throwable 類,在 Java 中隻有 Throwable 類型的執行個體才可以被抛出(throw)或者捕獲(catch),它是異常處理機制的基本組成類型。Exception 和 Error 展現了 Java 平台設計者對不同異常情況的分類。Exception 是程式正常運作中,可以預料的意外情況,可能并且應該被捕獲,進行相應處理。Error 是指在正常情況下,不大可能出現的情況,絕大部分的 Error 都會導緻程式(比如 JVM 自身)處于非正常的、不可恢複狀态。既然是非正常情況,是以不便于也不需要捕獲,常見的比如 OutOfMemoryError 之類,都是 Error 的子類。Exception 又分為可檢查(checked)異常和不檢查(unchecked)異常,可檢查異常在源代碼裡必須顯式地進行捕獲處理,這是編譯期檢查的一部分。前面我介紹的不可查的 Error,是 Throwable 不是 Exception。不檢查異常就是所謂的運作時異常,類似 NullPointerException、ArrayIndexOutOfBoundsException 之類,通常是可以編碼避免的邏輯錯誤,具體根據需要來判斷是否需要捕獲,并不會在編譯期強制要求。

  1. 談談你對解析與分派的認識。
  2. 修改對象A的equals方法的簽名,那麼使用HashMap存放這個對象執行個體的時候,會調用哪個equals方法?
  3. Java中實作多态的機制是什麼?
  4. 如何将一個Java對象序列化到檔案裡?
  5. 說說你對Java反射的了解

反射機制是 Java 語言提供的一種基礎功能,賦予程式在運作時自省(introspect,官方用語)的能力。通過反射我們可以直接操作類或者對象,比如擷取某個對象的類定義,擷取類聲明的屬性和方法,調用方法或者構造對象,甚至可以運作時修改類定義。

// 用法
Class<BluetoothDevice> bluetoothDeviceClass = BluetoothDevice.class;
bluetoothDeviceClass.getMethod("setPin", byte[].class).invoke(device, "1234".getBytes());
bluetoothDeviceClass.getMethod("createBond").invoke(device);
bluetoothDeviceClass.getMethod("setPairingConfirmation", boolean.class).invoke(device, true);
bluetoothDeviceClass.getMethod("cancelPairingUserInput").invoke(device);

// 常用方法
getDeclaredMethods() //擷取這個類中的所有方法
getReturnType() //擷取方法的傳回類型
getParameterTypes() //擷取方法的傳入參數類型
getDeclaredConstructors() //擷取所有的構造方法
getFields() //擷取這個類中所有被public修飾的成員變量
           

反射不僅可以讓我們獲得隐藏的方法和屬性,還可以讓對象的執行個體化從編譯時轉化為運作時,因為我們可以通過Class.forName(“cc.abto.demo.Book”).newInstance()的方法來生成新的執行個體

  1. 說說你對Java注解的了解

注解,也叫中繼資料。一種代碼級别的說明,在JDK1.5之後引入的特性,與類、接口、枚舉同一層次。可以聲明在包、類、字段、方法、局部變量、方法參數等前面,來對這些元素進行說明,注釋等。

作用分類:

  • 1)編寫文檔:通過代碼裡的辨別的中繼資料生成文檔【生成文檔doc文檔】
  • 2)代碼分析:通過代碼裡的辨別的中繼資料對代碼進行分析【使用反射】
  • 3)編譯檢查:通過代碼裡的辨別的中繼資料讓編譯器能過實作基本的編譯檢查【Override】
  1. 說說你對依賴注入的了解

依賴注入設計原則允許我們移除寫死依賴和讓我們的應用低耦合,可擴充和可維護。我們可以通過在Java中實作依賴注入将依賴關系從編譯時移到運作時來解析。

  1. 說一下泛型原理,并舉例說明

類型安全, 泛型的主要目标是實作java的類型安全。 泛型可以使編譯器知道一個對象的限定類型是什麼,這樣編譯器就可以在一個高的程度上驗證這個類型

消除了強制類型轉換, 使得代碼可讀性好,減少了很多出錯的機會

Java語言引入泛型的好處是安全簡單。泛型的好處是在編譯的時候檢查類型安全,并且所有的強制轉換都是自動和隐式的,提高代碼的重用率。

泛型的實作是靠類型擦除技術, 類型擦除是在編譯期完成的, 也就是在編譯期, 編譯器會将泛型的類型參數都擦除成它的限定類型,如果沒有則擦除為object類型之後在擷取的時候再強制類型轉換為對應的類型。 在運作期間并沒有泛型的任何資訊,是以也沒有優化。

  1. String為什麼要設計成不可變的?

字元串常量池(String pool, String intern pool, String保留池) 是Java堆記憶體中一個特殊的存儲區域, 當建立一個String對象時,假如此字元串值已經存在于常量池中,則不會建立一個新的對象,而是引用已經存在的對象。假若字元串對象允許改變,那麼将會導緻各種邏輯錯誤,比如改變一個對象會影響到另一個獨立對象. 嚴格來說,這種常量池的思想,是一種優化手段.

  1. Object類的equal和hashCode方法重寫,為什麼?

16)Java8新特性

  • Java 8允許我們給接口添加一個非抽象的方法實作,隻需要使用 default關鍵字即可
  • Labmbda表達式
  • 在Java 8中支援多重注解了

(三) 資料結構

  1. 常用資料結構簡介
  2. 并發集合了解哪些?
  3. 列舉java的集合以及集合之間的繼承關系
  4. 集合類以及集合架構
  5. 容器類介紹以及之間的差別(容器類估計很多人沒聽這個詞,Java容器主要可以劃分為4個部分:List清單、Set集合、Map映射、工具類(Iterator疊代器、Enumeration枚舉類、Arrays和Collections),具體的可以看看這篇博文 Java容器類)
  6. List,Set,Map的差別
  7. List和Map的實作方式以及存儲方式
  8. HashMap的實作原理
  9. HashMap資料結構?
  10. HashMap源碼了解
  11. HashMap如何put資料(從HashMap源碼角度講解)?
  12. HashMap怎麼手寫實作?
  13. ConcurrentHashMap的實作原理
  14. ArrayMap和HashMap的對比
  15. HashTable實作原理
  16. TreeMap、HashMap和HashTable的差別

Hashtable、HashMap、TreeMap 都是最常見的一些 Map 實作,是以鍵值對的形式存儲和操作資料的容器類型。Hashtable 是早期 Java 類庫提供的一個哈希表實作,本身是同步的,不支援 null 鍵和值,由于同步導緻的性能開銷,是以已經很少被推薦使用。HashMap 是應用更加廣泛的哈希表實作,行為上大緻上與 HashTable 一緻,主要差別在于 HashMap 不是同步的,支援 null 鍵和值等。通常情況下,HashMap 進行 put 或者 get 操作,可以達到常數時間的性能,是以它是絕大部分利用鍵值對存取場景的首選,比如,實作一個使用者 ID 和使用者資訊對應的運作時存儲結構。TreeMap 則是基于紅黑樹的一種提供順序通路的 Map,和 HashMap 不同,它的 get、put、remove 之類操作都是 O(log(n))的時間複雜度,具體順序可以由指定的 Comparator 來決定,或者根據鍵的自然順序來判斷

  1. HashMap與HashSet的差別
  2. HashSet與HashMap怎麼判斷集合元素重複?
  3. 集合Set實作Hash怎麼防止碰撞
  4. Vector、ArrayList和LinkedList的差別,以及應用場景

這三者都是實作集合架構中的 List,也就是所謂的有序集合,是以具體功能也比較近似,比如都提供按照位置進行定位、添加或者删除的操作,都提供疊代器以周遊其内容等。但因為具體的設計差別,在行為、性能、線程安全等方面,表現又有很大不同。Vector 是 Java 早期提供的線程安全的動态數組,如果不需要線程安全,并不建議選擇,畢竟同步是有額外開銷的。Vector 内部是使用對象數組來儲存資料,可以根據需要自動的增加容量,當數組已滿時,會建立新的數組,并拷貝原有數組資料。ArrayList 是應用更加廣泛的動态數組實作,它本身不是線程安全的,是以性能要好很多。與 Vector 近似,ArrayList 也是可以根據需要調整容量,不過兩者的調整邏輯有所差別,Vector 在擴容時會提高 1 倍,而 ArrayList 則是增加 50%。LinkedList 顧名思義是 Java 提供的雙向連結清單,是以它不需要像上面兩種那樣調整容量,它也不是線程安全的。

  1. 數組和連結清單的差別

數組是一種線性表資料結構。它用一組連續的記憶體空間,來存儲一組具有相同類型的資料。最大的特點就是支援随機通路,但插入、删除操作也是以變得比較低效,平均情況時間複雜度為O(n)。

連結清單它并不需要一塊連續的記憶體空間,它通過“指針”将一組零散的記憶體,空間可擴容,比較常用的是單連結清單,雙連結清單和循環連結清單。和數組相比,連結清單更适合插入、删除操作頻繁的場景,查詢的時間複雜度較高。

  1. 二叉樹的深度優先周遊和廣度優先周遊的具體實作
  2. 堆的結構
  3. 堆和樹的差別
  4. 堆和棧在記憶體中的差別是什麼(解答提示:可以從資料結構方面以及實際實作方面兩個方面去回答)?
  5. 什麼是深拷貝和淺拷貝
  6. 手寫連結清單逆序代碼
  7. 講一下對樹,B+樹的了解
  8. 講一下對圖的了解
  9. 判斷單連結清單成環與否?
  10. 連結清單翻轉(即:翻轉一個單項連結清單)
  11. 合并多個單有序連結清單(假設都是遞增的)

(四) 線程、多線程和線程池

  1. 開啟線程的三種方式?

繼承Thread類、實作Runnable接口、實作Callable接口

  1. run()和start()方法差別

start()方法來啟動線程,真正實作了多線程運作,這時無需等待。run()方法當作普通方法的方式調用,程式還是要順序執行,還是要等待run方法體執行完畢。

  1. 在Java中wait和seelp方法的不同;

sleep()方法是屬于Thread類中的。而wait()方法,則是屬于Object類中的。

sleep()方法導緻了程式暫停執行指定的時間,讓出cpu給其他線程,線程不會釋放對象鎖。而當調用wait()方法的時候,但是他的監控狀态依然保持者,當指定的時間到了又會自動恢複運作狀态。線程會放棄對象鎖,進入等待此對象的等待鎖定池,隻有針對此對象調用notify()方法後本線程才進入對象鎖定池準備擷取對象鎖進入運作狀态。

  1. 談談wait/notify關鍵字的了解

基類 Object 提供了一些基礎的 wait/notify/notifyAll 方法。如果我們持有某個對象的 Monitor 鎖,調用 wait 會讓目前線程處于等待狀态,直到其他線程 notify 或者 notifyAll。

  1. 什麼導緻線程阻塞?
  • 線程執行了Thread.sleep
  • 線程執行一段同步代碼,但是尚且無法獲得相關的同步鎖,隻能進入阻塞狀态,等到擷取了同步鎖,才能回複執行。
  • 線程執行了一個對象的wait()方法,直接進入阻塞狀态,等待其他線程執行notify()或者notifyAll()方法。
  • 線程執行某些IO操作,因為等待相關的資源而進入了阻塞狀态。
  1. 線程如何關閉?
  • 使用退出标志,使線程正常退出,也就是當run方法完成後線程終止
  • 使用stop方法強行終止線程(這個方法不推薦使用,因為stop和suspend、resume一樣,可能發生不可預料的結果
  • 使用interrupt方法中斷線程。
  1. 講一下java中的同步的方法
  2. 資料一緻性如何保證?
  3. 如何保證線程安全?
  4. 如何實作線程同步?
  5. 兩個程序同時要求寫或者讀,能不能實作?如何防止程序的同步?
  6. 線程間操作List
  7. Java中對象的生命周期
  8. Synchronized用法
  9. synchronize的原理

synchronized 代碼塊是由一對兒 monitorenter/monitorexit 指令實作的,Monitor 對象是同步的基本實作單元。

三種不同的鎖:偏斜鎖(Biased Locking)、輕量級鎖和重量級鎖。

所謂鎖的更新、降級,就是 JVM 優化 synchronized 運作的機制,當 JVM 檢測到不同的競争狀況時,會自動切換到适合的鎖實作,這種切換就是鎖的更新、降級。當沒有競争出現時,預設會使用偏斜鎖。

  1. 談談對Synchronized關鍵字,類鎖,方法鎖,重入鎖的了解
  2. static synchronized 方法的多線程通路和作用
  3. 同一個類裡面兩個synchronized方法,兩個線程同時通路的問題

多個線程通路同一個類的synchronized方法時, 都是串行執行的 ! 就算有多個cpu也不例外 ! synchronized方法使用了類java的内置鎖, 即鎖住的是方法所屬對象本身. 同一個鎖某個時刻隻能被一個執行線程所擷取, 是以其他線程都得等待鎖的釋放. 是以就算你有多餘的cpu可以執行, 但是你沒有鎖, 是以你還是不能進入synchronized方法執行

  1. volatile的原理

輕量級的synchronized,隻能用來修飾變量

保證了可見性和有序性(不保證原子性),如果一個共享變量被volatile關鍵字修飾,那麼如果一個線程修改了這個共享變量後,其他線程是立馬可知的。

當對volatile變量進行寫操作的時候,JVM會向處理器發送一條lock字首的指令,将這個緩存中的變量回寫到系統主存中。用到了緩存一緻性協定。

  1. 談談volatile關鍵字的用法
  2. 談談volatile關鍵字的作用
  3. synchronized 和volatile 關鍵字的差別

synchronized提供了同步鎖的概念,被synchronized修飾的代碼段可以防止被多個線程同時執行,必須一個線程把synchronized修飾的代碼段都執行完畢了,其他的線程才能開始執行這段代碼。因為synchronized保證了在同一時刻,隻能有一個線程執行同步代碼塊,是以執行同步代碼塊的時候相當于是單線程操作了,那麼線程的可見性、原子性、有序性(線程之間的執行順序)它都能保證了。

差別:

  • volatile隻能作用于變量,使用範圍較小。synchronized可以用在變量、方法、類、同步代碼塊等,使用範圍比較廣。
  • volatile隻能保證可見性和有序性,不能保證原子性。而可見性、有序性、原子性synchronized都可以包證。
  • volatile不會造成線程阻塞。synchronized可能會造成線程阻塞。
    1. synchronized與Lock的差別
  • lock是一個接口,而synchronized是java的一個關鍵字
  • synchronized在發生異常時候會自動釋放占有的鎖,是以不會出現死鎖;而lock發生異常時候,不會主動釋放占有的鎖
  • Lock可以通過trylock來知道有沒有擷取鎖,而synchronized不能;
  • synchronized原始采用的是CPU悲觀鎖機制,即線程獲得的是獨占鎖。而Lock用的是樂觀鎖方式。所謂樂觀鎖就是,每次不加鎖而是假設沒有沖突而去完成某項操作,如果因為沖突失敗就重試,直到成功為止。
  1. ReentrantLock 、synchronized和volatile比較
  2. ReentrantLock的内部實作
  3. lock原理
  4. 死鎖的四個必要條件?
  • 互斥條件:一個資源每次隻能被一個程序使用,即在一段時間内某 資源僅為一個程序所占有。此時若有其他程序請求該資源,則請求程序隻能等待。
  • 請求與保持條件:程序已經保持了至少一個資源,但又提出了新的資源請求,而該資源 已被其他程序占有,此時請求程序被阻塞,但對自己已獲得的資源保持不放。
  • 不可剝奪條件:程序所獲得的資源在未使用完畢之前,不能被其他程序強行奪走,即隻能 由獲得該資源的程序自己來釋放(隻能是主動釋放)。
  • 循環等待條件: 若幹程序間形成首尾相接循環等待資源的關系
  1. 怎麼避免死鎖?
  2. 對象鎖和類鎖是否會互相影響?

類鎖和對象鎖不是同1個東西,一個是類的Class對象的鎖,一個是類的執行個體的鎖。也就是說:1個線程通路靜态synchronized的時候,允許另一個線程通路對象的執行個體synchronized方法。反過來也是成立的,因為他們需要的鎖是不同的。

  1. 什麼是線程池,如何使用?

一個線程池包括以下四個基本組成部分:

1、線程池管理器(ThreadPool):用于建立并管理線程池,包括 建立線程池,銷毀線程池,添加新任務;

2、工作線程(PoolWorker):線程池中線程,在沒有任務時處于等待狀态,可以循環的執行任務;

3、任務接口(Task):每個任務必須實作的接口,以供工作線程排程任務的執行,它主要規定了任務的入口,任務執行完後的收尾工作,任務的執行狀态等;

4、任務隊列(taskQueue):用于存放沒有處理的任務。提供一種緩沖機制。

常見線程池有:newSingleThreadExecutor(單線程串行)、newFixedThreadExecutor(固定數量)、newCacheThreadExecutor(可緩存、推薦)、newScheduleThreadExecutor(大小無限制)

  1. Java的并發、多線程、線程模型
  2. 談談對多線程的了解

線程是由一個主線程和很多個子線程組成的,主線程消失,子線程也會消失,但是子線程消失其中一個主線程不會消失

線程的生命周期分為5個步驟像人的一生一樣,這5個步驟分别對應了5個方法

新生–>啟動–>運作–>阻塞–>銷毀

  1. 多線程有什麼要注意的問題?

線程之間共用程序所有資源,當多線程操作同一個變量的時候,可能會使得結果不正确。

是以要特别注意線程安全的問題。

通常保證線程安全有很多種方式

  • 使用線程鎖
  • 使用串行隊列
  • 使用線程安全的類
  • 使用信号量或runloop使異步看起來像同步在執行
  • 注意任務可能本身就是異步的
  1. 談談你對多線程同步機制的了解?

線程同步是為了確定線程安全,所謂線程安全指的是多個線程對同一資源進行通路時,有可能産生資料不一緻問題,導緻線程通路的資源并不是安全的。如果多線程程式運作結果和單線程運作的結果是一樣的,且相關變量的值與預期值一樣,則是線程安全的。

  1. 如何保證多線程讀寫檔案的安全?
  2. 多線程斷點續傳原理

多線程下載下傳檔案時,檔案是被分成多個部分,是被不同的線程同時下載下傳的,此時就需要每一條線程都分别需要一個記錄點,和每個線程完成狀态的記錄。隻有将所有線程的下載下傳狀态都處于完成狀态時,才能表示檔案下載下傳完成。

1、首先擷取要下載下傳檔案的長度,用來設定RomdomAccessFile(本地檔案)的長度

2、實時儲存檔案的下載下傳進度(此功能可以用資料庫來實作)

3、中斷後再次下載下傳,讀取進度,再從上次的下載下傳進度繼續下載下傳,并在本地的檔案續續寫如。

擷取檔案長度:fileLength = HttpUrlConnection.getContentLength()

每條線程需要下載下傳的大小 = fileLength / Thread_Num

  1. 斷點續傳的實作

二、Android

Android面試題包括Android基礎,還有一些源碼級别的、原理這些等。是以想去大公司面試,一定要多看看源碼和實作方式,常用架構可以試試自己能不能手寫實作一下,鍛煉一下自己。

(一)Android基礎知識點

  1. 四大元件是什麼

Activity/Service/BroadCast Recevicer/Content provider

  1. 四大元件的生命周期和簡單用法
  2. Activity之間的通信方式
  • 在Intent跳轉時攜帶資料
  • 借助類的靜态變量
  • 借助全局變量 Application
  • 借助Service服務
  • 借助外部存儲來實作通訊
  • 借助 SharedPreference
  • 使用Android資料庫 SQLite
  • 使用 File本地檔案
  1. 橫豎屏切換的時候,Activity 各種情況下的生命周期

Activity未配置configChanges屬性,切到橫屏後,再切回豎屏時,會走兩遍onPause——onSaveInstanceState——onStop——onDestroy——onCreate——onStart——onRestoreInstanceState——onResume 生命周期方法

隻要随意配置了configChanges屬性,切到橫屏和再切到豎屏,生命周期調用順序都表現為onConfigurationChanged

  1. Activity與Fragment之間生命周期比較
  2. Activity上有Dialog的時候按Home鍵時的生命周期

onPause() -> onStop()

對話框的出現并沒有使Activity進入背景。而是點選Home鍵才使Activity進入背景工作

  1. 兩個Activity 之間跳轉時必然會執行的是哪幾個方法?

當在A 裡面激活B 元件的時候, A會調用onPause()方法,然後B調用onCreate() ,onStart(), onResume()。

這個時候B覆寫了A的窗體, A會調用onStop()方法。

如果B是個透明的視窗,或者是對話框的樣式, 就不會調用A的onStop()方法。

如果B已經存在于Activity棧中,B就不會調用onCreate()方法。

  1. Activity的四種啟動模式對比
  • 标準模式(standard)每次啟動一個标準模式的Activity都會重新建立一個新的執行個體,不管這個Activity之前是否已經存在執行個體
  • 棧頂複用模式(singleTop)新啟動的Activity已經位于任務戰的棧頂,那麼此Activity不會被重新建立,隻會重新調用 onNewIntent 方法,這個Activity的onCreate、onStart都不會被系統調用。如果新Activity執行個體已經存在但不在棧頂,那麼重新建立 Activity 并放入棧頂
  • 棧内複用模式(singleTask)一個棧中同一個Activity隻存在唯一一個執行個體,無論是否在棧頂,隻要存在執行個體,都不會重新建立,和 singleTop 一樣會重新調用 onNewIntent 方法。需要注意的是:如果一個Activity被設定為singleTask模式,那麼當棧内已經存在該Activity執行個體時,再啟動該Activity,會讓該Activity執行個體之上的Activity被出棧
  • 單例模式(singleInstance)這是一種加強的singleTask模式,它除了具有singleTask模式的所有特性外,還加強了一點,那就是此種模式的Activity隻能單獨地位于一個任務棧中,不同的應用去打開這個activity 共享公用的同一個activity。他會運作在自己單獨,獨立的任務棧裡面,并且任務棧裡面隻有他一個執行個體存在。應用場景:呼叫來電界面。
  1. Activity狀态儲存與恢複

臨時性資料

onSaveInstanceState調用的原則是系統有未經你的許可銷毀Activity的可能。那麼onSaveInstanceState有下面幾種情況會調用:

按下HOME鍵、長按HOME鍵切換到了其他APP、橫豎屏切換、Activity的導航、鎖定螢幕

onRestoreInstanceState被調用的原則是Activity被銷毀了,而不是可能被銷毀了。

持久性資料

在onResume和onPause方法中做,可以把資料儲存在資料庫或者SharedPreference中。然而在生命周期函數中不适合做耗時的操作

  1. 如何實作Fragment的滑動?ViewPager+Fragment
  2. fragment之間傳遞資料的方式?

定義資料接口,在Activity中實作該接口,并實作接口中定義的方法,在Fragment A中聲明接口對象,并調用接口中的方法,Activity中的接口回調中,向Fragment B傳遞資料

EventBus傳值

  1. Activity 怎麼和Service 綁定?

Activity 通過 bindService(Intent service, ServiceConnection conn, int flags) 跟服務 進行綁定, 當綁定成功的時候服務會将代理對象通過 onBind() 方法傳給 conn, 這樣我們就拿到了服務提供的服務代理對象

  1. 怎麼在Activity 中啟動自己對應的Service?
  2. service和activity怎麼進行資料互動?

Activity和Service的互動方式主要有以下幾種:通過廣播進行互動、通過共享檔案、Messenger、AIDL

  1. Service的開啟方式
  2. 請描述一下Service 的生命周期
  • onCreate(): 首次建立服務時,系統将調用此方法。如果服務已在運作,則不會調用此方法,該方法隻調用一次。
  • onStartCommand(): 當另一個元件通過調用startService()請求啟動服務時,系統将調用此方法。
  • onDestroy(): 當服務不再使用且将被銷毀時,系統将調用此方法。
  • onBind(): 當另一個元件通過調用bindService()與服務綁定時,系統将調用此方法。
  • onUnbind(): 當另一個元件通過調用unbindService()與服務解綁時,系統将調用此方法。
  • onRebind(): 當舊的元件與服務解綁後,另一個新的元件與服務綁定,onUnbind()傳回true時,系統将調用此方法。
  1. 請描述一下廣播BroadcastReceiver的了解
  2. 廣播的分類
  3. 廣播使用的方式和場景
  4. BroadcastReceiver,LocalBroadcastReceiver 差別

BroadcastReceiver用于應用之間的傳遞消息;而LocalBroadcastManager用于應用内部傳遞消息,比broadcastReceiver更加高效。

BroadcastReceiver使用的Content API,是以本質上它是跨應用的,是以在使用它時必須要考慮到不要被别的應用濫用;LocalBroadcastManager不需要考慮安全問題,因為它隻在應用内部有效。

  1. AlertDialog,popupWindow,Activity差別

AlertDialog 是非阻塞式對話框;而PopupWindow 是阻塞式對話框。

兩者最根本的差別在于有沒有建立一個 window,PopupWindow 沒有建立,而是通過 WMS 将 View 加到 DecorView;Dialog 是建立了一個 window (PhoneWindow),相當于走了一遍 Activity 中建立 window 的流程。

  1. Application 和 Activity 的 Context 對象的差別

Acitiivity 繼承自ContextThemeWrapper—>再繼承ContextWrapper—>Context。

Appliction 、Service繼承自ContextWrapper—>再繼承Context。

Application、Service 和 Activity 最終都是繼承自Context,是以它們是同一個上下文。

  1. Android屬性動畫特性

屬性動畫可以對任何對象的屬性做動畫而不僅僅是View,甚至可以沒有對象。除了作用對象進行擴充外,屬性動畫的效果也加強了,不僅能實作View動畫的4中效果,還能實作其它多種效果,這些效果都是通過ValuAnimator或ObjectAnimator、AnimatorSet等來實作的。

  1. 如何導入外部資料庫?
  2. LinearLayout、RelativeLayout、FrameLayout的特性及對比,并介紹使用場景。

RelativeLayout會讓子View調用2次onMeasure,LinearLayout 在有weight時,也會調用子View2次onMeasure

RelativeLayout的子View如果高度和RelativeLayout不同,則會引發效率問題,當子View很複雜時,這個問題會更加嚴重。如果可以,盡量使用padding代替margin

  1. 談談對接口與回調的了解
  2. 回調的原理

回調是一段可執行的代碼通過參數傳遞給别一段代碼,以期望在一個合适的時間調用這個參數

  1. 寫一個回調demo

    Callback.java

    public interface Callback {

    void printFinished(String msg);

    }

    Printer.java

    public class Printer {

    public void print(Callback callback) {

    System.out.println("正在列印 . . . ");

    try {

    Thread.currentThread();

    Thread.sleep(3000);// 毫秒

    } catch (Exception e) {

    e.printStackTrace();

    }

    callback.printFinished(“列印完成”);

    }

    }

    People.java

    public class People {

    Printer printer = new Printer();

    // 同步回調

    public void goToPrintSyn(Callback callback) {

    printer.print(callback);

    }

    // 異步回調

    public void goToPrintASyn(Callback callback) {

    new Thread(new Runnable() {

    public void run() {

    printer.print(callback);

    }

    }).start();

    }

    }

  2. 介紹下SurfView
  3. RecycleView的使用
  4. 序列化的作用,以及Android兩種序列化的差別
  5. 內插補點器

Interpolator設定 屬性值 從初始值過渡到結束值 的變化規律的一個接口,如勻速、加速 & 減速 等等,即确定了 動畫效果變化的模式,如勻速變化、加速變化 等等

應用場景:實作非線性運動的動畫效果

  1. 估值器

TypeEvaluator設定 屬性值 從初始值過渡到結束值 的變化具體數值的接口

插值器(Interpolator)決定 值 的變化規律(勻速、加速blabla),即決定的是變化趨勢;而接下來的具體變化數值則交給估值器

屬性動畫特有的屬性,協助插值器 實作非線性運動的動畫效果

  1. Android中資料存儲方式

五種資料存儲 :SharePreferences、SQLite、Contert Provider、File、網絡存儲

(二)Android源碼相關分析

  1. Android動畫架構實作原理

Android 動畫就是通過 ParentView 來不斷調整 ChildView 的畫布坐标系來實作的

這其中又涉及到兩個重要的類型,Animation 和 Transformation,這兩個類是實作動畫的主要的類,Animation 中主要定義了動畫的一些屬性比如開始時間、持續時間、是否重複播放等,這個類主要有兩個重要的函數:getTransformation 和 applyTransformation,在 getTransformation 中 Animation 會根據動畫的屬性來産生一系列的內插補點點,然後将這些內插補點點傳給 applyTransformation,這個函數将根據這些點來生成不同的 Transformation,Transformation 中包含一個矩陣和 alpha 值

  1. Android各個版本API的差別

    //V9.0:劉海屏的适配、電源管理、開發的應用預設不支援Http

    //V8.0:通知欄适配(Notifcation)、廣播限制、背景服務限制 8.0以上建立的前台Service需要發送一個Notification,否則Service會Anr

    //V7.0:多視窗支援、檔案讀寫權限适配、引入一項新的應用簽名方案 :APK Signature Scheme v2、需要适配FileProvider,否則應用會崩潰。app之間的私有檔案共享隻能用FileProvider這種方式.

    //V6.0:Android 動态權限申請、指紋識别、移除HttpClient庫

    //V5.0:虛拟機由Dalvik替換為Art虛拟機,Dalvik 使用JIT編譯器,Art是AOT編譯器、Materil Design設計規範、WebView cookie 存儲問題

    //V4.0:沉浸式狀态欄、WebView webview調試功能、WebView 增加對 https請求限制需要去驗證https證書

  2. Requestlayout,onlayout,onDraw,DrawChild差別與聯系

requestLayout()方法對View樹進行重新布局,過程包括了measure()和layout()過程,但不會調用draw()過程,即不會發生重新繪制視圖過程。

onLayout()的調用時機是:View需要給自己設定大小和位置了或者ViewGroup需要給子View和ViewGroup自身時調用。

View的繪制流程一共包括三步:①測量measure;②布局layout;③繪制draw;onDraw()方法就是在第三布繪制時發生,開發者已經測量好View的大小,設定好View的布局,剩下最後一步就是,具體畫出這個布局。畫的方法就是onDraw(),每個View都需要利用這個方法畫出自己,ViewGroup除非設定了背景,否則不用調用該方法。

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

  1. invalidate和postInvalidate的差別及使用

當Invalidate()被調用的時候,View的OnDraw()就會被調用;Invalidate()是重新整理UI,UI更新必須在主線程,是以invalidate必須在UI線程中被調用,如果在子線程中更新視圖的就調用postInvalidate()。

postInvalidate()實際調用的方法,mHandler.sendMessageDelayed,在子線程中用handler發送消息,是以才能在子線程中使用。

  1. Activity-Window-View三者的差别

Activity 是四大元件之一,也是我們的界面載體,可以展示頁面;而 View 實際上就是一個一個的視圖,這些視圖可以搭載在一個 Layout 檔案上,通過 Activity 的 setContentView() 方法傳遞給 Activity;Window 是一個窗體,每個 Activity 對應一個 Window,通常我們在代碼中用 getWindow() 來擷取它。

每個 Activity 包含了一個 Window 對象,這個對象是由 PhoneWindow 做的實作。而 PhoneWindow 将 DecorView 作為了一個應用視窗的根 View,這個 DecorView 又把螢幕劃分為了兩個區域:一個是 TitleView,一個是 ContentView,而我們平時在 Xml 檔案中寫的布局正好是展示在 ContentView 中的。

  1. 談談對Volley的了解
  2. 如何優化自定義View
  3. 低版本SDK如何實作高版本api?
  4. 描述一次網絡請求的流程
  5. HttpUrlConnection 和 okhttp關系
  6. Bitmap對象的了解
  7. looper架構
  8. ActivityThread,AMS,WMS的工作原理
  9. 自定義View如何考慮機型适配
  10. 自定義View的事件
  11. AstncTask+HttpClient 與 AsyncHttpClient有什麼差別?
  12. LaunchMode應用場景
  13. AsyncTask 如何使用?
  14. SpareArray原理
  15. 請介紹下ContentProvider 是如何實作資料共享的?
  16. AndroidService與Activity之間通信的幾種方式
  17. IntentService原理及作用是什麼?
  18. 說說Activity、Intent、Service 是什麼關系
  19. ApplicationContext和ActivityContext的差別
  20. SP是程序同步的嗎?有什麼方法做到同步?
  21. 談談多線程在Android中的使用
  22. 程序和 Application 的生命周期
  23. 封裝View的時候怎麼知道view的大小
  24. RecycleView原理

RecyclerView是谷歌官方出的一個用于大量資料展示的新控件,可以用來代替傳統的ListView,更加強大和靈活。支援RecyclerView高效運作的主要六大類:

  • Adapter:為每一項Item建立視圖
  • ViewHolder:承載Item視圖的子布局
  • LayoutManager:負責Item視圖的布局的顯示管理
  • ItemDecoration:給每一項Item視圖添加子View,例如可以進行畫分隔線之類
  • ItemAnimator:負責處理資料添加或者删除時候的動畫效果
  • Recycler:負責RecyclerView中子View的回收與複用

RecyclerView擁有四級緩存:

  • 螢幕内緩存:指螢幕内的ViewHolder,緩存在mAttachedScrap(資料已改變)、mChangedScrap(未分離的)
  • 螢幕外緩存:滑出螢幕緩存在mCachedViews,預設個數是2個,可設定
  • 自定義緩存:自己實作ViewCacheExtension,一般不會用到
  • 緩存池:ViewHolder首先會緩存在mCachedViews中,超過2個,就會添加到mRecyclerPool中。mRecyclerPool會根據ViewType把ViewHolder分别存儲在不同集合中,每個集合最多緩存5個ViewHolder。

Recyclerview在擷取ViewHolder時按四級緩存的順序查找,如果沒找到就建立。通過了解RecyclerView的四級緩存,我們可以知道,RecyclerView最多可以緩存N(螢幕最多可顯示的item數)+ 2 (螢幕外的緩存) + 5*M (M代表M個ViewType,緩存池的緩存)。

  1. AndroidManifest的作用與了解

歸根結底就是Android系統的app需要通過文本方式直接告訴系統的資訊太多了

  1. Canvas save restore

save():儲存目前的繪圖狀态。restore():恢複之前儲存的繪圖狀态。

  1. onMeasure()、onLayout()、onDraw()
  • onMeasure():這個函數最終目的是設定尺寸,如果“自己”是 ViewGroup 則必須在測量自己的同時,測量所有“子View”的 “尺寸”

    必須調用 void setMeasuredDimension(int measuredWidth, int measuredHeight) 來設定“尺寸”,不調用會抛出異常 IllegalStateException

    參數 widthMeasureSpec heightMeasureSpec 是“父View”配置設定給“自己”的 measure spec,可以看做是“父View”對“自己”的要求,MeasureSpec是由一個32位 int 值來表示的。其中該 int 值對應的二進制的高2位代表SpecMode,低30位代表SpecSize

  • onLayout():安排自己的子View的位置。調用childView的layout(l, t, r, b)方法。
  • onDraw():

    第一步,對視圖的背景進行繪制。

    第三步,對視圖的内容進行繪制。

    第四步,對目前視圖的所有子視圖進行繪制。

    第六步,對視圖的滾動條進行繪制。

    建議不要在onDraw方法體裡建立對象,因為onDraw方法會被頻繁調用,減少垃圾回收對繪圖性能的影響。

    canvas.save canvas.restore

(三)常見的一些原理性問題

  1. Handler機制和底層實作
  2. Handler、Thread和HandlerThread的差别

Handler:在android中負責發送和處理消息,通過它可以實作其他支線線程與主線程之間的消息通訊。

Thread:Java程序中執行運算的最小機關,亦即執行處理機排程的基本機關。某一程序中一路單獨運作的程式。

HandlerThread:一個繼承自Thread的類HandlerThread,Android中沒有對Java中的Thread進行任何封裝,而是提供了一個繼承自Thread的類HandlerThread類,這個類對Java的Thread做了很多便利的封裝。

HandlerThread對象start後可以獲得其Looper對象,并且使用這個Looper對象執行個體Handler,之後Handler就可以運作在其他線程中了。

  1. handler發消息給子線程,looper怎麼啟動?
  2. 關于Handler,在任何地方new Handler 都是什麼線程下?

目前線程如果是主線程的話,Handler handler = new Handler();不是主線程的話,Looper.prepare(); Handler handler = new Handler();Looper.loop();或者Handler handler = new Handler(Looper.getMainLooper());

  1. ThreadLocal原理,實作及如何保證Local屬性?
  2. 請解釋下在單線程模型中Message、Handler、Message Queue、Looper之間的關系

Message: 消息對象

MessageQueen: 存儲消息對象的隊列

Looper:負責循環讀取MessageQueen中的消息,讀到消息之後就把消息交給Handler去處理。

Handler:發送消息和處理消息

  1. 請描述一下View事件傳遞分發機制
  • dispatchTouchEvent:用于分發事件,該方法決定是由目前的View自己的onTouchEvent來處理,還是分發給子View,讓子View遞歸調用其自身的dispatchTouchEvent來處理。
  • onInterceptTouchEvent:用來攔截事件,當父控件下發事件給子控件進行攔截處理的時候,如果子控件需要對事件進行處理,就要在onInterceptTouchEvent方法中進行事件的監聽以及邏輯的判斷。
  • onTouchEvent:用于處理傳遞到View的手勢事件。
  1. Touch事件傳遞流程

Activity -> PhoneWindow -> DecorView -> ViewGroup -> … -> View

  1. 事件分發中的onTouch 和onTouchEvent 有什麼差別,又該如何使用?

onTouchEvent方法是專門用來處理事件分發的,它一定存在Activity、View和ViewGroup這三者中。onTouch方法是View設定了觸摸監聽事件後,需要重寫的方法,是OnTouchListener接口中的方法。

  1. View和ViewGroup分别有哪些事件分發相關的回調方法
  2. View重新整理機制

在Android的View重新整理機制中,父View負責重新整理(invalidateChild)、布局(layoutChild)顯示子View。而當子View需要重新整理時,則是通知父View重新整理子view來完成。

  1. View繪制流程

View的繪制基本分為measure、layout、draw 過程

測量一個比較重要的概念是,MeasureSpec一共有三種模式

  • UPSPECIFIED : 父容器對于子容器沒有任何限制,子容器想要多大就多大
  • EXACTLY: 父容器已經為子容器設定了尺寸,子容器應當服從這些邊界,不論子容器想要多大的空間。
  • AT_MOST:子容器可以是聲明大小内的任意大小

https://www.jianshu.com/p/5a71014e7b1b

  1. 自定義控件原理
  2. 自定義View如何提供擷取View屬性的接口?
  3. Android代碼中實作WAP方式聯網
  4. AsyncTask機制
  5. AsyncTask原理及不足
  6. 如何取消AsyncTask?
  7. 為什麼不能在子線程更新UI?
  8. ANR産生的原因是什麼?

在Android裡,應用程式的響應性是由Activity Manager和WindowManager系統服務監視的 。當它監測到以下情況中的一個時,Android就會針對特定的應用程式顯示ANR:

  • 1.在5秒内沒有響應輸入的事件(例如,按鍵按下,螢幕觸摸)
  • 2.BroadcastReceiver在10秒内沒有執行完畢
  • 3.service是20

造成以上兩點的原因有很多,比如在主線程中做了非常耗時的操作,比如說是下載下傳,io異常等。

  1. ANR定位和修正
  2. oom是什麼?
  3. 什麼情況導緻oom?
  4. 有什麼解決方法可以避免OOM?
  5. Oom 是否可以try catch?為什麼?
  6. 記憶體洩漏是什麼?
  7. 什麼情況導緻記憶體洩漏?
  • 資源性對象未關閉(比如Cursor、File等)
  • 注冊對象未登出,一般發生在廣播接收器、注冊觀察者等。
  • 類的靜态變量持有大資料對象,如Bitmap等
  • 非靜态内部類的靜态執行個體,靜态内部類會維持一個外部類執行個體的引用,阻止被系統回收。
  • Handler臨時性記憶體洩漏
  • 容器中的對象沒清理,在不需要該對象時,應該及時從集合中清理出去。
  • WebView
  1. 如何防止線程的記憶體洩漏?

檢查、監控、優化

  • 對象引用-根據業務需求合理的使用強弱軟虛引用。
  • 減少不必要的記憶體開銷-記憶體複用

    有效利用系統自帶的資源,比如一些通用的字元串、顔色定義、常用Icon圖示,還有些樣式和簡單布局。

    視圖複用-adapter裡ViewHolder的運用

    使用對象池減少記憶體的配置設定和回收

    Bitmap對象的複用-inBitmap屬性可以告知Bitmap解碼器嘗試使用已經存在的記憶體區域。

  • 使用最優的資料類型

    HashMap與ArrayMap,Android提供的ArrayMap更節省記憶體。

    盡量避免使用枚舉類型-枚舉類型的最大優點是類型安全,但在Android平台上記憶體開銷是直接定義常量的三倍以上

    LruCache-推薦做圖檔記憶體緩存,既不要太大(會造成其他可用記憶體太小),也不要太小,具體要綜合考慮。

  • 圖檔記憶體優化

    設定位圖規格、isSampleSize、inScaled/inDensity/inTargetDensity、inBitmap(decode方法會嘗試重用一個已經存在的位圖)

  1. 記憶體洩露場景的解決方法
  2. 記憶體洩漏和記憶體溢出差別?
  3. LruCache預設緩存大小。基本上設定為手機記憶體的1/8
  4. ContentProvider的權限管理(解答:讀寫分離,權限控制-精确到表級,URL控制)
  5. 如何通過廣播攔截和abort一條短信?

在清單檔案中注冊廣播接收器,設定該廣播接收器優先級,盡量設高一點

建立一個BroadcastReceiver來實作廣播的處理,并設定攔截器abortBroadcast();

  1. 廣播是否可以請求網絡?子線程可以
  2. 廣播引起anr的時間限制是多少?10s
  3. 計算一個view的嵌套層級

    while(view.getParent() != null) {

    count++;

    View = view.getParents();

    }

  4. Activity棧
  5. Android線程有沒有上限?
  6. 線程池有沒有上限?
  7. ListView重用的是什麼?
  8. Android為什麼引入Parcelable?

Serializable 會使用反射,序列化和反序列化過程需要大量 I/O 操作, Parcelable 自已實作封送和解封(marshalled &unmarshalled)操作不需要用反射,資料也存放在 Native 記憶體中,效率要快很多。

  1. 有沒有嘗試簡化Parcelable的使用?
  2. App的啟動流程?
  • 點選App圖示,Launcher程序采用Binder IPC像system_server程序發起startActivity請求
  • system_server程序接收到請求後,向zygote程序發送建立程序的請求
  • Zygote程序fork出新的子程序,即App程序
  • App程序通過Binder IPC向system_server程序發起attachApplication請求
  • system_server程序接收到請求後,進行一系列準備工作後,再通過Binder IPC向App程序發送scheduleLaunchActivity請求
  • App程序的Binder線程在收到請求後,通過Handler向主線程發送LAUNCH_ACTIVITY消息
  • 主線程收到Message後,通過發射機制建立目标Activity,并回調Activity.onCreate()等法法。
  • 到此,App便正式啟動,開始進入Activity生命周期。

(四)開發中常見的一些問題

  1. ListView 中圖檔錯位的問題是如何産生的?
  2. 混合開發有了解嗎?
  3. 知道哪些混合開發的方式?說出它們的優缺點和各自使用場景?(解答:比如:RN,weex,H5,小程式,WPA等。做Android的了解一些前- 端js等還是很有好處的);
  4. 螢幕适配的處理技巧都有哪些?
  5. 伺服器隻提供資料接收接口,在多線程或多程序條件下,如何保證資料的有序到達?
  6. 動态布局的了解
  7. 怎麼去除重複代碼?
  8. 畫出 Android 的大體架構圖
  • 應用層:用Java語言編寫的運作在虛拟機上的程式,如電子郵件、短信、月曆、浏覽器和聯系人等
  • 應用架構層:系統元件API(Content Provicers、Views、Manager(Activity、Notification、Resource、Telephony、Window))
  • 系統運作庫(原生C/C++庫及Android運作庫):當使用Android應用架構時,Android系統會通過一些C/C++庫來支援我們使用的各個元件,使其更好的為我們服務,比如SQLite、Webkit。
  • Linux核心:Android核心系統服務,如安全性、記憶體管理、程序管理、網絡協定棧和驅動模型都依賴于該核心。Linux核心也是作為硬體與軟體棧的抽象層。
  1. Recycleview和ListView的差別

RecyclerView比ListView多兩級緩存,支援多個離ItemView緩存,支援開發者自定義緩存處理邏輯,支援所有RecyclerView共用同一個RecyclerViewPool(緩存池)。

RecyclerView更大的亮點在于提供了局部重新整理的接口,通過局部重新整理,就能避免調用許多無用的bindView。ListView和RecyclerView最大的差別在于資料源改變時的緩存的處理邏輯,ListView是"一鍋端",将所有的mActiveViews都移入了二級緩存mScrapViews,而RecyclerView則是更加靈活地對每個View修改标志位,區分是否重新bindView.

https://www.jianshu.com/p/257c279a3493

Android新增的Recyclerview主要用于代替ListView。Recyclerview可擴充性強。

  • 可以通過LayoutManager形成線性(橫向與豎向)、網格、瀑布流布局。
  • 通過OnItemTouchListener監聽 Item 的事件,雖然比ListView.OnItemClickListener麻煩了點,但是可以實作更複雜的功能,比如item滑動。
  • 提供了notifyItemInserted、notifyItemRemoved、notifyItemChanged、notifyItemMoved來提高局部重新整理的效率。
  • 沒有ListView那種 HeaderView 和 FooterView , 但可以通過來 getItemViewType來生成不同的視圖。
  • RecyclerView還定義了ViewHolder,配合RecyclerView.Adapter,封裝重用ItemView的邏輯,還有四級緩存,效率大大增加。
  1. ListView圖檔加載錯亂的原理和解決方案

1>:某一個位置的元素剛進入螢幕開始請求圖檔,圖檔沒有下載下傳完成,就被移出螢幕,根據ListView工作原理可知,被移出螢幕的控件會很快的被重複利用起來,如果在這個時候之前發起圖檔的請求有了響應,會将剛才位置的圖檔顯示到目前位置,雖然他們位置不同,卻共用着同一個ImageView執行個體,這個時候會出現圖檔亂序;

2>:新進入螢幕的元素也會去請求圖檔,等圖檔下載下傳完的時候會設定到同樣的ImageView,是以就出現先顯示一張圖檔,然後又變為另一張圖檔,就造成圖檔變來變去;

解決方案:

1>:在getView()方法中用url位址給ImageView設定tag标記;

2>:在onPostExecute()方法中調用 mListView.findViewWithTag(imageUrl) 擷取ImageView執行個體,然後判斷如果不為null,就把drawable圖檔設定到該ImageView控件上即可;

  1. 動态權限适配方案,權限組的概念
  2. Android系統為什麼會設計ContentProvider?談談你對ContentProvider的了解

ContentProvider應用程式間非常通用的共享資料的一種方式,也是Android官方推薦的方式。Android中許多系統應用都使用該方式實作資料共享,比如通訊錄、短信等。

設計用意在于:

封裝。對資料進行封裝,提供統一的接口,使用者完全不必關心這些資料是在DB,XML、Preferences或者網絡請求來的。當項目需求要改變資料來源時,使用我們的地方完全不需要修改。

提供一種跨程序資料共享的方式。

就是資料更新通知機制了。因為資料是在多個應用程式中共享的,當其中一個應用程式改變了這些共享資料的時候,它有責任通知其它應用程式,讓它們知道共享資料被修改了,這樣它們就可以作相應的處理。

ContentResolver接口的notifyChange函數來通知那些注冊了監控特定URI的ContentObserver對象,使得它們可以相應地執行一些處理。ContentObserver可以通過registerContentObserver進行注冊。

ContentProvider和調用者在同一個程序,ContentProvider的方法(query/insert/update/delete等)和調用者在同一線程中;

ContentProvider和調用者在不同的程序,ContentProvider的方法會運作在它自身所在程序的一個Binder線程中。

  1. 說說ContentProvider、ContentResolver、ContentObserver 之間的關系
  • ContentProvider——内容提供者, 在android中的作用是對外共享資料,也就是說你可以通過ContentProvider把應用中的資料共享給其他應用通路,其他應用可以通過ContentProvider 對你應用中的資料進行添删改查。
  • ContentResolver——内容解析者, 其作用是按照一定規則通路内容提供者的資料(其實就是調用内容提供者自定義的接口來操作它的資料)。
  • ContentObserver——内容觀察者,目的是觀察(捕捉)特定Uri引起的資料庫的變化,繼而做一些相應的處理,它類似于資料庫技術中的觸發器(Trigger),當ContentObserver所觀察的Uri發生變化時,便會觸發它。
  1. 下拉狀态欄是不是影響activity的生命周期

不會

  1. 如果在onStop的時候做了網絡請求,onResume的時候怎麼恢複?
  2. Bitmap 使用時候注意什麼?
  • 要選擇合适的圖檔規格(ALPHA_8、ARGB_4444、ARGB_8888、RGB_565)分别占用1、2、4、2byte,Alpha_8主要用于Alpha通道模闆,相當于做一個染色。圖像要渲染兩次,雖然減少記憶體,但是增加繪制的開銷。頭像一般使用ARGB_444
  • 減低采樣率。BitmapFactory.Options inSampleSize inJustDecodeBounds
  • 複用記憶體。通過軟引用複用記憶體塊
  • 及時回收。即,recycle
  • 壓縮圖檔。compress
  • 盡量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource來設定一張大圖,因為這些函數在完成decode後,最終都是通過java層的createBitmap來完成的,需要消耗更多記憶體,可以通過BitmapFactory.decodeStream方法
  1. Bitmap的recycler()
  2. Android中開啟攝像頭的主要步驟
  3. ViewPager使用細節,如何設定成每次隻初始化目前的Fragment,其他的不初始化?
  4. 點選事件被攔截,但是想傳到下面的View,如何操作?
  5. 微信首頁面的實作方式
  6. 微信上消息小紅點的原理

三、進階開發技術面試題

這裡講的是大公司需要用到的一些高端Android技術,這裡專門整理了一個文檔,希望大家都可以看看。這些題目有點技術含量,需要好點時間去研究一下的。

(一)圖檔

  1. 圖檔庫對比
  • Universal Image Loader:最早 支援View在滾動過程中暫停圖檔加載。 可以對多個子產品進行單獨配置。 持多級緩存以及多種緩存算法,可以根據使用場景選擇适合的緩存政策 以根據ImageView的大小對Bitmap進行裁剪,減少Bitmap占用過多的記憶體
  • Picasso:Square 自帶統計監控,如緩存命中率,記憶體使用大小,節省的流量等 支援優先級處理,每次任務排程前會選擇優先級高的任務 支援飛行模式,并發線程數根據網絡類型變化 其并沒有自己設計一套磁盤緩存,而是通過通過Okhttp網絡請求庫去實作,這樣的好處是可以通過Response Header中的cache-control和expired靈活的控制本地緩存
  • Glide:Google,Google官方推薦 支援Gif,Webp以及視訊檔案的解碼 支援縮略圖 activity生命周期綁定 支援加載動畫 Fresco:Facebook 4.4以及之前的系統上利用了匿名共享記憶體使得app可以使用比正常狀态下更多的記憶體 漸進式加載jpeg圖檔,支援圖檔從模糊到清晰加載; 圖檔可以以任意的中心點顯示在 ImageView上; 支援gif的顯示
  1. 圖檔庫的源碼分析
  2. 圖檔架構緩存實作
  3. LRUCache原理

LruCache的核心思想很好了解,就是要維護一個緩存對象清單,其中對象清單的排列方式是按照通路順序實作的,即一直沒通路的對象,将放在隊尾,即将被淘汰。而最近通路的對象将放在隊頭,最後被淘汰。這個隊列由LinkedHashMap來維護

  1. 圖檔加載原理
  2. 自己去實作圖檔庫,怎麼做?
  3. Glide源碼解析
  4. Glide使用什麼緩存?
  5. Glide記憶體緩存如何控制大小?

(二)網絡和安全機制

  1. 網絡架構對比和源碼分析
  2. 自己去設計網絡請求架構,怎麼做?
  3. okhttp源碼
  • 五個攔截器

    RetryAndFollowUpInterceptor:負責請求的重試和重定向

    BridgeInterceptor:給請求添加對應的 header 資訊,處理響應結果的header資訊

    CacheInterceptor:根據目前擷取的狀态選擇 網絡請求 、讀取緩存、更新緩存。

    ConnectInterceptor:建立 http 連接配接。

    CallServerInterceptor:讀寫網絡資料。

  • 攔截器順序: Interceptors -> RetryAndFollowUpInterceptor -> BridgeInterceptor -> CacheInterceptor -> ConnectInterceptor -> CallServerIntercepter
  • 請求流程: newCall(RealCall)->enqueue->Dispatcher->enqueue->getResponseWithInterceptorChain()->interceptors->response
  • RetryAndFollowUpInterceptor:負責請求的重試和重定向 BridgeInterceptor:給請求添加對應的 header 資訊,處理響應結果的header資訊 CacheInterceptor:根據目前擷取的狀态選擇 網絡請求 、讀取緩存、更新緩存。 ConnectInterceptor:建立 http 連接配接。 CallServerInterceptor:讀寫網絡資料。 攔截器順序: Interceptors -> RetryAndFollowUpInterceptor -> BridgeInterceptor -> CacheInterceptor -> ConnectInterceptor -> CallServerIntercepter 請求流程: newCall(RealCall)->enqueue->Dispatcher->enqueue->getResponseWithInterceptorChain()->interceptors->response
  1. 網絡請求緩存處理,okhttp如何處理網絡緩存的
  2. 從網絡加載一個10M的圖檔,說下注意事項
  3. TCP的3次握手和四次揮手
  • 請求 -> 應答 -> 應答之應答,例:A:您好,我是 A。B:您好 A,我是 B。A:您好 B。
  • 揮手:A:B 啊,我不想玩了。B:哦,你不想玩了啊,我知道了。B:A 啊,好吧,我也不玩了,拜拜。A:好的,拜拜。
  1. TCP與UDP的差別
  • TCP 是面向連接配接的,UDP 是面向無連接配接的。TCP 會三次握手,而 UDP 不會。
  • TCP 提供可靠傳遞。通過 TCP 連接配接傳輸的資料,無差錯、不丢失、不重複、并且按序到達。UDP 繼承了 IP 包的特性,不保證不丢失,不保證按順序到達。
  • TCP 是面向位元組流的。發送的時候發的是一個流,沒頭沒尾。而 UDP 繼承了 IP 的特性,基于資料報的,一個一個地發,一個一個地收。
  • TCP 是可以有擁塞控制的。它意識到包丢棄了或者網絡的環境不好了,就會根據情況調整自己的行為,看看是不是發快了,要不要發慢點。UDP 就不會,應用讓我發,我就發,管它洪水滔天。
  • 因而 TCP 其實是一個有狀态服務,通俗地講就是有腦子的,裡面精确地記着發送了沒有,接收到沒有,發送到哪個了,應該接收哪個了,錯一點兒都不行。而 UDP 則是無狀态服務。通俗地說是沒腦子的,天真無邪的,發出去就發出去了。
  1. TCP與UDP的應用

UDP使用場景:需要資源少,在網絡情況比較好的内網,或者對于丢包不敏感的應用。不需要一對一溝通,建立連接配接,而是可以廣播的應用。需要處理速度快,時延低,可以容忍少數丢包,但是要求即便網絡擁塞,也毫不退縮,一往無前的時候。

  1. HTTP協定
  2. HTTP1.0與2.0的差別
  • HTTP1.x的解析是基于文本。HTTP2.0的協定解析決定采用二進制格式,實作友善且健壯。
  • HTTP2.0多路複用,即連結共享
  • HTTP1.x的header帶有大量資訊,而且每次都要重複發送,
  • HTTP2.0使用encoder來減少需要傳輸的header大小,通訊雙方各自cache一份header fields表,既避免了重複header的傳輸,又減小了需要傳輸的大小。
  • HTTP2.0也具有server push功能。
  1. HTTP封包結構

HTTP 的封包大概分為三大部分。第一部分是請求行,第二部分是請求的首部,第三部分才是請求的正文實體。

  1. HTTP與HTTPS的差別以及如何實作安全性
  2. 如何驗證證書的合法性?
  3. https中哪裡用了對稱加密,哪裡用了非對稱加密,對加密算法(如RSA)等是否有了解?
  4. client如何确定自己發送的消息被server收到?
  5. 談談你對WebSocket的了解
  6. WebSocket與socket的差別
  7. 談談你對安卓簽名的了解。
  • V1:Android 應用的簽名工具有兩種:jarsigner 和 apksigner。它們的簽名算法沒什麼差別,主要是簽名使用的檔案不同。在 META-INF 檔案夾下有三個檔案:MANIFEST.MF、CERT.SF、CERT.RSA。它們就是簽名過程中生成的檔案

    簽名驗證是發生在 APK 的安裝過程中,一共分為三步:

    1. 檢查 APK 中包含的所有檔案,對應的摘要值與 MANIFEST.MF 檔案中記錄的值一緻。
    2. 使用證書檔案(RSA 檔案)檢驗簽名檔案(SF 檔案)沒有被修改過。
    3. 使用簽名檔案(SF 檔案)檢驗 MF 檔案沒有被修改過。

      劣勢:簽名校驗速度慢,完整性保障不夠,META-INF 目錄用來存放簽名,自然此目錄本身是不計入簽名校驗過程的,比如一些快速批量打包方案就選擇在這個目錄中添加管道檔案。

  • V2:是一種全檔案簽名方案,該方案能夠發現對 APK 的受保護部分進行的所有更改,進而有助于加快驗證速度并增強完整性保證。v2 簽名将驗證歸檔中的所有位元組,而不是單個 ZIP 條目
  1. 請解釋安卓為啥要加簽名機制?

在安裝 APK 時,需要確定 APK 來源的真實性,以及 APK 沒有被第三方篡改。

  1. 視訊加密傳輸
  2. App 是如何沙箱化,為什麼要這麼做?
  3. 權限管理系統(底層的權限是如何進行 grant 的)?

(三)資料庫

  1. sqlite更新,增加字段的語句
  2. 資料庫架構對比和源碼分析
  3. 資料庫的優化
  4. 資料庫資料遷移問題

(四)插件化、子產品化、元件化、熱修複、增量更新、Gradle

子產品化、元件化、插件化差別?

  • 子產品化:将一個複雜業務實作,根據功能、頁面或者其他進行不同粒度的劃分程不同的子產品,子產品之間解耦,分别進行實作,特點:子產品之間解耦,可以獨立管理。
  • 元件化:将一個app的代碼拆分成幾份獨立的元件,元件之間是低耦合的,可以獨立編譯打包;也可以将元件打包到一個apk中。是解耦與加快編譯,隔離不需要關注的部分

    (1)每個子產品可獨立編譯,提高了編譯速度;

    (2)開發隻負責自己的子產品,還可以再做的隔離一些,每個業務線隻可見自己業務子產品的代碼,避免了誤修改和版本管理問題。

    (3)公共的Lib依然是個獨立子產品

    與子產品化的差別:是每個子產品的角色的轉換,一個元件可以獨立編譯打包,也可以作為lib內建到整個apk中

  • 插件化:插件化是将一個apk根據業務功能拆分成不同的子apk,主流實作方式是通過Hook技術實作。

    主要問題:如何加載類、如何加載資源、如何管理元件生命周期。

    • 加載類:

      在宿主工程的AndroidManifest.xml中預先注冊Activity進行占坑。

      使用占坑Activity繞過AMS驗證。啟動Activity通過Hook Instrumentation類的execStartActvity,将啟動插件Activity的Intent替換成宿主預注冊的插樁Activity。

      還原插件Activity

    • 加載資源:在Application中重寫getResources,并傳回插件的Resources,因為插件apk中的四大元件實際都是在宿主apk建立的,那麼他們拿到的Application實際上都是宿主的,是以它們隻需要通過getApplication().getResources()就可以非常友善的拿到插件的Resource。
    • 元件生命周期:通常的做法是通過Hook相應的系統對象,實作欺上瞞下

      從技術上講,就是解決如何啟動未安裝的apk裡面的類(主要是四大元件)。

      與元件化的主要差別:

    • 形式上的差別,元件化的機關是module,插件化的機關是apk
    • 關注點不同,插件化更關注動态加載、熱更新、熱修複等‘插拔’技術。
  1. 對熱修複的了解

主流的熱修複架構類型

  • ClassLoader:将熱修複的類放在dexElements[]的最前面,這樣加載類時會優先加載到要修複的類以達到修複目的。如騰訊的Tinker、Nuwa等。
  • Native hook:修改java方法在native層的函數指針,指向修複後的方法以達到修複目的。如阿裡的Andifix、DexPosed等。
  • Instant run:在編譯打包階段對每個函數都插入一段控制邏輯代碼。就是今天我們要介紹的Robust實作原理。
  1. 插件化原理分析

主要利用 Java ClassLoader 、反射及動态代理等的原理,如 Android 的 DexClassLoader,可動态加載的内容包括 apk、dex、jar 等。

1.宿主apk和插件apk都是使用PathClassLoader加載,合并宿主和插件的ClassLoader

2.宿主apk資源和插件apk資源是隔離的,重寫Activity的getResources和getAssets

3.Hook IActivityManager.startActivity和ActivityThread.mH.mCallback來騙過AMS對Activity的檢測

  1. 子產品化實作(好處,原因)
  2. 熱修複,插件化
  3. 項目元件化的了解
  4. 描述清點選 Android Studio 的 build 按鈕後發生了什麼
  • 通過aapt打包res資源檔案,生成R.java、resources.arsc和res檔案
  • 處理.aidl檔案,生成對應的Java檔案
  • 通過Java Compoiler編譯R.java、Java接口檔案、Java源檔案,生成.class檔案
  • 通過dex指令,将.class檔案和第三方庫中的.class檔案處理生成classes.dex檔案,dx會将class轉換為Dalvik位元組碼,生成常量池,消除備援資料等
  • 通過apkbuilder工具,将aapt生成的resources.arsc和res檔案、assets檔案和classes.dex一起打包生成apk
  • 通過Jarsigner工具,對上面的apk進行debug或release簽名
  • 通過zipalign工具,将簽名後的apk進行對齊處理。
  1. 統跳協定ARouter實作原理
  • 編譯期:通過注解@Route去掃描所有檔案,生成路由映射檔案(Path和Activity.class),這些檔案都會統一打包到APK裡
  • 運作期:使用路由跳轉之前需要擷取路由映射關系,并儲存到記憶體中。ARouter.init
  • 頁面跳轉:ARouter通過自己存儲的路由表找到路由位址對應的class檔案,然後通過new Intent執行跳轉。

(五)架構設計和設計模式

  1. 談談你對Android設計模式的了解
  2. MVC MVP MVVM原理和差別

MVC: 視圖層(View) 對應于xml布局檔案和java代碼動态view部分 控制層(Controller) MVC中Android的控制層是由Activity來承擔的 模型層(Model) 針對業務模型,建立的資料結構和相關的類,它主要負責網絡請求,資料庫處理,I/O的操作。

問題:因為activity扮演了controller和view的工作,是以controller和view不太好徹底解耦

MVP: Presenter為Model和View之間互動的橋梁。Presenter跟View互相持有 MVP徹底解決了MVC中View和Controller傻傻分不清楚的問題,

但是随着業務邏輯的增加,一個頁面可能會非常複雜,UI的改變是非常多,會有非常多的case,這樣就會造成View的接口會很龐大。

MVVM: 通過雙向綁定的機制,實作資料和UI内容,隻要想改其中一方,另一方都能夠及時更新的一種設計理念,隻需要改變資料就行。 但是由于資料和視圖的雙向綁定,導緻出現問題時不太好定位來源

  1. 你所知道的設計模式有哪些?
  2. 項目中常用的設計模式
  3. 手寫生産者/消費者模式
  4. 寫出觀察者模式的代碼
  5. 擴充卡模式,裝飾者模式,外觀模式的異同?
  6. 用到的一些開源架構,介紹一個看過源碼的,内部實作過程。
  7. 談談對RxJava的了解
  8. RxJava的功能與原理實作
  9. RxJava的作用,與平時使用的異步操作來比的優缺點
  10. 說說EventBus作用,實作方式,代替EventBus的方式
  11. 從0設計一款App整體架構,如何去做?
  12. 說一款你認為目前比較火的應用并設計(比如:直播APP,P2P金融,小視訊等)
  13. 談談對java狀态機了解
  14. Fragment如果在Adapter中使用應該如何解耦?
  15. Binder機制及底層實作
  16. 對于應用更新這塊是如何做的?(解答:灰階,強制更新,分區域更新)?
  17. 實作一個Json解析器(可以通過正則提高速度)
  18. 統計啟動時長,标準

(六)性能優化

  1. 如何對Android 應用進行性能分析以及優化?
  2. ddms 和 traceView
  3. 性能優化如何分析systrace?
  4. 用IDE如何分析記憶體洩漏?
  5. Java多線程引發的性能問題,怎麼解決?
  6. 啟動頁白屏及黑屏解決?
  7. 啟動太慢怎麼解決?
  8. 怎麼保證應用啟動不卡頓?
  9. App啟動崩潰異常捕捉
  10. 自定義View注意事項
  11. 現在下載下傳速度很慢,試從網絡協定的角度分析原因,并優化(提示:網絡的5層都可以涉及)。
  12. Https請求慢的解決辦法(提示:DNS,攜帶資料,直接通路IP)
  13. 如何保持應用的穩定性
  • 提高代碼品質
    • 代碼審查
      • 何時代碼審查?底層公共子產品、重大特性業務、與其他子產品有耦合、新手、應用即将釋出前
      • 誰來審查?團隊審查、子產品負責人審查、結對審查
      • 代碼審查内容
        • 設計思路與設計思想(單一職責原則、開閉原則)
        • 代碼設計(代碼複用、更合理的代碼、潛在的缺陷、錯誤處理、效率)
        • 設計邏輯
        • 代碼風格(命名、方法長度、函數參數個數)
        • 需求了解是否到位
    • 代碼靜态掃描工具
      • CheckStyle:檢查代碼規範和風格
      • FindBugs:可視化UI
      • PMD:主要潛在的Bug、未使用的代碼、重複代碼、循環體建立新對象
      • Android Lint:代碼+布局
  • Crash監控
    • Java層Crash監控 實作UncaughtExceptionHandler接口
    • Native層Crash監控,不能通過UncaughtExceptionHandler捕獲
    • Crash上報
  • ANR剖析
    • ANR類型:(KeyDispatchTimeout輸入5s無響應、BroadcastTimeout 10s、ServiceTimeout 20s)
    • ANR分析
      • ANR IN:發生在ANR的具體類
      • PID:發生ANR的程序
      • Reason:目前ANR類型以及導緻ANR的原因
      • CPU usage:CPU的使用情況,ANR前後兩個時間點的CPU使用情況
    • ANR監控
  • 提高背景程序存活率
  1. RecyclerView和ListView的性能對比
  2. ListView的優化
  3. RecycleView優化
  4. View渲染
  5. Bitmap如何處理大圖,如一張30M的大圖,如何預防OOM
  6. java中的四種引用的差別以及使用場景
  7. 強引用置為null,會不會被回收?

(七)NDK、jni、Binder、AIDL、程序通信有關

  1. 請介紹一下NDK
  2. 什麼是NDK庫?
  3. jni用過嗎?
  4. 如何在jni中注冊native函數,有幾種注冊方式?
  5. Java如何調用c、c++語言?
  6. jni如何調用java層代碼?
  7. 程序間通信的方式?
  8. Binder機制
  9. 簡述IPC?
  10. 什麼是AIDL?
  11. AIDL解決了什麼問題?
  12. AIDL如何使用?
  13. Android 上的 Inter-Process-Communication 跨程序通信時如何工作的?
  14. 多程序場景遇見過麼?
  15. Android程序分類?
  16. 程序和 Application 的生命周期?
  17. 程序排程
  18. 談談對程序共享和線程安全的認識
  19. 談談對多程序開發的了解以及多程序應用場景
  20. 什麼是協程?

(八)framework層、ROM定制、Ubuntu、Linux之類的問題

  1. java虛拟機的特性
  2. 談談對jvm的了解
  3. JVM記憶體區域,開線程影響哪塊記憶體
  4. 對Dalvik、ART虛拟機有什麼了解?
  5. Art和Dalvik對比
  • Dalvik中采用的是jit來做及時翻譯,将dex或odex中并排的dalvik code(或者叫smali指令集)運作态翻譯成native code去執行. 而在ART中,完全抛棄了Dalvik的jit,使用了aot直接在安裝時用dex2oat将其完全翻譯成native code.
  • Dalvik的gc的過程.主要有有四個過程:

    1、當gc被觸發時候,其會去查找所有活動的對象,整個程式與虛拟機内部的所有線程就會挂起,這樣目的是在較少的堆棧裡找到所引用的對象.需要注意的是這個回收動作是和應用程式同時執行(非并發).

    2、gc對符合條件的對象進行标記

    3、gc對标記的對象進行回收

    4、恢複所有線程的執行現場繼續運作

    這麼做的好處是,當pause了之後,gc勢必是相當快速的.但是如果出現gc頻繁并且記憶體吃緊勢必會導緻ui卡頓,掉幀.操作不流暢等.

    ART改善了這種gc方式,主要的改善點在将其非并發過程改變成了部分并發.還有就是對記憶體的重新配置設定管理

    當art gc發生時:

    1、gc将會鎖住java堆,掃描并進行标記

    2、标記完畢釋放掉java堆的鎖,并且挂起所有線程

    3、gc對标記的對象進行回收

    4、恢複所有線程的執行現場繼續運作

    5、重複2-4直到結束

    可以看出整個過程做到了部分并發使得時間縮短.據官方測試資料說gc效率提高2倍

  • dalvik.他的記憶體管理特點是:記憶體碎片化嚴重

    在art中,它将java分了一塊空間命名為Large-Object-Space,這塊記憶體空間的引入用來專門存放large object.同時art又引入了moving collector的技術,即将不連續的實體記憶體塊進行對齊.

  1. 虛拟機原理,如何自己設計一個虛拟機(記憶體管理,類加載,雙親委派)
  2. 談談你對雙親委派模型了解
  3. JVM記憶體模型,記憶體區域
  4. 類加載機制
  5. 談談對ClassLoader(類加載器)的了解
  6. 談談對動态加載(OSGI)的了解
  7. 記憶體對象的循環引用及避免
  8. 記憶體回收機制、GC回收政策、GC原理時機以及GC對象
  9. 垃圾回收機制與調用System.gc()差別
  10. Ubuntu編譯安卓系統
  11. 系統啟動流程是什麼?(提示:Zygote程序 –> SystemServer程序 –> 各種系統服務 –> 應用程序)
  12. 大體說清一個應用程式安裝到手機上時發生了什麼
  13. 簡述Activity啟動全部過程
  14. App啟動流程,從點選桌面開始
  15. 邏輯位址與實體位址,為什麼使用邏輯位址?
  16. Android為每個應用程式配置設定的記憶體大小是多少?
  17. Android中程序記憶體的配置設定,能不能自己配置設定定額記憶體?
  18. 程序保活的方式
  19. 如何保證一個背景服務不被殺死?(相同問題:如何保證service在背景不被kill?)比較省電的方式是什麼?
  20. App中喚醒其他程序的實作方式

(九)算法

  1. 排序算法有哪些?
  2. 最快的排序算法是哪個?
  3. 手寫一個冒泡排序
  4. 手寫快速排序代碼
  5. 快速排序的過程、時間複雜度、空間複雜度
  6. 手寫堆排序
  7. 堆排序過程、時間複雜度及空間複雜度
  8. 寫出你所知道的排序算法及時空複雜度,穩定性
  9. 二叉樹給出根節點和目标節點,找出從根節點到目标節點的路徑
  10. 給阿裡2萬多名員工按年齡排序應該選擇哪個算法?
  11. GC算法(各種算法的優缺點以及應用場景)
  12. 蟻群算法與蒙特卡洛算法
  13. 子串包含問題(KMP 算法)寫代碼實作
  14. 一個無序,不重複數組,輸出N個元素,使得N個元素的和相加為M,給出時間複雜度、空間複雜度。手寫算法
  15. 萬億級别的兩個URL檔案A和B,如何求出A和B的差集C(提示:Bit映射->hash分組->多檔案讀寫效率->磁盤尋址以及應用層面對尋址的優化)
  16. 百度POI中如何試下查找最近的商家功能(提示:坐标鏡像+R樹)。
  17. 兩個不重複的數組集合中,求共同的元素。
  18. 兩個不重複的數組集合中,這兩個集合都是海量資料,記憶體中放不下,怎麼求共同的元素?
  19. 一個檔案中有100萬個整數,由空格分開,在程式中判斷使用者輸入的整數是否在此檔案中。說出最優的方法
  20. 一張Bitmap所占記憶體以及記憶體占用的計算
  21. 2000萬個整數,找出第五十大的數字?
  22. 燒一根不均勻的繩,從頭燒到尾總共需要1個小時。現在有若幹條材質相同的繩子,問如何用燒繩的方法來計時一個小時十五分鐘呢?
  23. 求1000以内的水仙花數以及40億以内的水仙花數
  24. 5枚硬币,2正3反如何劃分為兩堆然後通過翻轉讓兩堆中正面向上的硬8币和反面向上的硬币個數相同
  25. 時針走一圈,時針分針重合幾次
  26. N*N的方格紙,裡面有多少個正方形
  27. x個蘋果,一天隻能吃一個、兩個、或者三個,問多少天可以吃完?

(十)其他

  1. 在上家公司的技術成長?
  2. 做過最有成就感?有技術難度的點?
  3. 項目架構是怎麼設計的?
  4. Glide原理
  5. OkHttp、Retrofit
  • Retrofit主要負責應用層面的封裝,就是說主要面向開發者,友善使用,比如請求參數,響應資料的處理,錯誤處理等等。
  • OkHttp主要負責socket部分的優化,比如多路複用,buffer緩存,資料壓縮等等 封裝不同:
  • Retrofit封裝了具體的請求,線程切換以及資料轉換。
  • OkHttp 是基于Http協定封裝的一套請求用戶端,雖然它也可以開線程,但根本上它更偏向真正的請求,跟HttpClient, HttpUrlConnection的職責是一樣的。

另外,網上一般都推薦RxJava+Retrofit+OkHttp架構,Retrofit負責請求的資料和請求的結果,使用接口的方式呈現,OkHttp負責請求的過程,RxJava負責異步,各種線程之間的切換,用起來炒雞爽。

  1. 熱修複原理
  2. 日志回撈原理
  3. HttpDNS原理
  4. AOP