2020Android面試學(xué)習(xí)

Java String 有多長?

2個方面 
棧   String longString = "aaaa....aaaa";  字節(jié)數(shù)65535炊琉,字節(jié)碼的格式是UTF8
實際是65534苔咪,javac源碼 length<65535
kotlin是65535
String longString = "叁叁肆那";
一個漢字占3個字節(jié),漢字個數(shù)65535/3悼泌,是沒問題的
源碼 length>65535
主要受字節(jié)碼影響松捉,Latin是65534,非Latin是65535
也會方法區(qū)大小限制

堆      byte[] bytes = loadFromFile("test.txt");
        String string = new String(bytes);
通過new出String的對象馆里,理論上最大長度是 Integer.MAX_VALUE
Java虛擬機指令newarray的限制
ArrayList的源碼中
Some VM reserve some header words in an array
最大長度是 Integer.MAX_VALUE - 8
也會受到堆內(nèi)存大小的限制

匿名內(nèi)部類

匿名內(nèi)部類名字是 包名+$1 $2
編譯器生成
為什么可以new 匿名內(nèi)部類
子類可以訪問父類的構(gòu)造方法

泛型

類型擦除 從編譯的細節(jié)
類型擦除 對運行時的影響
類型擦除 對反射的影響
對比類型不擦除的語言
為什么java選擇類型擦除?
類型擦除的好處?
運行時內(nèi)存負擔小
兼容性好       1.5之后才有泛型
類型擦除的問題?
基本類型無法作為泛型實參 所以需要裝箱和拆箱 開銷比較大
泛型類型無法用作方法重載
泛型類型無法當做真實類型使用 編譯之后被擦除了,T都是object
靜態(tài)方法無法引用泛型參數(shù) 泛型參數(shù)只有類實例化之后才知道隘世,所以static方法不知道
類型強轉(zhuǎn)運行時開銷  需要強轉(zhuǎn) 編譯時擦除泛型
泛型簽名
泛型簽名.png

獲取泛型


獲取泛型.png

獲取泛型實例.png
kotlin反射.png

onActivityResult使用很麻煩,為什么不設(shè)計成回調(diào)

B回到A鸠踪,A會被銷毀,會重新創(chuàng)建對象的實例,所以回調(diào)不能使用
解決方案:
  activity嵌套fragment,用fragment里的onActivityrResult里的引用丰捷。因為fragment在activity創(chuàng)建之后生成,所以拿到fragment里新的對象實例少漆,fragment持有的對象的activity检访,必然是新的卖氨。
唯一性五嫂,view的唯一可以是id孩灯,通過findviewbyId獲取
fragment的唯一性可以考mWho掀亩,通過反射拿到 

如何停止一個線程

線程stop已經(jīng)被廢棄
線程不能直接停止炼七,讀寫操作容易crash,資源不能清理枝誊;也不能暫停皮壁,一直占用cpu,其它線程會一直等待。
但是任務(wù)可以停止
Interrupt
volatitle Boolean標志位

如何寫出線程安全的程序

什么是線程安全?
可變資源(內(nèi)存)線程間共享
解決方案:
不共享資源  重入函數(shù)  threadLocal(final 避免存儲大量對象 用完之后及時移除對象)
禁止重排序 final(定義的變量不可以被修改 方法绘闷,類不可被復(fù)寫,繼承)volatile(可見性)
保證可見性 fina volatile 加鎖(鎖釋放會強制將緩存刷新到主內(nèi)存)
保證原子性(簡單理解 運行步驟不可拆分 +運算可被拆分成3個步驟,所以不具有原子性)
保證原子性的方法:
加鎖,保證操作的互斥性
使用CAS指令(如Unsafe.compareAndSwapInt)
使用原子數(shù)值類型(如AtomicInteger)
使用原子屬性更新器(如AtomicReferenceFiledUpdater)

ConcurrentHashMap如何實現(xiàn)并發(fā)訪問

ConcurrentHashMap 類中包含兩個靜態(tài)內(nèi)部類 HashEntry 和 Segment侦鹏。HashEntry 用來封裝映射表的鍵 / 值對跨释;Segment 用來充當鎖的角色,每個 Segment 對象守護整個散列映射表的若干個桶它碎。每個桶是由若干個 HashEntry 對象鏈接起來的鏈表套腹。一個 ConcurrentHashMap 實例中包含由若干個 Segment 對象組成的數(shù)組

