Android

自我介紹
項(xiàng)目經(jīng)歷,重點(diǎn)介紹工作經(jīng)歷和內(nèi)容

Android基礎(chǔ)

4種啟動(dòng)模式和應(yīng)用場(chǎng);Service啟動(dòng)方式
Activity和Fragment如何通信?

ViewModel; 接口回調(diào);getActivity()和FragmentManager
Android和H5如何通信?
android調(diào)用js: webview.loadurl()
js調(diào)用android: addJavascriptInterface()

Service如何增加權(quán)限

IPC進(jìn)程間通信

Binder

Binder意外死亡了?
1.給Binder設(shè)置DeathRecipient監(jiān)聽(tīng),當(dāng)Binder死亡時(shí),我們會(huì)收到binderDied方法的回調(diào),在binderDied方法中我們可以重連遠(yuǎn)程服務(wù)
2.在onServiceDisconnected中重連遠(yuǎn)程服務(wù)

Bundle,共享內(nèi)存
Messenger

底層實(shí)現(xiàn)是AIDL
服務(wù)端進(jìn)程:創(chuàng)建一個(gè)Service來(lái)處理客戶(hù)端的連接請(qǐng)求,創(chuàng)建一個(gè)Handler并通過(guò)它來(lái)創(chuàng)建一個(gè)Messenger對(duì)象,然后在Service的onBind中返回這個(gè)Messenger對(duì)象底層Binder即可
客戶(hù)端進(jìn)程:綁定服務(wù)端的Service,綁定成功后用服務(wù)端的IBinder對(duì)象創(chuàng)建一個(gè)Messenger,通過(guò)這個(gè)Messenger就可以向服務(wù)端發(fā)送消息了,發(fā)消息類(lèi)型為Message對(duì)象

AIDL, Socket,
ContentProvider

ContentProvider是Android中提供的專(zhuān)門(mén)用于不同應(yīng)用間進(jìn)行數(shù)據(jù)共享的方式,底層實(shí)現(xiàn)同樣也是Binder; onCreate運(yùn)行在main線(xiàn)程中,query,update,insert和delete方法運(yùn)行在Binder線(xiàn)程中; android:authorities是Content Provider的唯一標(biāo)識(shí),通過(guò)這個(gè)屬性外部應(yīng)用就可以訪(fǎng)問(wèn)我們的ContentProvider;

線(xiàn)程間通信Handler

1.Handler工作機(jī)制
2.一個(gè)線(xiàn)程有幾個(gè)handler,looper,如何區(qū)分不同handler發(fā)送的消息(榮耀負(fù)一屏面試題)
3.Handler如何讓子線(xiàn)程和子線(xiàn)程通信? Looper#prepare(); Looper#loop()
4.Handler導(dǎo)致的內(nèi)存泄漏如何分析解決?
5.為什么Android刷新UI只能在主線(xiàn)程?
因?yàn)锳ndroid的UI控件不是線(xiàn)程安全的,如果在多線(xiàn)程中并發(fā)訪(fǎng)問(wèn)可能會(huì)導(dǎo)致UI控件處于不可預(yù)期的狀態(tài)
6.子線(xiàn)程可以刷新UI嗎?

其實(shí)是可以的,比如在Activity#onCreate方法里,在ViewRootImpl創(chuàng)建之前可以在子線(xiàn)程中操作UI;
ViewRootImpl是在Activity#onResume流程里創(chuàng)建,通過(guò)WindowManager.addView->WindowManagerImpl#addView->WindowManagerGlobal#addView->new ViewRootImpl
如果在子線(xiàn)程進(jìn)行UI操作,ViewRootImpl#checkThread會(huì)拋出一個(gè)異常,only the original thread that creates a view hierarchy can touch its view只有創(chuàng)建View層級(jí)的線(xiàn)程才能操作UI

自定義View

自定義下載進(jìn)度按鈕
繪制背景圓形矩形,繪制進(jìn)度,繪制文字,加入動(dòng)畫(huà)ValueAnimator,執(zhí)行View.invalidate方法
自定義View,兩行左對(duì)齊,一行中間對(duì)齊(華為車(chē)載面試)

View的事件體系

View的滑動(dòng);

使用scrollTo/scrollBy;使用動(dòng)畫(huà);改變布局參數(shù)

彈性滑動(dòng);

