Android面试题详细整理系列(一)
以下這些面試題都是筆者在(2017年1月-2017年3月)這段時間所面試android工程師的總結(jié)而來,面試的公司包括巨頭xx等,還有新貴公司如dd在線科技,gm金融,zk網(wǎng),momo科技,zbj等,還有小型活力公司如軟都科技,星云顏值,英克科技等,不足之處,還望各位不吝賜教。
1.如何在子線程創(chuàng)建handler?
熟悉handler機制的童鞋都知道,通常handler是在主線程創(chuàng)建,但有些時候要在子線程創(chuàng)建handler,應該怎么辦(什么時候? 面試的時候 哈哈)不要急 辦法總該有 嘿嘿
方法1:(直接獲取當前子線程的looper)
方法2(獲取主線程的looper,或者說是UI線程的looper)
new Thread(new Runnable() { public void run() { Handler handler = new Handler(Looper.getMainLooper()){ // 區(qū)別在這!!!! @Override public void handleMessage(Message msg) { Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show(); } }; handler.sendEmptyMessage(1); }; }).start();2.應用程序ANR產(chǎn)生的原因?如何定位ANR
大家面試的時候肯定會發(fā)現(xiàn),有經(jīng)驗的老司機提問時都是先拋出一個簡單問題,然后由此引出很多深層次的問題,關(guān)鍵在后邊,這是面試百度時候的一個問題(筆者去的是百度科技園 老偏僻了)且聽我娓娓道來
產(chǎn)生的原因大家都知道是在主線程里做了耗時的操作導致的,ANR一般有三種類型:
1:KeyDispatchTimeout(5 seconds) –主要類型
按鍵或觸摸事件在特定時間內(nèi)無響應
2:BroadcastTimeout(10 seconds)
BroadcastReceiver在特定時間內(nèi)無法處理完成
3:ServiceTimeout(20 seconds) –小概率類型
Service在特定的時間內(nèi)無法處理完成
那我們就要著手解決主要類型,具體如何定位,有以下幾種思路:
1.通過ANR日志定位問題
當ANR發(fā)生時,我們往往通過Logcat和traces文件(目錄/data/anr/)的相關(guān)信息輸出去定位問題。主要包含以下幾方面:
1)基本信息,包括進程名、進程號、包名、系統(tǒng)build號、ANR
類型等等;
2)CPU使用信息,包括活躍進程的CPU平均占用率、IO情況等等;
3)線程堆棧信息,所屬進程包括發(fā)生ANR的進程、其父進程、最近有活動的3個進程等等。
但是在平常測試中,ANR有基本測試不到,因為ANR基本發(fā)生在垃圾設備中,弱網(wǎng)絡,頻繁操作。而且問題不必現(xiàn),即使看到了問題,定位麻煩:要去data/anr.txt文件里面查找,必須root,比較麻煩。
2.引入ANR檢測工具
由于anr問題不必現(xiàn),因此引入以下ANR檢測工具,當anr問題出現(xiàn)時,自動dump手機中的日志信息如trace文件、堆棧信息等,基本原理如下:
2.1、基本原理
檢測到UI主線程卡頓時間超過設定的時間,如4s,即dump trace文件以及堆棧信息,同時拋出異常,收集信息,根據(jù)這些文件信息即可定位到發(fā)生anr的原因
2.2、ANR檢測工具在Baidu Browser中的應用
2.2.1如何在源代碼中插入anr檢測工具
步驟一:源代碼libs中添加anr.jar
步驟二:在 Application 的onCreate中添加初始化sdk的代碼
initSDK(Context context, String appKey, boolean watchdog, int time)
其中time表示檢測判定線程是否超時(發(fā)生anr)的門限值,單位:ms
步驟三:正常編譯打包apk
2.2.2如何測試發(fā)現(xiàn)并定位anr問題
安裝步驟2.2.1編譯打包插入anr檢測的apk
測試app,任意操作(monkey/case),當發(fā)生anr時,會自動殺掉進程,并在本地生成日志文件日志路徑:/sdcard/lynq_anr下有兩個文件夾
以Baidu Browser啟動為例。
Baidu Browser啟動過程主線程過長,在低端機上容易導致發(fā)生anr;線程超時,app進程kill掉,查看手機本地trace日志,Crash信息包括trace文件以及堆棧信息
分析trace文件
Trace文件通過DDMS可以查看具體發(fā)生ANR卡頓的原因
通過real Time/Call從大到小排序,找到對應的與代碼相關(guān)消耗時間最大的方法可以看出書簽數(shù)據(jù)庫初始化消耗CPU時間最長。
3.android的context是指什么,在一個應用程序中有多少Context實例?
這個問題還是很好回答的嘛,首先Context描述的是一個應用程序環(huán)境的信息,即上下文,是一個抽象類。
因此總Context實例個數(shù)=Service個數(shù)+Activity個數(shù)+1個A品牌力cationContext個數(shù)
4.Jni開發(fā)步驟?
1)使用Android Studio開發(fā)工具,下載NDK
2)創(chuàng)建含有native方法的Java類
3)通過javah命令生成.h文件
4)在.c文件中實現(xiàn)以上方法
5)編寫Android.mk文件
6)用NDK工具編譯生成.so文件
7)把.so文件復制到lib下
5.事件沖突解決方案
針對滑動沖突這里給出兩種解決方案:外部攔截法,內(nèi)部攔截法。
1)外部攔截法
情景:一個ViewPager嵌套了一個Listview,一個是左右滑動,一個上下滑動。這個時候我們可以用外部攔截法,來處理沖突。在父容器ViewPager中,重寫onInterceptTouchEvent()方法,判斷當左右滑動時就攔截事件,上下滑動就不攔截,將事件交由子元素Listview來處理。首先我們需要重寫一個ViewPager,叫MyViewPager,然后重寫onInterceptTouchEvent()方法。具體代碼如下:
2)內(nèi)部攔截法
情景:一個ViewPager嵌套了一個ViewPager,兩個都是左右滑動。這個時候我們可以用內(nèi)部攔截法,來處理沖突。即重寫子元素的dispatchTouchEvent()方法,并調(diào)用getParent().requestDisallowInterceptTouchEvent(true)是父容器不能攔截子元素需要的事件。下面來看具體代碼:
當然,還需要修改父容器的onInterceptTouchEvent()方法,代碼如下:
@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {int action=ev.getAction();if(action==MotionEvent.ACTION_DOWN){return false;}else {return true;}}6.如何查看Activty任務棧結(jié)構(gòu)?
剛聽到問題,小哥我一下蒙蔽了,細細一想,有以下解決方案
方法一:通過ActivityManager獲取狀態(tài)
Android提供了ActivityManger來幫助開發(fā)者了解運行期間的狀態(tài),通過調(diào)用getRunningTasks(int)方法,就可以在得到RunningTaskInfo的列表,其代表著當前Android設備正在運行著的Task。從RunningTaskInfo中又可以進一步得到更多的信息。
方法二:手動記錄和管理Activities棧
Activity的創(chuàng)建和銷毀都會有相應的回調(diào)函數(shù):onCreate(),onDestroy()。因此可以自建一個靜態(tài)全局Stack對象,在onCreate()時候講當前Activity對象加入到Stack中,而在onDestroy()時把它從Stack中移除。這樣我們就隨時可以知道當前Activity的詳細情況了。
方法三:使用adb shell指令
Android還為開發(fā)者提供了adb(Android Debug Bridge),這是非常強大的調(diào)試工具。最常用的自然是logcat來顯示日志記錄。另外一個很強大的指令就是這里要提到的dumpsys。dumpsys還可以添加不同的參數(shù)來指示需要輸出哪一類Service的信息。對于本文提到的內(nèi)容,需要查看的就是activity,指令就是:
輸入上述指令,就能得到關(guān)于設備非常長的一段訊息,單是也能清晰看出它們比較詳細的分類
ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)* PendingIntentRecord{42b05f20 com.android.vending startService}... ... ... ...ACTIVITY MANAGER BROADCAST STATE (dumpsys activity broadcasts)Historical broadcasts [foreground]:#0: BroadcastRecord{430d2fb8 u-1 android.intent.action.TIME_TICK}act=android.intent.action.TIME_TICK flg=0x50000014 (has extras)extras: Bundle[{android.intent.extra.ALARM_COUNT=1}]... ... ... ...ACTIVITY MANAGER CONTENT PROVIDERS (dumpsys activity providers)Published single-user content providers (by class):* ContentProviderRecord{429d18a8 u0 com.android.phone/.IccProvider}proc=ProcessRecord{429765d8 858:com.android.phone/1001}singleton=trueauthority=icc... ... ... ...ACTIVITY MANAGER SERVICES (dumpsys activity services)User 0 active services:* ServiceRecord{429f8668 u0 com.android.bluetooth/.hid.HidService}app=nullcreated=-1h44m27s317ms started=false connections=0... ... ... ...ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)Stack #0:Task id #28TaskRecord{43525058 #28 A=com.android.systemui U=0 sz=1}Intent { act=com.android.systemui.recent.action.TOGGLE_RECENTS flg=0x10c00000 cmp=com.android.systemui/.recent.RecentsActivity (has extras) }Hist #0: ActivityRecord{428d1ae8 u0 com.android.systemui/.recent.RecentsActivity t28}Intent { act=com.android.systemui.recent.action.TOGGLE_RECENTS flg=0x10800000 cmp=com.android.systemui/.recent.RecentsActivity bnds=[328,886][656,1176] }ProcessRecord{42968230 695:com.android.systemui/u0a12}... ... ... ...ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)Process LRU list (sorted by oom_adj, 28 total, non-act at 3, non-svc at 3):PERS #27: sys F/ /P trm: 0 605:system/1000 (fixed)... ... ... ...每一個類別都有一個括號內(nèi)容,給出了更加詳細的指令來查看該類別下更多具體內(nèi)容。因此再來嘗試指令:
db shell dumpsys activity activities就能看到下邊的結(jié)果
CTIVITY MANAGER ACTIVITIES (dumpsys activity activities)Stack #0:Task id #28* TaskRecord{43525058 #28 A=com.android.systemui U=0 sz=1}... ... ... ...* Hist #0: ActivityRecord{428d1ae8 u0 com.android.systemui/.recent.RecentsActivity t28}... ... ... ...Task id #1* TaskRecord{429a35f8 #1 A=com.android.launcher U=0 sz=1}... ... ... ...* Hist #0: ActivityRecord{429a1760 u0 com.android.launcher/com.android.launcher2.Launcher t1}... ... ... ...Running activities (most recent first):TaskRecord{43525058 #28 A=com.android.systemui U=0 sz=1}Run #1: ActivityRecord{428d1ae8 u0 com.android.systemui/.recent.RecentsActivity t28}TaskRecord{429a35f8 #1 A=com.android.launcher U=0 sz=1}Run #0: ActivityRecord{429a1760 u0 com.android.launcher/com.android.launcher2.Launcher t1}mLastPausedActivity: ActivityRecord{428d1ae8 u0 com.android.systemui/.recent.RecentsActivity t28}Stack #1:Task id #25* TaskRecord{42b0ee20 #25 I=com.iderzheng/.SingleTaskActivity U=0 sz=5}numActivities=5 rootWasReset=false userId=0 mTaskType=0 numFullscreen=5 mOnTopOfHome=trueintent={cmp=com.iderzheng/.SingleTaskActivity}realActivity=com.iderzheng/.SingleTaskActivityActivities=[ActivityRecord{42a7e160 u0 com.iderzheng/.SingleTaskActivity t25}, ActivityRecord{42bffdf0 u0 com.iderzheng/.StandardActivity t25}, ActivityRecord{42e9e8f8 u0 com.iderzheng/.SingleTopActivity t25}, ActivityRecord{434c2238 u0 com.iderzheng/.StandardActivity t25}, ActivityRecord{4279d2d8 u0 com.iderzheng/.SingleTopActivity t25}]askedCompatMode=falselastThumbnail=null lastDescription=nulllastActiveTime=6229735 (inactive for 357s)* Hist #4: ActivityRecord{4279d2d8 u0 com.iderzheng/.SingleTopActivity t25}packageName=com.iderzheng processName=com.iderzhenglaunchedFromUid=10124 launchedFromPackage=com.iderzheng userId=0app=ProcessRecord{4312cbb0 3700:com.iderzheng/u0a124}Intent { cmp=com.iderzheng/.SingleTopActivity bnds=[328,580][656,870] }frontOfTask=false task=TaskRecord{42b0ee20 #25 I=com.iderzheng/.SingleTaskActivity U=0 sz=5}taskAffinity=com.iderzhengrealActivity=com.iderzheng/.SingleTopActivitybaseDir=/data/app/com.iderzheng-1.apkdataDir=/data/data/com.iderzhengstateNotNeeded=false componentSpecified=true mActivityType=0compat={320dpi} labelRes=0x7f0a0013 icon=0x7f020057 theme=0x7f0b0000config={1.0 310mcc?mnc en_US ldltr sw384dp w384dp h567dp 320dpi nrml port finger -keyb/v/h -nav/h s.7}launchFailed=false launchCount=0 lastLaunchTime=-1h40m33s397mshaveState=false icicle=nullstate=RESUMED stopped=false delayedResume=false finishing=falsekeysPaused=false inHistory=true visible=true sleeping=false idle=truefullscreen=true noDisplay=false immersive=false launchMode=1frozenBeforeDestroy=false thumbnailNeeded=false forceNewConfig=falsemActivityType=APPLICATION_ACTIVITY_TYPEthumbHolder: 42b0ee20 bm=null desc=nullwaitingVisible=false nowVisible=true lastVisibleTime=-5m56s862ms... ... ... ...Running activities (most recent first):TaskRecord{42b0ee20 #25 I=com.iderzheng/.SingleTaskActivity U=0 sz=5}Run #7: ActivityRecord{4279d2d8 u0 com.iderzheng/.SingleTopActivity t25}TaskRecord{429e9558 #24 A=com.iderzheng U=0 sz=1}Run #6: ActivityRecord{429d5408 u0 com.iderzheng/.SingleInstanceActivity t24}TaskRecord{42b0ee20 #25 I=com.iderzheng/.SingleTaskActivity U=0 sz=5}Run #5: ActivityRecord{434c2238 u0 com.iderzheng/.StandardActivity t25}Run #4: ActivityRecord{42e9e8f8 u0 com.iderzheng/.SingleTopActivity t25}Run #3: ActivityRecord{42bffdf0 u0 com.iderzheng/.StandardActivity t25}Run #2: ActivityRecord{42a7e160 u0 com.iderzheng/.SingleTaskActivity t25}TaskRecord{4282e508 #23 A=com.iderzheng U=0 sz=2}Run #1: ActivityRecord{429655d8 u0 com.iderzheng/.StandardActivity t23}Run #0: ActivityRecord{429564e0 u0 com.iderzheng/.MainActivity t23}... ... ... ...Recent tasks:... ... ... ...整個log顯示了當前所有在運行的任務棧,它們的id分別是什么。對于每個Task,也有Activity數(shù)量等信息,同時也列出了其中的Activity列表,并且對于每個Activity也有比較詳細的描述,比如啟動它的Intent的內(nèi)容。
如果覺得內(nèi)容過多,只想看看棧的內(nèi)容,也可以直接跳到”Running activities (most recent first)”那部分,比較簡潔而又明了的列出了棧中得Activity列表,就能知道當按下返回鍵的時候會應該會回到哪個Activity以后是要退出程序。
在寫這篇文章時參考了很多同行的博客,在此特別感謝Iden,Vonnie Jade,baidu_mtc的博客,hongdameng的專欄等同行。希望大家共同成長,共同進步。
我是kris,See you next time!!!
http://blog.iderzheng.com/debug-activity-task-stack-with-adb-shell-dumpsys/ 使用adb shell dumpsys檢測Android的Activity任務棧(Iden)
http://www.cnblogs.com/yxx123/p/5250101.html Android滑動事件沖突(Vonnie Jade)
http://blog.csdn.net/baidu_mtc/article/details/50396143 ANR檢查定位分析工具(baidu_mtc的博客)
http://blog.csdn.net/hongdameng/article/details/42639961# Android子線程創(chuàng)建Handler方法(hongdameng的專欄)
總結(jié)
以上是生活随笔為你收集整理的Android面试题详细整理系列(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android常用开源库之Univers
- 下一篇: Android面试题详细整理系列(二)