優(yōu)化so包

動態(tài)下發(fā)so包
image.png
image.png

捕獲Native異常

old_singalhandlers.png

android_singal_handler.png

JNIEnvHelper.png

Activity的啟動流程

Activity跨進程啟動.png

如何跨App啟動Activity

uid   exported intentFilter  拒接服務(wù)漏洞
uid.png

ComponentName.png
exported.png

intentFilter.png
Activity加權(quán)限.png

Handler

post為什么能切換主線程?
調(diào)用主線程的handler,thread run()方法
threadLocal是什么?
是map,ThreadLocalMap,key是線程名.currentThread
threadLocal是全局唯一的,泛型是looper,Looper是全局唯一的,不能new,只有Looper.prepare()保證唯一
一個線程只綁定一個looper,一個looper只綁定一個mQueue


post,sendMessage,sendEmptyMessageAtTime最終都調(diào)用enqueueMessage
發(fā)送消息
handler.sendMessage(msg),enqueueMessage壓入消息隊列 max_pool_size=50
取消息
Looper.loop()輪詢器 , msg.target.dispatchMessage,msg.target是handler

Looper.loop()為什么不會ANR?
Binder.clearCallingIdentity() native方法
在for循環(huán)中,Trace.traceBegin(traceTag,msg.target.getTraceName(msg))調(diào)用nativeTraceBegin native方法
調(diào)用2個native方法回收釋放

消息隊列優(yōu)化
枚舉類型  復(fù)用  重復(fù)消息過濾  互斥消息取消
image.png
image.png
image.png

如何避免OOM

使用合適的數(shù)據(jù)結(jié)構(gòu)
內(nèi)存復(fù)用 建立一個內(nèi)存池 Message pool
避免使用枚舉 對象 24Bytes
Bitmap 合適分辨率 放在合適的目錄(mdpi)bitmap的重采樣和復(fù)用配置
謹慎使用多進程  預(yù)加載一些配置和資源
使用合適的數(shù)據(jù)結(jié)構(gòu).png
5R法則.png

對圖片進行緩存

網(wǎng)絡(luò)/磁盤/內(nèi)存
LRU 最近最少使用 LinkeHashMap 線程安全synchronized 將被訪問的元素移到鏈表尾部,迭代器訪問第一個元素最老
LFU 頻率使用最多的

image.png

圖片占用內(nèi)存的大小

jpg 用RGB_565 沒有透明通道
使用inSampleize采樣 大圖->小圖
使用矩陣變換來放大圖片 小圖->大圖
使用.9圖圖做背景
不使用圖片 優(yōu)先使用VectorDrawable

Binder

image.png

AIDL Android Interface Definition Language Android接口定義語言
打開binder   driver="/dev/binder"   
buffer創(chuàng)建    binder_open(driver,128*1024)
開辟內(nèi)存映射  128kmmap
ServiceMananger啟動
打包Parcel中,數(shù)據(jù)寫入binder設(shè)備 writeTransactionData , copy_from_user
服務(wù)注冊,添加到鏈表svclist中
定義主線程中的線程池
循環(huán)從mIn和mOut中取出讀寫請求 buffer是256字節(jié),發(fā)到binder設(shè)備中       

案列:三方登錄
client 創(chuàng)建AIDL,定義接口方法(與server同一包名),創(chuàng)建service,用于service端回調(diào)通信
server 創(chuàng)建AIDL,定義接口方法(與client同一包名),創(chuàng)建service,用于接收client端發(fā)送的消息
client  serviceManager  server


image.png

image.png

PackageManagerService
http://www.reibang.com/p/cb0555d62b9c

在Systemserver中啟動
ApplicationPackageManager  IPackageManager(mPM)  AIDL
image.png

安裝

有界面安裝
PackageInstallerActivity  PackageUtil.getPackageInfo(sourceFile)  startInstall() InstallAppProgress.class(通過handler broadcastReceiver 回調(diào)消息)
無界面安裝 
調(diào)用C adb_commandline(buff4096)  install_app(獲取手機內(nèi)部存儲路徑 sd卡存儲路徑) 通過shell:pm PackageManagerService handler發(fā)送消息 默認安裝4次,4次不成功即失敗
image.png

無界面安裝 .png


image.png

image.png

image.png

ActivityManagerService

image.png

image.png

調(diào)用2次binder機制 App進程->系統(tǒng)進程->App進程
源碼分析.png