使用Scroller;通過(guò)動(dòng)畫(huà);使用延遲策略:使用Handler或View的postDelayed方法,線(xiàn)程的sleep方法

事件分發(fā);
滑動(dòng)沖突:

性能優(yōu)化

1.內(nèi)存優(yōu)化:

  • ANR (多地使用CPU資源,一般是指做大量的耗時(shí)任務(wù),會(huì)導(dǎo)致手機(jī)變得卡頓甚至出現(xiàn)程序無(wú)法響應(yīng)的情況)

當(dāng)一個(gè)進(jìn)程發(fā)生ANR以后,系統(tǒng)會(huì)在data/anr目錄下常見(jiàn)一個(gè)文件traces.txt, 導(dǎo)出anr: adb pull /data/anr/traces.txt
anr分析?如果沒(méi)有app堆棧信息如何分析?(榮耀負(fù)一屏面試)
結(jié)合trace.txt和Event Log/android_log主日志文件
1.anr時(shí)間點(diǎn) 2.主線(xiàn)程狀態(tài) 3.問(wèn)題類(lèi)型
堆棧信息,內(nèi)存信息和CPU負(fù)載
確認(rèn)是否是系統(tǒng)環(huán)境影響:
整機(jī)負(fù)載:搜索ANR in關(guān)鍵字
低內(nèi)存:內(nèi)存緊張的時(shí)候,內(nèi)存回收線(xiàn)程如kswapd,HeapTaskDaemon會(huì)變得活躍,搜索lowmemorykiller關(guān)鍵字,可以看到問(wèn)題時(shí)間區(qū)域會(huì)有較多的查殺行為
主線(xiàn)程處于BLOCK(waiting to lock held by xxx,其他線(xiàn)程持有了鎖,并嘗長(zhǎng)時(shí)間未釋放,主線(xiàn)程等待鎖超時(shí)),WAITING,TIME_WAITING狀態(tài),基本就是函數(shù)阻塞導(dǎo)致的anr,

若主線(xiàn)程無(wú)異常,則排查下CPU負(fù)載,各個(gè)進(jìn)程占用CPU的詳細(xì)情況,是否有其他應(yīng)用搶占了CPU資源導(dǎo)致的ANR
如果CPU和堆棧都很正常,考慮是否內(nèi)存緊張,系統(tǒng)日志里搜索下
am_meminfo,onTrimMemory

  • OOM(過(guò)多的使用內(nèi)存會(huì)導(dǎo)致程序內(nèi)存溢出)
  • 內(nèi)存泄漏,
    分析工具:Android Profiler和MAT,LeakCanary
  • 內(nèi)存抖動(dòng)

Android Studio Profiler:
CPU->Record Java/Kotlin Method trace ->生成trace文件->分析卡頓
Memory->Capture Heap Dump ->生成hprof文件(內(nèi)存切片)->分析內(nèi)存泄漏

  • 布局優(yōu)化:

盡量減少布局文件的層級(jí),布局中的層級(jí)減少了,意味著Android繪制時(shí)的工作量少了
<include>標(biāo)簽:可以將一個(gè)指定的布局文件加載到當(dāng)前的布局文件中
<merge>標(biāo)簽:merge標(biāo)簽一般和include標(biāo)簽一起使用從而減少布局的層級(jí),eg:當(dāng)前布局是一個(gè)豎直方向的LinearLayout,如果被包含的布局文件中也采用了豎直方向的LinearLayout, 那么顯然被包含的布局文件中的LinearLayout是多余的,通過(guò)merge標(biāo)簽可以去掉多余的一層LinearLayout
ViewStub:按需加載所需的布局文件,eg:網(wǎng)絡(luò)異常時(shí)的界面,這個(gè)時(shí)候沒(méi)有必要在整個(gè)界面初始化的時(shí)候?qū)⑵浼虞d進(jìn)來(lái),通過(guò)ViewStub就可以做到在使用的時(shí)候再加載

  • 繪制優(yōu)化:
    View的onDraw方法要避免執(zhí)行大量的操作;onDraw中不要?jiǎng)?chuàng)建新的局部變量,因?yàn)閛nDraw方法可能會(huì)被頻繁調(diào)用
  • 內(nèi)存泄漏優(yōu)化:

