記錄之前一次面試。
先說一下面試問到的需要的點:tcp/udp.volatile關鍵字.多進程.hashmap.anr.activity.MVP.算法題.自定義view.OKHTTP.java相關.數據結構.性能優化.
爲此我整理了一份983頁的PDF,把自己平時收集的面試題,和平時工作中碰到的都融合進去了
(更多完整項目下載。未完待續。源碼。圖文知識後續上傳github。)
可以點擊關於我聯繫我獲取完整PDF
(VX:mm14525201314)
- 自定義view的過程
- java線程,安卓線程池
- handle
- gc,gc的使用方式
- okhttp源碼
- 設計模式
- hashmap源碼
- 線程安全性
- hash運算過程
- java相關(面向對象的理解 多態的實習 接口和抽象類 內存模型 多線程 線程池原理)
- 性能優化相關
問到的問題中,還是性能優化相關的對我的印象比較深刻,所以着重講一下(答案僅供參考)
1、圖片的三級緩存中,圖片加載到內存中,如果內存快爆了,會發生什麼?怎麼處理
首先我們要清楚圖片的三級緩存是如何的
如果內存足夠時不回收。內存不夠時就回收軟引用對象
2、內存中如果加載一張 500*500 的 png 高清圖片.應該是佔用多少的內存?
- 不考慮屏幕比的話: 佔用內存=500 500 4 = 1000000B ≈
0.95MB - 考慮屏幕比的的話: 佔用內存= 寬度像素 x (
inTargetDensity
/inDensity
) x 高度像素 x(inTargetDensity
/inDensity
)x 一個像素所佔的內存字節
大小 - inDensity 表示目標圖片的 dpi(放在哪個資源文件夾下),
inTargetDensity
表示目標屏幕的 dpi
3、WebView 的性能優化 ?
一個加載網頁的過程中,native、網絡、後端處理、CPU 都會
參與,各自都有必要的工作和依賴關係;讓他們相互並行處理
而不是相互阻塞纔可以讓網頁加載更快: - WebView 初始化慢,可以在初始化同時先請求數據,
讓後端和網絡不要閒着。 - 常用 JS 本地化及延遲加載,使用第三方瀏覽內核
- 後端處理慢,可以讓服務器分 trunk 輸出,在後端計算
的同時前端也加載網絡靜態資源。 - 腳本執行慢,就讓腳本在最後運行,不阻塞頁面解析。
- 同時,合理的預加載、預緩存可以讓加載速度的瓶頸更
小。 - WebView 初始化慢,就隨時初始化好一個 WebView
待用。 - DNS 和鏈接慢,想辦法複用客戶端使用的域名和鏈接。
4、Bitmap 如何處理大圖,如一張 30M 的大圖,如何預防 OOM?
參考回答: 避免 OOM 的問題就需要對大圖片的加載進行管理,主要通
過縮放來減小圖片的內存佔用。 BitmapFactory
提供的加載圖片的四類方法(decodeFile
、decodeResource
、decodeStream
、decodeByteArray
)
都支持BitmapFactory.Options
參數,通過inSampleSize
參
數就可以很方便地對一個圖片進行採樣縮放- 比如一張 10241024 的高清圖片來說。那麼它佔有的內存爲
102410244,即 4MB,如果 inSampleSize 爲 2,那麼採樣後
的圖片佔用內存只有 512512*4,即 1MB(注意:根據最新的官
方文檔指出,inSampleSize
的取值應該總是爲 2 的指數,即
1、2、4、8 等等,如果外界輸入不足爲 2 的指數,系統也會默
認選擇最接近 2 的指數代替,比如 2) - 綜合考慮。通過採樣率即可有效加載圖片,流程如下
- 將
BitmapFactory.Options
的inJustDecodeBounds
參數設爲 true 並加載圖片 - 從
BitmapFactory.Options
中取出圖片的原始寬高信
息,它們對應 outWidth 和 outHeight 參數 - 根據採樣率的規則並結合目標 View 的所需大小計算出
採樣率inSampleSize
- 將
BitmapFactory.Options
的inJustDecodeBounds
參數設爲 false,重新加載圖片
- 將
5、內存回收機制與 GC 算法(各種算法的優缺點以及應用場景);GC 原理時機以及 GC 對象
參考回答:
內存判定對象可回收有兩種機制:
-
引用計數算法: 給對象中添加一個引用計數器,每當有
一個地方引用它時,計數器值就加 1;當引用失效時,
計數器值就減 1;任何時刻計數器爲 0 的對象就是不可
能再被使用的。然而在主流的 Java 虛擬機裏未選用引用
計數算法來管理內存,主要原因是它難以解決對象之間相互循環引用的問題,所以出現了另一種對象存活判定
算法。 - 可達性分析法: 通過一系列被稱爲『GCRoots』的對象
作爲起始點,從這些節點開始向下搜索,搜索所走過的
路徑稱爲引用鏈,當一個對象到 GC Roots 沒有任何引
用鏈相連時,則證明此對象是不可用的。其中可作爲 GC
Roots 的對象:虛擬機棧中引用的對象,主要是指棧幀
中的本地變量*、本地方法棧中 Native 方法引用的對
象、方法區中類靜態屬性引用的對象、方法區中常量引
用的對象
GC 回收算法有以下四種:
- 分代收集算法: 是當前商業虛擬機都採用的一種算法,
根據對象存活週期的不同,將 Java 堆劃分爲新生代和老
年代,並根據各個年代的特點採用最適當的收集算法。 - 新生代: 大批對象死去,只有少量存活。使用『複製算
法』,只需複製少量存活對象即可。- 複製算法: 把可用內存按容量劃分爲大小相等的
兩塊,每次只使用其中的一塊。當這一塊的內存
用盡後,把還存活着的對象『複製』到另外一塊
上面,再將這一塊內存空間一次清理掉。實現簡單,運行高效。在對象存活率較高時就要進行較多的複製操作,效率將會變低
- 複製算法: 把可用內存按容量劃分爲大小相等的
- 老年代: 對象存活率高。使用『標記—清理算法』或者
『標記—整理算法』,只需標記較少的回收對象即可。- 標記-清除算法: 首先『標記』出所有需要回收
的對象,然後統一『清除』所有被標記的對象。
標記和清除兩個過程的效率都不高,清除之後會
產生大量不連續的內存碎片,空間碎片太多可能
會導致以後在程序運行過程中需要分配較大對象
時,無法找到足夠的連續內存而不得不提前觸發
另一次垃圾收集動作。 - 標記-整理算法: 首先『標記』出所有需要回收
的對象,然後進行『整理』,使得存活的對象都
向一端移動,最後直接清理掉端邊界以外的內
存。標記整理算法會將所有的存活對象移動到一
端,並對不存活對象進行處理,因此其不會產生
內存碎片6、內存泄露和內存溢出的區別 ?AS 有什麼工具可以檢測內存泄露
- 標記-清除算法: 首先『標記』出所有需要回收
- 內存溢出(out of memory): 是指程序在申請內存時,沒有足
夠的內存空間供其使用,出現 out of memory;比如申請了一
個 integer,但給它存了 long 才能存下的數,那就是內存溢
出。 - 內存泄露(memory leak): 是指程序在申請內存後,無法釋放
已申請的內存空間,一次內存泄露危害可以忽略,但內存泄露
堆積後果很嚴重,無論多少內存,遲早會被佔光。memory leak
會最終會導致 out of memory! - 查找內存泄漏可以使用 Android Studio 自帶的
AndroidProfiler
工具或 MAT
7、性能優化,怎麼保證應用啓動不卡頓? 黑白屏怎麼處理?
- 應用啓動速度,取決於你在 application 裏面時候做了什麼事
情,比如你集成了很多 sdk,並且 sdk 的 init 操作都需要在主
線程裏實現所以會有卡頓的感覺。在非必要的情況下可以把加
載延後或則開啓子線程處理 -
另外,影響界面卡頓的兩大因素,分別是界面繪製和數據處
理。- 佈局優化(使用 include,merge 標籤,複雜佈局推薦使
用ConstraintLayout
等) onCreate()
中不執行耗時操作 把頁面顯示的 View 細
分一下,放在AsyncTask
裏逐步顯示,用Handler
更好。這樣用戶的看到的就是有層次有步驟的一個個的
View 的展示,不會是先看到一個黑屏,然後一下顯示
所有 View。最好做成動畫,效果更自然。- 利用多線程的目的就是儘可能的減少
onCreate()
和onReume()
的時間,使得用戶能儘快看到頁面,操作
頁面。 - 減少主線程阻塞時間。
- 提高 Adapter 和
AdapterView
的效率。
- 佈局優化(使用 include,merge 標籤,複雜佈局推薦使
- 黑白屏產生原因: 當我們在啓動一個應用時,系統會去檢查是
否已經存在這樣一個進程,如果不存在,系統的服務會先檢查startActivity
中的 intent 的信息,然後在去創建進程,最後啓
動Acitivy
,即冷啓動。而啓動出現白黑屏的問題,就是在這段
時間內產生的。系統在繪製頁面加載佈局之前,首先會初始化
窗口(Window),而在進行這一步操作時,系統會根據我們設
置的 Theme 來指定它的 Theme 主題顏色,我們在 Style 中的
設置就決定了顯示的是白屏還是黑屏。windowIsTranslucent
和windowNoTitle
,將這兩個
屬性都設置成 true (會有明顯的卡頓體驗,不推薦)- 如果啓動頁只是是一張圖片,那麼爲啓動頁專一設置一
個新的主題,設置主題的android:windowBackground
屬性爲啓動頁背景圖即
可
- 使用 layer-list 製作一張圖片 launcher_layer.xml,將其
設置爲啓動頁專一主題的背景,並將其設置爲啓動頁布
局的背景。8、強引用置爲 null,會不會被回收?
不會立即釋放對象佔用的內存。 如果對象的引用被置爲 null,
只是斷開了當前線程棧幀中對該對象的引用關係,而 垃圾收集
器是運行在後臺的線程,只有當用戶線程運行到安全點(safe
point)或者安全區域纔會掃描對象引用關係,掃描到對象沒有被
引用則會標記對象,這時候仍然不會立即釋放該對象內存,因
爲有些對象是可恢復的(在 finalize 方法中恢復引用 )。只有
確定了對象無法恢復引用的時候纔會清除對象內存。
9、ListView 跟 RecyclerView 的區別
動畫區別:
- 在
RecyclerView
中,內置有許多動畫 API,例如:notifyItemChanged()
,notifyDataInserted()
,notifyItemMoved()
等等;如果需要自定義動畫效果,
可以通過實現(RecyclerView.ItemAnimator
類)完成
自定義動畫效果,然後調用RecyclerView.setItemAnimator();
- 但是
ListView
並沒有實現動畫效果,但我們可以在
Adapter 自己實現 item 的動畫效果;
刷新區別:
ListView
中通常刷新數據是用全局刷新notifyDataSetChanged()
,這樣一來就會非常消耗資
源;本身無法實現局部刷新,但是如果要在 ListView 實 現局部刷新,依然是可以實現的,當一個 item 數據刷新
時,我們可以在 Adapter 中,實現一個onItemChanged()
方法,在方法裏面獲取到這個 item
的 position(可以通過getFirstVisiblePosition()
),然
後調用getView()
方法來刷新這個 item 的數據;RecyclerView
中可以實現局部刷新,例如:notifyItemChanged();
緩存區別:
RecyclerView
比ListView
多兩級緩存,支持多個離ItemView
緩存,支持開發者自定義緩存處理邏輯,支
持所有RecyclerView
共用同一個RecyclerViewPool
(緩存池)。ListView
和RecyclerView
緩存機制基本一致,但緩存
使用不同
10、ListView 的 adapter 是什麼 adapter
BaseAdapter
:抽象類,實際開發中我們會繼承這個類並且重
寫相關方法,用得最多的一個適配器!ArrayAdapter
:支持泛型操作,最簡單的一個適配器,只能展
現一行文字〜SimpleAdapter
:同樣具有良好擴展性的一個適配器,可以自
定義多種效果!SimpleCursorAdapter
:用於顯示簡單文本類型的listView
,
一般在數據庫那裏會用到,不過有點過時,不推薦使用!
11、LinearLayout、FrameLayout、RelativeLayout 性能對比,爲什麼?
RelativeLayout
會讓子 View 調用 2 次onMeasure
,LinearLayout
在有 weight 時,也會調用子 View 2 次onMeasure
RelativeLayout
的子 View 如果高度和RelativeLayout
不同,
則會引發效率問題,當子 View 很複雜時,這個問題會更加嚴
重。如果可以,儘量使用 padding 代替 margin。 o 在不影響層級深度的情況下,使用LinearLayout
和FrameLayout
而不是RelativeLayout
。
請查看完整的PDF版
(更多完整項目下載。未完待續。源碼。圖文知識後續上傳github。)
可以點擊關於我聯繫我獲取完整PDF
(VX:mm14525201314)