App啟動流程

image.png

image.png

換膚

思路
1.
 替換textcolor 和 background
自定義Textview Button Imageview LinearLayout
重寫AppCompatViewInflater
在onCreate中重寫Factory2
系統(tǒng)API UIMode判斷是白天黑夜
2.
將resource打包apk
反射獲取AssetManager,new resource,加載path拜英,拿到皮膚包的包名
apk內(nèi)resources.arsc映射文件盛垦,資源name必須一一對應(yīng)湿弦,通過資源id叉跛,獲取name柒傻,type

資源加載流程.png

image.png

image.png

image.png

image.png

image.png

image.png

插件化

Hook
類加載  createClassLoader
資源加載 AssetManager
四大組件  activity hook Intent service hook AMP 動態(tài)代理 
廣播 解析插件Manifest 將靜態(tài)廣播轉(zhuǎn)成動態(tài) 毕赐遥活只能在宿主中

shadow
靜態(tài)代理
image.png

Tinker熱修復(fù)

代碼 dexDiff算法
資源 Entry的BSDiff
46831行代碼
算法機制
old new 先根據(jù)索引排序冒窍,只要old < new delete = replace  > add 

1.獲取系統(tǒng)的classLoader pathList
2.構(gòu)造dexElements
3.將補丁dex注入到系統(tǒng)dexElements的最前面

sp原理 mmkv

ArrayMap  ConcurrentHashMap分段加鎖
2級緩存 磁盤 內(nèi)存
讀數(shù)據(jù)會阻塞 加鎖
commit會阻塞 apply開啟線程異步

MMKV 是基于 mmap 內(nèi)存映射的 key-value 組件遏匆,底層序列化/反序列化使用 protobuf 實現(xiàn)瘦馍,性能高洞豁,穩(wěn)定性強犀变。
內(nèi)存準備
通過 mmap 內(nèi)存映射文件榨呆,提供一段可供隨時寫入的內(nèi)存塊罗标,App 只管往里面寫數(shù)據(jù),由操作系統(tǒng)負責(zé)將內(nèi)存回寫到文件积蜻,不必擔心 crash 導(dǎo)致數(shù)據(jù)丟失闯割。
數(shù)據(jù)組織
數(shù)據(jù)序列化方面我們選用 protobuf 協(xié)議,pb 在性能和空間占用上都有不錯的表現(xiàn)竿拆。
寫入優(yōu)化
考慮到主要使用場景是頻繁地進行寫入更新宙拉,我們需要有增量更新的能力。我們考慮將增量 kv 對象序列化后丙笋,append 到內(nèi)存末尾谢澈。
空間增長
使用 append 實現(xiàn)增量更新帶來了一個新的問題,就是不斷 append 的話御板,文件大小會增長得不可控锥忿。我們需要在性能和空間上做個折中。

socket TCP UDP

TCP socket 
 ServerSocket  accept()  阻塞 inputstream
 ClientSocket  IP 端口號 outputstream  
流的方式發(fā)送
UDP socket
DatagramSocket receive()  阻塞
ClientSocket  InetAddress IP 端口號 send
包的方式發(fā)送 最大長度 65535-8
UDP 不可靠 是服務(wù)端抓取數(shù)據(jù)
單播 廣播 多播

Https為什么安全

加密 TLS
對身份進行驗證 證書

kotlin協(xié)程

協(xié)程就是個線程框架
協(xié)程的掛起本質(zhì)就是線程切出去再切回來
是輕量級的線程怠肋,解決并發(fā)問題
CoroutineScope創(chuàng)建協(xié)程
coroutineScope.launch(Dispatchers.IO) {
    ...
}
withContext 這個函數(shù)可以切換到指定的線程敬鬓,并在閉包內(nèi)的邏輯執(zhí)行結(jié)束之后,自動把線程切回去繼續(xù)執(zhí)行 消除了并發(fā)代碼在協(xié)作時的嵌套

suspend 『掛起』是非阻塞式的 掛起的對象是協(xié)程 只是一個提醒 我是一個耗時函數(shù),我被我的創(chuàng)建者用掛起的方式放在后臺運行列林,所以請在協(xié)程里調(diào)用我
什么是掛起瑞你?掛起,就是一個稍后會被自動切回來的線程調(diào)度操作
啟動一個協(xié)程可以使用 launch 或者 async 函數(shù)希痴,協(xié)程其實就是這兩個函數(shù)中閉包的代碼塊者甲。