靜態(tài)變量導(dǎo)致的內(nèi)存泄漏:持有了Activity Context
單例模式導(dǎo)致的內(nèi)存泄漏:?jiǎn)卫J降奶攸c(diǎn)是其生命周期和Applicaiton保持一致,如果使用了Activity,會(huì)導(dǎo)致Activity對(duì)象無(wú)法被及時(shí)釋放
屬性動(dòng)畫(huà)導(dǎo)致的內(nèi)存泄漏:在onDestroy中調(diào)用animator.cancel來(lái)停止動(dòng)畫(huà)

2.繪制優(yōu)化
Tools->Layout Inspector
卡頓分析 Perfetto和Systrace

3.啟動(dòng)優(yōu)化

動(dòng)畫(huà)

View動(dòng)畫(huà),幀動(dòng)畫(huà)和

  • 屬性動(dòng)畫(huà)
    ValueAnimator,ObjectAnimator和AnimationSet,其中ObjectAnimator繼承自ValueAnimator,AnimationSet是動(dòng)畫(huà)集合
    TypeEvaluator決定了動(dòng)畫(huà)如何從初始值過(guò)渡到結(jié)束值
    TimeInterpolator決定了動(dòng)畫(huà)從初始值過(guò)渡到結(jié)束值的節(jié)奏
    屬性動(dòng)畫(huà)和view動(dòng)畫(huà)區(qū)別?(榮耀商城面試)
圖片加載

ImageLoader的實(shí)現(xiàn):
1、圖片壓縮(BitmapFactory.Options按照一定的采樣率加載縮小后的圖片),內(nèi)存緩存(LruCache,內(nèi)部LinkedHashMap以強(qiáng)引用的方式存儲(chǔ)外界的緩存對(duì)象)和磁盤(pán)緩存(DiskLruCache)
2、Glide加載圖片,如果這時(shí)候按了Home鍵,Glide還會(huì)繼續(xù)加載圖片嗎?
如果Glide.with傳的context是Activity的context,那么Glide的生命周期和Activity是一致的;如果傳的context是Application的Context,那么Glide的生命周期和應(yīng)用一致;Glide內(nèi)部會(huì)創(chuàng)建一個(gè)空白的Fragment,用來(lái)管理Glide的生命周期

Jetpack

Lifecycle

讓某個(gè)類(lèi)實(shí)現(xiàn)LifecycleObserver接口;方法添加OnLifecycleEvent注解;在Activity#onCreate中調(diào)用getLifecycle().addObserver()方法

WorkManager任務(wù)調(diào)度
Room
ViewModel+LiveData
DataBinding

其他

1.熱流和冷流的區(qū)別?
熱流:數(shù)據(jù)來(lái)了立即發(fā)出,不管有沒(méi)有訂閱者
冷流:數(shù)據(jù)準(zhǔn)備好了,有訂閱者了,才會(huì)發(fā)送數(shù)據(jù)
2.adb命令

adb shell ps | grep 包名
導(dǎo)出anr: adb pull /data/anr/traces.txt
adb shell pm clear 包名
adb install -r -d xxx

3.git命令

git commit; git push; git pull;
git log
git reset xxx

android gradle編譯引用下載的三方aar包保存的電腦本地位置
android spannablestring設(shè)置文字圓角背景
android spannablestring實(shí)現(xiàn)textview不同文字大小文字居中顯示
1.一個(gè)橫向的LinearLayout下有兩個(gè)TextView, 如果內(nèi)容過(guò)長(zhǎng),擠壓截?cái)嗟谝粋€(gè)TextView, 第二個(gè)TextView內(nèi)容完全展示: LinearLayout寬度wrap_content, 第一個(gè)TextView設(shè)置width=0,layout_weight=1,lines=1,ellipsize=end
2.折疊屏旋轉(zhuǎn)180度, fragment的onConfigurationChanged方法沒(méi)有走,View的onConfigurationChanged方法執(zhí)行了
3.自定義SpannableString, 繼承RelativeSpan,實(shí)現(xiàn)getSize和draw方法
4.鏡像語(yǔ)言下,文字沒(méi)有右對(duì)齊,TextView需要設(shè)置android:textDirection="locale"
5.RecyclerView是指圓角矩形背景,outlineProvider, 設(shè)置clipToOutline=true;
不讓RecyclerView可以自己滑動(dòng),可以重寫(xiě)一個(gè)類(lèi)繼承LinearLayoutManager,重寫(xiě)canScrollVertically和canScrollHorizontally設(shè)置為false
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容