kotlin inline

減少方法壓棧,出棧,進而減少資源消耗
也就是說inline關(guān)鍵字實際上增加了代碼量,但是提升了性能砌创,而且增加的代碼量是在編譯期執(zhí)行的虏缸,對程序可讀性不會造成影響

APT javapont

注解目標是在類 方法 參數(shù)
編譯期 運行時
extends AbstractProessor

內(nèi)存抖動

循環(huán) 頻繁調(diào)用導(dǎo)致GC頻繁
自我介紹
您好,我叫湯文斌嫩实,在上家公司擔任Android leader 刽辙,帶領(lǐng)3人團隊,負責(zé)公司5個項目甲献,3個已經(jīng)上線宰缤,2個是公司內(nèi)部項目。上線的項目平均日活在1w左右晃洒,崩潰率維持在1%慨灭。主要負責(zé)產(chǎn)品和前后端溝通,架構(gòu)搭建和技術(shù)選型球及,以及新技術(shù)的布道氧骤。

APP瘦身優(yōu)化

代碼優(yōu)化   混淆 第三方庫 移除無用代碼
資源優(yōu)化   混淆 壓縮 刪除冗余資源 
so優(yōu)化      只用arm包,最小

列表卡頓優(yōu)化

布局 不要嵌套
圖片 不要太大 滑動取消加載
線程  使用線程池

jetpack

lifecycle 解決代碼入侵 解決內(nèi)存泄漏 解決統(tǒng)一管理
liveData和lifecycle綁定 可以感應(yīng)生命周期 不會崩潰
viewmodel 管理數(shù)據(jù) 重建不丟失

GC

可達性分析吃引,尋找GCRoot
GCRoot對象  Java虛擬機棧 方法區(qū) 活躍的 Native 引用的對象存在
堆內(nèi)存分配不足  systen.gc()

classLoader 雙親委派模式

先找父類筹陵,父類找不到自身才會執(zhí)行實際的類加載過程
自定義classLoader 重寫findClass 調(diào)用defineClass方法將字節(jié)碼轉(zhuǎn)成Class對象
Android中classLoader PathClassLoader DexClassLoader
PathClassLoader用來加載系統(tǒng)apk和被安裝到手機的apk內(nèi)的dex文件
DexClassLoader可以從SD卡上加載包含class.dex的.jar和.apk文件

LeakCanary原理

weakReference  ReferenceQueue
頁面需要被回收,就將其包裝到weakReference中镊尺,并且在weakReference的構(gòu)造器中傳入自定義的ReferenceQueue
將包裝的weakReference做一個標記key朦佩,并且在一個強引用Set中添加相應(yīng)的key記錄
主動觸發(fā)GC,遍歷ReferenceQueue鹅心,刪除對應(yīng)的Set記錄
如果Set中依然有對象吕粗,則內(nèi)存泄漏
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纺荧,一起剝皮案震驚了整個濱河市旭愧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宙暇,老刑警劉巖输枯,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件占贫,死亡現(xiàn)場離奇詭異桃熄,居然都是意外死亡,警方通過查閱死者的電腦和手機型奥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門瞳收,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碉京,“玉大人,你說我怎么就攤上這事螟深⌒持妫” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵界弧,是天一觀的道長凡蜻。 經(jīng)常有香客問我,道長垢箕,這世上最難降的妖魔是什么划栓? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮条获,結(jié)果婚禮上忠荞,老公的妹妹穿的比我還像新娘。我一直安慰自己帅掘,他們只是感情好钻洒,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著锄开,像睡著了一般素标。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上萍悴,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天头遭,我揣著相機與錄音,去河邊找鬼癣诱。 笑死计维,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的撕予。 我是一名探鬼主播鲫惶,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼实抡!你這毒婦竟也來了欠母?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤吆寨,失蹤者是張志新(化名)和其女友劉穎赏淌,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體啄清,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡六水,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掷贾。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡睛榄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出想帅,到底是詐尸還是另有隱情懈费,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布博脑,位于F島的核電站憎乙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏叉趣。R本人自食惡果不足惜泞边,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望疗杉。 院中可真熱鬧阵谚,春花似錦、人聲如沸烟具。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽朝聋。三九已至嗡午,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冀痕,已是汗流浹背荔睹。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留言蛇,地道東北人僻他。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像腊尚,于是被迫代替她去往敵國和親吨拗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容