Android面試題
Android面試題包括Android基礎(chǔ),還有一些源碼級別的童漩、原理這些等弄贿。所以想去大公司面試,一定要多看看源碼和實現(xiàn)方式矫膨,常用框架可以試試自己能不能手寫實現(xiàn)一下差凹,鍛煉一下自己。
(一)Android基礎(chǔ)知識點
1侧馅、四大組件是什么
1)Activity:用戶可操作的可視化界面危尿,為用戶提供一個完成操作指令的窗口。一個Activity通常是一個單獨的屏幕馁痴,Activity通過Intent來進行通信谊娇。Android中會維持一個Activity Stack,當(dāng)一個新Activity創(chuàng)建時弥搞,它就會放到棧頂邮绿,這個Activity就處于運行狀態(tài)渠旁。
2)Service:服務(wù),運行在手機后臺船逮,適合執(zhí)行不需和用戶交互且還需長期運行的任務(wù)顾腊。
3)ContentProvider:內(nèi)容提供者,使一個應(yīng)用程序的指定數(shù)據(jù)集提供給其他應(yīng)用程序挖胃,其他應(yīng)用可通過ContentResolver類從該內(nèi)容提供者中獲取或存入數(shù)據(jù)杂靶。它提供了一種跨進程數(shù)據(jù)共享的方式,當(dāng)數(shù)據(jù)被修改后酱鸭,ContentResolver接口的notifyChange函數(shù)通知那些注冊監(jiān)控特定URI的ContentObserver對象吗垮。
如果ContentProvider和調(diào)用者在同一進程中,ContentProvider的方法(query/insert/update/delete等)和調(diào)用者在同一線程中凹髓;如果ContentProvider和調(diào)用者不在同一進程烁登,ContentProvider方法會運行在它自身進程的一個Binder線程中。
4)Broadcast Receiver: 廣播接收者蔚舀,運用在應(yīng)用程序間傳輸信息饵沧,可以使用廣播接收器來讓應(yīng)用對一個外部事件做出響應(yīng)。
2赌躺、四大組件的生命周期和簡單用法
1)Activity:onCreate()->onStart()->onResume()->onPause()->onStop()->onDestory()
onCreate():為Activity設(shè)置布局狼牺,此時界面還不可見;
onStart(): Activity可見但還不能與用戶交互礼患,不能獲得焦點
onRestart(): 重新啟動Activity時被回調(diào)
onResume(): Activity可見且可與用戶進行交互
onPause(): 當(dāng)前Activity暫停是钥,不可與用戶交互,但還可見缅叠。在新Activity啟動前被系統(tǒng)調(diào)用保存現(xiàn)有的Activity中的持久數(shù)據(jù)悄泥、停止動畫等。
onStop(): 當(dāng)Activity被新的Activity覆蓋不可見時被系統(tǒng)調(diào)用
onDestory(): 當(dāng)Activity被系統(tǒng)銷毀殺掉或是由于內(nèi)存不足時調(diào)用
2)Service
a) onBind方式綁定的:onCreate->onBind->onUnBind->onDestory(不管調(diào)用bindService幾次肤粱,onCreate只會調(diào)用一次码泞,onStart不會被調(diào)用,建立連接后狼犯,service會一直運行,直到調(diào)用unBindService或是之前調(diào)用的bindService的Context不存在了领铐,系統(tǒng)會自動停止Service,對應(yīng)的onDestory會被調(diào)用)
b) startService啟動的:onCreate->onStartCommand->onDestory(start多次悯森,onCreate只會被調(diào)用一次,onStart會調(diào)用多次绪撵,該service會在后臺運行瓢姻,直至被調(diào)用stopService或是stopSelf)
c) 又被啟動又被綁定的服務(wù),不管如何調(diào)用onCreate()只被調(diào)用一次音诈,startService調(diào)用多少次幻碱,onStart就會被調(diào)用多少次绎狭,而unbindService不會停止服務(wù),必須調(diào)用stopService或是stopSelf來停止服務(wù)褥傍。必須unbindService和stopService(stopSelf)同時都調(diào)用了才會停止服務(wù)儡嘶。
3)BroadcastReceiver
a) 動態(tài)注冊:存活周期是在Context.registerReceiver和Context.unregisterReceiver之間,BroadcastReceiver每次收到廣播都是使用注冊傳入的對象處理的恍风。
b) 靜態(tài)注冊:進程在的情況下蹦狂,receiver會正常收到廣播,調(diào)用onReceive方法朋贬;生命周期只存活在onReceive函數(shù)中凯楔,此方法結(jié)束,BroadcastReceiver就銷毀了锦募。onReceive()只有十幾秒存活時間摆屯,在onReceive()內(nèi)操作超過10S,就會報ANR糠亩。
進程不存在的情況虐骑,廣播相應(yīng)的進程會被拉活,Application.onCreate會被調(diào)用削解,再調(diào)用onReceive富弦。
4)ContentProvider:應(yīng)該和應(yīng)用的生命周期一樣,它屬于系統(tǒng)應(yīng)用氛驮,應(yīng)用啟動時腕柜,它會跟著初始化,應(yīng)用關(guān)閉或被殺矫废,它會跟著結(jié)束盏缤。
3、Activity之間的通信方式
1)通過Intent方式傳遞參數(shù)跳轉(zhuǎn)
2)通過廣播方式
3)通過接口回調(diào)方式
4)借助類的靜態(tài)變量或全局變量
5)借助SharedPreference或是外部存儲蓖扑,如數(shù)據(jù)庫或本地文件
4唉铜、Activity各種情況下的生命周期
1) 兩個Activity(A->B)切換(B正常的Activity)的生命周期:onPause(A)->onCreate(B)->onStart(B)->onResume(B)->oStop(A)
這時如果按回退鍵回退到A? onPause(B)->onRestart(A)->onStart(A)->onResume(A)->oStop(B)
如果在切換到B后調(diào)用了A.finish(),則會走到onDestory(A)律杠,這時點回退鍵會退出應(yīng)用
2) 兩個Activity(A->B)切換(B透明主題的Activity或是Dialog風(fēng)格的Acivity)的生命周期:onPause(A)->onCreate(B)->onStart(B)->onResume(B)
這時如果回退到A? onPause(B)->onResume(A)->oStop(B)->onDestory(B)
3) Activity(A)啟動后點擊Home鍵再回到應(yīng)用的生命周期:onPause(A)->oStop(A)->onRestart(A)->onStart(A)->onResume(A)
5、橫豎屏切換的時候柜去,Activity 各種情況下的生命周期
1)切換橫屏?xí)r:onSaveInstanceState->onPause->onStop->onDestory->onCreate->onStart->onRestoreInstanceState->onResume
2) 切換豎屏?xí)r:會打印兩次相同的log? ?
onSaveInstanceState->onPause->onStop->onDestory->onCreate->onStart->onRestoreInstanceState->onResume->onSaveInstanceState->onPause->onStop->onDestory->onCreate->onStart->onRestoreInstanceState->onResume
3) 如果在AndroidMainfest.xml中修改該Activity的屬性灰嫉,添加android:configChanges="orientation"
橫豎屏切換,打印的log一樣嗓奢,同1)
4) 如果AndroidMainfest.xml中該Activity中的android:configChanges="orientation|keyboardHidden"讼撒,則只會打印
onConfigurationChanged->
6、Activity與Fragment之間生命周期比較
Fragment生命周期:onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume->onPause->onStop->onDestoryView->onDestory->onDetach
切換到該Fragment:onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume
按下Power鍵:onPause->onSaveInstanceState->onStop
點亮屏幕解鎖:onStart->onRestoreInstanceState->onResume
切換到其他Fragment: onPause->onStop->onDestoryView
切回到該Fragment: onCreateView->onActivityCreated->onStart->onResume
退出應(yīng)用:onPause->onStop->onDestoryView->onDestory->onDetach
7、Activity上有Dialog的時候按Home鍵時的生命周期
AlertDialog并不會影響Activity的生命周期根盒,按Home鍵后才會使Activity走onPause->onStop钳幅,AlertDialog只是一個組件,并不會使Activity進入后臺炎滞。
8敢艰、兩個Activity 之間跳轉(zhuǎn)時必然會執(zhí)行的是哪幾個方法?
前一個Activity的onPause厂榛,后一個Activity的onResume
9盖矫、前臺切換到后臺,然后再回到前臺击奶,Activity生命周期回調(diào)方法抖格。彈出Dialog炬称,生命值周期回調(diào)方法砍鸠。
1)前臺切換到后臺践瓷,會執(zhí)行onPause->onStop,再回到前臺痰驱,會執(zhí)行onRestart->onStart->onResume
2) 彈出Dialog证芭,并不會影響Activity生命周期
10、Activity的四種啟動模式對比
1)standard:標(biāo)準(zhǔn)啟動模式(默認(rèn))担映,每啟動一次Activity废士,都會創(chuàng)建一個實例,即使從ActivityA startActivity ActivityA,也會再次創(chuàng)建A的實例放于棧頂蝇完,當(dāng)回退時官硝,回到上一個ActivityA的實例。
2) singleTop:棧頂復(fù)用模式短蜕,每次啟動Activity氢架,如果待啟動的Activity位于棧頂,則不會重新創(chuàng)建Activity的實例朋魔,即不會走onCreate->onStart岖研,會直接進入Activity的onPause->onNewIntent->onResume方法
3) singleInstance: 單一實例模式,整個手機操作系統(tǒng)里只有一個該Activity實例存在警检,沒有其他Actvity,后續(xù)請求均不會創(chuàng)建新的Activity孙援。若task中存在實例,執(zhí)行實例的onNewIntent()扇雕。應(yīng)用場景:鬧鐘赃磨、瀏覽器、電話
4) singleTask:棧內(nèi)復(fù)用洼裤,啟動的Activity如果在指定的taskAffinity的task棧中存在相應(yīng)的實例,則會把它上面的Activity都出棧,直到當(dāng)前Activity實例位于棧頂腮鞍,執(zhí)行相應(yīng)的onNewIntent()方法值骇。如果指定的task不存在,創(chuàng)建指定的taskAffinity的task,taskAffinity的作用移国,進入指寫taskAffinity的task,如果指定的task存在吱瘩,將task移到前臺,如果指定的task不存在迹缀,創(chuàng)建指定的taskAffinity的task. 應(yīng)用場景:應(yīng)用的主頁面
11使碾、Activity狀態(tài)保存于恢復(fù)
Activity被主動回收時,如按下Back鍵祝懂,系統(tǒng)不會保存它的狀態(tài)票摇,只有被動回收時,雖然這個Activity實例已被銷毀砚蓬,但系統(tǒng)在新建一個Activity實例時矢门,會帶上先前被回收Activity的信息。在當(dāng)前Activity被銷毀前調(diào)用onSaveInstanceState(onPause和onStop之間保存)灰蛙,重新創(chuàng)建Activity后會在onCreate后調(diào)用onRestoreInstanceState(onStart和onResume之間被調(diào)用)祟剔,它們的參數(shù)Bundle用來數(shù)據(jù)保存和讀取的。
保存View狀態(tài)有兩個前提:View的子類必須實現(xiàn)了onSaveInstanceState; 必須要設(shè)定Id摩梧,這個ID作為Bundle的Key
12物延、fragment各種情況下的生命周期
正常情況下的生命周期:onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume->onPause->onStop->onDestoryView->onDestory->onDetach
1)Fragment在Activity中replace? onPause(舊)->onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume->onStop(舊)->onDestoryView(舊)
如果添加到backStack中,調(diào)用remove()方法fragment的方法會走到onDestoryView仅父,但不會執(zhí)行onDetach()叛薯,即fragment本身的實例是存在的,成員變量也存在驾霜,但是view被銷毀了案训。如果新替換的Fragment已在BackStack中,則不會執(zhí)行onAttach->onCreate
13粪糙、Fragment狀態(tài)保存onSaveInstanceState是哪個類的方法强霎,在什么情況下使用?
在對應(yīng)的FragmentActivity.onSaveInstanceState方法會調(diào)用FragmentController.saveAllState蓉冈,其中會對mActive中各個Fragment的實例狀態(tài)和View狀態(tài)分別進行保存.當(dāng)Activity在做狀態(tài)保存和恢復(fù)的時候, 在它其中的fragment自然也需要做狀態(tài)保存和恢復(fù).
參考文章:Android Fragment使用(三) Activity, Fragment, WebView的狀態(tài)保存和恢復(fù)
14城舞、Fragment.startActivityForResult是和FragmentActivity的startActivityForResult?
如果希望在Fragment的onActivityResult接收數(shù)據(jù)寞酿,就要調(diào)用Fragment.startActivityForResult家夺, 而不是Fragment.getActivity().startActivityForResult。Fragment.startActivityForResult->FragmentActivitymHost.HostCallbacks.onStartActivityFromFragment->FragmentActivity.startActivityFromFragment伐弹。如果request=-1則直接調(diào)用FragmentActivity.startActivityForResult拉馋,它會重新計算requestCode,使其大于0xfffff。
參考文章:徹底搞懂startActivityForResult在FragmentActivity和Fragment中的異同
15煌茴、如何實現(xiàn)Fragment的滑動随闺?
ViewPager+FragmentPagerAdapter+List<Fragment>
16、fragment之間傳遞數(shù)據(jù)的方式蔓腐?
1)在相應(yīng)的fragment中編寫方法矩乐,在需要回調(diào)的fragment里獲取對應(yīng)的Fragment實例,調(diào)用相應(yīng)的方法回论;
2)采用接口回調(diào)的方式進行數(shù)據(jù)傳遞散罕;
a) 在Fragment1中創(chuàng)建一個接口及接口對應(yīng)的set方法; b) 在Fragment1中調(diào)用接口的方法;c)在Fragment2中實現(xiàn)該接口傀蓉;
3)利用第三方開源框架EventBus
17欧漱、service和activity怎么進行數(shù)據(jù)交互?
1)通過bindService啟動服務(wù)僚害,可以在ServiceConnection的onServiceConnected中獲取到Service的實例硫椰,這樣就可以調(diào)用service的方法,如果service想調(diào)用activity的方法萨蚕,可以在service中定義接口類及相應(yīng)的set方法,在activity中實現(xiàn)相應(yīng)的接口奕翔,這樣service就可以回調(diào)接口言法浩蓉;
2)通過廣播方式
18派继、說說ContentProvider捻艳、ContentResolver、ContentObserver 之間的關(guān)系
ContentProvider實現(xiàn)各個應(yīng)用程序間數(shù)據(jù)共享认轨,用來提供內(nèi)容給別的應(yīng)用操作绅络。如聯(lián)系人應(yīng)用中就使用了ContentProvider嘁字,可以在自己應(yīng)用中讀取和修改聯(lián)系人信息,不過需要獲取相應(yīng)的權(quán)限衷恭。它也只是一個中間件随珠,真正的數(shù)據(jù)源是文件或SQLite等。
ContentResolver內(nèi)容解析者牙丽,用于獲取內(nèi)容提供者提供的數(shù)據(jù)烤芦,通過ContentResolver.notifyChange(uri)發(fā)出消息
ContentObserver內(nèi)容監(jiān)聽者析校,可以監(jiān)聽數(shù)據(jù)的改變狀態(tài),觀察特定Uri引起的數(shù)據(jù)庫變化遂唧,繼而做一些相應(yīng)的處理吊奢,類似于數(shù)據(jù)庫中的觸發(fā)器页滚,當(dāng)ContentObserver所觀察的Uri發(fā)生變化時,便會觸發(fā)它裹驰。
19幻林、請描述一下廣播BroadcastReceiver的理解
BroadcastReceiver是一種全局監(jiān)聽器,用來實現(xiàn)系統(tǒng)中不同組件之間的通信躏敢。有時候也會用來作為傳輸少量而且發(fā)送頻率低的數(shù)據(jù)件余,但是如果數(shù)據(jù)的發(fā)送頻率比較高或者數(shù)量比較大就不建議用廣播接收者來接收了掘宪,因為這樣的效率很不好魏滚,因為BroadcastReceiver接收數(shù)據(jù)的開銷還是比較大的。
20更哄、廣播的分類
1)普通廣播:完全異步的,可以在同一時刻(邏輯上)被所有接收者接收到觅捆,消息傳遞的效率比較高麻敌,并且無法中斷廣播的傳播术羔。
2)有序廣播:發(fā)送有序廣播后级历,廣播接收者將按預(yù)先聲明的優(yōu)先級依次接收Broadcast。優(yōu)先級高的優(yōu)先接收到廣播玩讳,而在其onReceiver()執(zhí)行過程中嚼贡,廣播不會傳播到下一個接收者编曼,此時當(dāng)前的廣播接收者可以abortBroadcast()來終止廣播繼續(xù)向下傳播,也可以將intent中的數(shù)據(jù)進行修改設(shè)置往扔,然后將其傳播到下一個廣播接收者萍膛。 sendOrderedBroadcast(intent, null);//發(fā)送有序廣播
3)粘性廣播:sendStickyBroadcast()來發(fā)送該類型的廣播信息嚷堡,這種的廣播的最大特點是蝌戒,當(dāng)粘性廣播發(fā)送后,最后的一個粘性廣播會滯留在操作系統(tǒng)中桩匪。如果在粘性廣播發(fā)送后的一段時間里友鼻,如果有新的符合廣播的動態(tài)注冊的廣播接收者注冊,將會收到這個廣播消息僻爽,雖然這個廣播是在廣播接收者注冊之前發(fā)送的贾惦,另外一點须板,對于靜態(tài)注冊的廣播接收者來說,這個等同于普通廣播。
21杰刽、廣播使用的方式和場景
1)App全局監(jiān)聽:在AndroidManifest中靜態(tài)注冊的廣播接收器王滤,一般我們在收到該消息后雁乡,需要做一些相應(yīng)的動作,而這些動作與當(dāng)前App的組件曲饱,比如Activity或者Service的是否運行無關(guān)扩淀,比如我們在集成第三方Push SDK時啤挎,一般都會添加一個靜態(tài)注冊的BroadcastReceiver來監(jiān)聽Push消息庆聘,當(dāng)有Push消息過來時伙判,會在后臺做一些網(wǎng)絡(luò)請求或者發(fā)送通知等等织盼。
2)組件局部監(jiān)聽:這種主要是在Activity或者Service中使用registerReceiver()動態(tài)注冊的廣播接收器,因為當(dāng)我們收到一些特定的消息邮利,比如網(wǎng)絡(luò)連接發(fā)生變化時,我們可能需要在當(dāng)前Activity頁面給用戶一些UI上的提示厕吉,或者將Service中的網(wǎng)絡(luò)請求任務(wù)暫停头朱。所以這種動態(tài)注冊的廣播接收器適合特定組件的特定消息處理项钮。
22希停、在manifest 和代碼中如何注冊和使用BroadcastReceiver?
1)mainfest中注冊:靜態(tài)注冊的廣播接收者就是一個常駐在系統(tǒng)中的全局監(jiān)聽器脖苏,也就是說如果你應(yīng)用中配置了一個靜態(tài)的BroadcastReceiver棍潘,而且你安裝了應(yīng)用而無論應(yīng)用是否處于運行狀態(tài),廣播接收者都是已經(jīng)常駐在系統(tǒng)中了恤浪。
??? <receiver android:name=".MyBroadcastReceiver">
??????? <intent-filter>
??????????? <action android:name="com.smilexie.test.intent.mybroadcastreceiver"/>
??????? </intent-filter>
??? </receiver>
2) 動態(tài)注冊:動態(tài)注冊的廣播接收者只有執(zhí)行了registerReceiver(receiver, filter)才會開始監(jiān)聽廣播消息水由,并對廣播消息作為相應(yīng)的處理砂客。
??? IntentFilter fiter = new IntentFilter("com.smilexie.test.intent.mybroadcastreceiver");
??? MyBroadcastReceiver receiver = new MyBroadcastReceiver();
??? registerReceiver(receiver, filter);
??? //撤銷廣播接受者的動態(tài)注冊
??? unregisterReceiver(receiver);
23、本地廣播和全局廣播有什么差別媚创?
1)LocalBroadcastReceiver僅在自己的應(yīng)用內(nèi)發(fā)送接收廣播钞钙,也就是只有自己的應(yīng)用能收到芒炼,數(shù)據(jù)更加安全术徊。廣播只在這個程序里赠涮,而且效率更高世囊。只能動態(tài)注冊窿祥,在發(fā)送和注冊的時候采用LocalBroadcastManager的sendBroadcast方法和registerReceiver方法晒衩。
2)全局廣播:發(fā)送的廣播事件可被其他應(yīng)用程序獲取听系,也能響應(yīng)其他應(yīng)用程序發(fā)送的廣播事件(可以通過 exported–是否監(jiān)聽其他應(yīng)用程序發(fā)送的廣播 在清單文件中控制) 全局廣播既可以動態(tài)注冊靠胜,也可以靜態(tài)注冊。
24陕习、AlertDialog,popupWindow,Activity區(qū)別
(1)Popupwindow在顯示之前一定要設(shè)置寬高该镣,Dialog無此限制损合。
(2)Popupwindow默認(rèn)不會響應(yīng)物理鍵盤的back嫁审,除非顯示設(shè)置了popup.setFocusable(true);而在點擊back的時候,Dialog會消失枣购。
(3)Popupwindow不會給頁面其他的部分添加蒙層棉圈,而Dialog會分瘾。
(4)Popupwindow沒有標(biāo)題吁系,Dialog默認(rèn)有標(biāo)題汽纤,可以通過dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);取消標(biāo)題
(5)二者顯示的時候都要設(shè)置Gravity蕴坪。如果不設(shè)置背传,Dialog默認(rèn)是Gravity.CENTER。
(6)二者都有默認(rèn)的背景痴脾,都可以通過setBackgroundDrawable(new ColorDrawable(android.R.color.transparent));去掉赞赖。
(7)Popupwindow彈出后薯定,取得了用戶操作的響應(yīng)處理權(quán)限话侄,使得其他UI控件不被觸發(fā)。而AlertDialog彈出后吞杭,點擊背景芽狗,AlertDialog會消失童擎。
25顾复、Application 和 Activity 的 Context 對象的區(qū)別
1)Application Context是伴隨應(yīng)用生命周期芯砸;不可以showDialog, startActivity, LayoutInflation
可以startService\BindService\sendBroadcast\registerBroadcast\load Resource values
2)Activity Context指生命周期只與當(dāng)前Activity有關(guān)给梅,而Activity Context這些操作都可以动羽,即凡是跟UI相關(guān)的运吓,都得用Activity做為Context來處理羽德。
一個應(yīng)用Context的數(shù)量=Activity數(shù)量+Service數(shù)量+1(Application數(shù)量)
26?Android屬性動畫特性
1)可以對非View的對象進行動畫操作宅静;
2)補間動畫只能實現(xiàn)移動站欺、縮放矾策、旋轉(zhuǎn)贾虽、淡入淡出,而無法擴展菇肃,如對背景顏色進行改變等琐谤,但是屬性動畫就可以斗忌;
3)屬性動畫真正改變了對象的屬性
27?如何導(dǎo)入外部數(shù)據(jù)庫?
android系統(tǒng)下數(shù)據(jù)庫應(yīng)該存放在/data/data/com..(package name)/目錄下织阳,通過FileInputStream讀取原數(shù)據(jù)庫陈哑,再用FileOutputStream把讀取到的東西寫入到那個目錄下伸眶。在原數(shù)據(jù)庫放在項目源碼的/res/raw/目錄下厘贼,建立一個DBManager類嘴秸,
28岳掐、談?wù)剬涌谂c回調(diào)的理解
原理:先創(chuàng)建一個對象串述,再創(chuàng)建一個控制器對象纲酗,將回調(diào)對象需要被調(diào)用的方法告訴控制器對象觅赊,控制器對象負(fù)責(zé)檢查某個場景是否出現(xiàn)或某個條件是否滿足吮螺,當(dāng)滿足時,自動調(diào)用回調(diào)對象方法坯约。
29闹丐、介紹下SurfView
SurfaceView擁有獨立的繪圖表面Surface卿拴,它不與其宿主窗口共享一個Surface堕花,由于擁有獨立的Surface缘挽,所以SurfaceView的UI就可以在一個單獨的線程中進行繪制师崎。繪圖流程:在繪圖表面的基礎(chǔ)上創(chuàng)建一塊畫布,即獲得一個Canvas對象惊畏;利用Canvas類提供的繪圖接口在前面獲得的畫布上繪制任意的UI衅鹿;將已填充好了的UI數(shù)據(jù)的畫布緩沖區(qū)提交給SurfaceFlinger服務(wù)大渤,以便SurfaceFlinger服務(wù)可以將它合成到屏幕上泵三。
優(yōu)點:1)可以在非UI線程中繪制;2)SurfaceView的頻率可以操作60FPS; 3) 在要求實時性比較高的游戲開發(fā)中具篇,view的onDraw一般滿足不了要求凌埂,這時只能用SurfaceView
使用步驟:
1)繼承自SurfaceView; 2)初始化時,拿到SurfaceHolder伏恐,給SurfaceHolder設(shè)置Callback; 3) 在Callback中寫幾個回調(diào)方法surfaceCreated\surfaceChanged\surfaceDestoryed翠桦;4)在surfaceCreated中起一個線程胳蛮,在線程中拿到SurfaceHolder去鎖定Canvas進行繪圖仅炊。
RecycleView的使用
序列化的作用,以及Android兩種序列化的區(qū)別
差值器
實現(xiàn)Interpolator接口蜕窿,根據(jù)時間來計算當(dāng)前屬性需要改變的百分比值桐经。設(shè)置值的變化趨勢次询,SDK中包含了勻速插值器LinearInterpolator屯吊、加速插值器盒卸、減速插值器DecelerateInterpolator蔽介、先加速再減速AccelerateDecelerateInterpolator、彈
??? 估值器
根據(jù)屬性變化的百分比值來計算改變后的屬性值。需要實現(xiàn)TypeEvaluatior接口
??? Android中數(shù)據(jù)存儲方式
1)SharedPreferences:用來存儲一些簡單的配置信息律胀,如登錄的用戶名炭菌、密碼黑低,采用map數(shù)據(jù)結(jié)構(gòu)存儲投储。寫入的時候先調(diào)用edit()使其處于編輯態(tài)玛荞,再修改數(shù)據(jù)勋眯,最后用commit()來提交修改的數(shù)據(jù)客蹋。采用XML格式將數(shù)據(jù)存儲到設(shè)備上/data/data/<package name>/shares_prefs下讶坯。只能在同一個包內(nèi)使用辆琅,不能在不同包之間使用。
2) 數(shù)據(jù)庫SQLite
3)SD卡婉烟,本地存儲:openFileInput()和openFileOutput()
4)使用ContentProvider存儲數(shù)據(jù):可向其他應(yīng)用共享數(shù)據(jù)娩井,
(二)Android源碼相關(guān)分析
1、Android屬性動畫實現(xiàn)原理
工作原理:在一定時間間隔內(nèi)似袁,通過不斷對值進行改變洞辣,并不斷將該值賦給對象的屬性,從而實現(xiàn)該對象在該屬性上的動畫效果扬霜。
1)ValueAnimator:通過不斷控制值的變化(初始值->結(jié)束值),將值手動賦值給對象的屬性而涉,再不斷調(diào)用View的invalidate()方法著瓶,去不斷onDraw重繪view,達到動畫的效果婴谱。
主要的三種方法:
a) ValueAnimator.ofInt(int values):估值器是整型估值器IntEaluator
b) ValueAnimator.ofFloat(float values):估值器是浮點型估值器FloatEaluator
c) ValueAnimator.ofObject(ObjectEvaluator, start, end):將初始值以對象的形式過渡到結(jié)束值蟹但,通過操作對象實現(xiàn)動畫效果,需要實現(xiàn)Interpolator接口谭羔,自定義估值器 ?
估值器TypeEvalutor华糖,設(shè)置動畫如何從初始值過渡到結(jié)束值的邏輯。插值器(Interpolator)決定值的變化模式(勻速瘟裸、加速等);估值器(TypeEvalutor)決定值的具體變化數(shù)值客叉。
??? // 自定義估值器,需要實現(xiàn)TypeEvaluator接口
??? public class ObjectEvaluator implements TypeEvaluator{ ?
??? // 復(fù)寫evaluate()话告,在evaluate()里寫入對象動畫過渡的邏輯
??????? @Override ?
??????? public Object evaluate(float fraction, Object startValue, Object endValue) { ?
??????????? // 參數(shù)說明
??????????? // fraction:表示動畫完成度(根據(jù)它來計算當(dāng)前動畫的值)
??????????? // startValue兼搏、endValue:動畫的初始值和結(jié)束值
??????????? ... // 寫入對象動畫過渡的邏輯
??????????? return value; ?
??????????? // 返回對象動畫過渡的邏輯計算后的值
??????? }
2) ObjectAnimator:直接對對象的屬性值進行改變操作,從而實現(xiàn)動畫效果
ObjectAnimator繼承自ValueAnimator類沙郭,底層的動畫實現(xiàn)機制還是基本值的改變佛呻。它是不斷控制值的變化,再不斷自動賦給對象的屬性病线,從而實現(xiàn)動畫效果吓著。這里的自動賦值,是通過調(diào)用對象屬性的set/get方法進行自動賦值送挑,屬性動畫初始值如果有就直接取绑莺,沒有則調(diào)用屬性的get()方法獲取,當(dāng)值更新變化時惕耕,通過屬性的set()方法進行賦值纺裁。每次賦值都是調(diào)用view的postInvalidate()/invalidate()方法不斷刷新視圖(實際調(diào)用了onDraw()方法進行了重繪視圖)。
??? //Object 需要操作的對象司澎; propertyName 需要操作的對象的屬性欺缘; values動畫初始值&結(jié)束值,
??? //如果是兩個值惭缰,則從a->b值過渡浪南,如果是三值,則從a->b->c
??? ObjectAnimator animator = ObjectAnimator.ofFloat(Object object, String propertyName, float ...values);
如果采用ObjectAnimator類實現(xiàn)動畫漱受,操作的對象的屬性必須有g(shù)et()和set()方法络凿。
其他用法:
1)AnimatorSet組合動畫
??? AnimatorSet.play(Animator anim)?? :播放當(dāng)前動畫
??? AnimatorSet.after(long delay)?? :將現(xiàn)有動畫延遲x毫秒后執(zhí)行
??? AnimatorSet.with(Animator anim)?? :將現(xiàn)有動畫和傳入的動畫同時執(zhí)行
??? AnimatorSet.after(Animator anim)?? :將現(xiàn)有動畫插入到傳入的動畫之后執(zhí)行
??? AnimatorSet.before(Animator anim) :? 將現(xiàn)有動畫插入到傳入的動畫之前執(zhí)行
2) ViewPropertyAnimator直接對屬性操作,View.animate()返回的是一個ViewPropertyAnimator對象昂羡,之后的調(diào)用方法都是基于該對象的操作絮记,調(diào)用每個方法返回值都是它自身的實例
View.animate().alpha(0f).x(500).y(500).setDuration(500).setInterpolator()
3)設(shè)置動畫監(jiān)聽
??? Animation.addListener(new AnimatorListener() {
????????????? @Override
????????????? public void onAnimationStart(Animation animation) {
????????????????? //動畫開始時執(zhí)行
????????????? }
?????????????? @Override
????????????? public void onAnimationRepeat(Animation animation) {
????????????????? //動畫重復(fù)時執(zhí)行
????????????? }
???????????? @Override
????????????? public void onAnimationCancel()(Animation animation) {
????????????????? //動畫取消時執(zhí)行
????????????? }
????????????? @Override
????????????? public void onAnimationEnd(Animation animation) {
????????????????? //動畫結(jié)束時執(zhí)行
????????????? }
????????? });
2、補間動畫實現(xiàn)原理
主要有四種AlpahAnimation\ ScaleAnimation\ RotateAnimation\ TranslateAnimation四種虐先,對透明度怨愤、縮放、旋轉(zhuǎn)蛹批、位移四種動畫撰洗。在調(diào)用View.startAnimation時篮愉,先調(diào)用View.setAnimation(Animation)方法給自己設(shè)置一個Animation對象,再調(diào)用invalidate來重繪自己差导。在View.draw(Canvas, ViewGroup, long)方法中進行了getAnimation(), 并調(diào)用了drawAnimation(ViewGroup, long, Animation, boolean)方法试躏,此方法調(diào)用Animation.getTranformation()方法,再調(diào)用applyTranformation()方法设褐,該方法中主要是對Transformation.getMatrix().setTranslate/setRotate/setAlpha/setScale來設(shè)置相應(yīng)的值颠蕴,這個方法系統(tǒng)會以60FPS的頻率進行調(diào)用。具體是在調(diào)Animation.start()方法中會調(diào)用animationHandler.start()方法助析,從而調(diào)用了scheduleAnimation()方法犀被,這里會調(diào)用mChoreographer.postCallback(Choregrapher.CALLBACK_ANIMATION, this, null)放入事件隊列中,等待doFrame()來消耗事件外冀。
當(dāng)一個 ChildView 要重畫時寡键,它會調(diào)用其成員函數(shù) invalidate() 函數(shù)將通知其 ParentView 這個 ChildView 要重畫,這個過程一直向上遍歷到 ViewRoot雪隧,當(dāng) ViewRoot 收到這個通知后就會調(diào)用ViewRoot 中的 draw 函數(shù)從而完成繪制昌腰。View::onDraw() 有一個畫布參數(shù) Canvas, 畫布顧名思義就是畫東西的地方,Android 會為每一個 View 設(shè)置好畫布膀跌,View 就可以調(diào)用 Canvas 的方法遭商,比如:drawText, drawBitmap, drawPath 等等去畫內(nèi)容。每一個 ChildView 的畫布是由其 ParentView 設(shè)置的捅伤,ParentView 根據(jù) ChildView 在其內(nèi)部的布局來調(diào)整 Canvas劫流,其中畫布的屬性之一就是定義和 ChildView 相關(guān)的坐標(biāo)系,默認(rèn)是橫軸為 X 軸丛忆,從左至右祠汇,值逐漸增大,豎軸為 Y 軸熄诡,從上至下可很,值逐漸增大。
?a?£?? ?3?
Android 補間動畫就是通過 ParentView 來不斷調(diào)整 ChildView 的畫布坐標(biāo)系來實現(xiàn)的凰浮,在ParentView的dispatchDraw方法會被調(diào)用我抠。
??? dispatchDraw()
??? {
??? ....
??? Animation a = ChildView.getAnimation()
??? Transformation tm = a.getTransformation();
??? Use tm to set ChildView's Canvas;
??? Invalidate();
??? ....
??? }
這里有兩個類:Animation 和 Transformation,這兩個類是實現(xiàn)動畫的主要的類袜茧,Animation 中主要定義了動畫的一些屬性比如開始時間菜拓、持續(xù)時間、是否重復(fù)播放等笛厦,這個類主要有兩個重要的函數(shù):getTransformation 和 applyTransformation纳鼎,在 getTransformation 中 Animation 會根據(jù)動畫的屬性來產(chǎn)生一系列的差值點,然后將這些差值點傳給 applyTransformation,這個函數(shù)將根據(jù)這些點來生成不同的 Transformation贱鄙,Transformation 中包含一個矩陣和 alpha 值劝贸,矩陣是用來做平移、旋轉(zhuǎn)和縮放動畫的逗宁,而 alpha 值是用來做 alpha 動畫的(簡單理解的話悬荣,alpha 動畫相當(dāng)于不斷變換透明度或顏色來實現(xiàn)動畫),調(diào)用 dispatchDraw 時會調(diào)用 getTransformation 來得到當(dāng)前的 Transformation疙剑。某一個 View 的動畫的繪制并不是由他自己完成的而是由它的父 view 完成。
1)補間動畫TranslateAnimation,View位置移動了践叠,可是點擊區(qū)域還在原來的位置言缤,為什么?
View在做動畫是禁灼,根據(jù)動畫時間的插值管挟,計算出一個Matrix,不停的invalidate弄捕,在onDraw中的Canvas上使用這個計算出來的Matrix去draw view的內(nèi)容僻孝。某個view的動畫繪制并不是由它自己完成,而是由它的父view完成守谓,使它的父view畫布進行了移動穿铆,而點擊時還是點擊原來的畫布。使得它看起來變化了斋荞。
參考文章:Android 動畫框架詳解荞雏,第 1 部分
3、Android各個版本API的區(qū)別
Android API版本對照表及各個版本特性簡單描述
主要記住一些大版本變化:
android3.0 代號Honeycomb, 引入Fragments, ActionBar,屬性動畫平酿,硬件加速
android4.0 代號Ice Cream凤优,API14:截圖功能,人臉識別蜈彼,虛擬按鍵筑辨,3D優(yōu)化驅(qū)動
android5.0 代號Lollipop API21:調(diào)整桌面圖標(biāo)及部件透明度等
android6.0 代號M Marshmallow API23,軟件權(quán)限管理幸逆,安卓支付棍辕,指紋支持,App關(guān)聯(lián)还绘,
android7.0 代號N Preview API24痢毒,多窗口支持(不影響Activity生命周期),增加了JIT編譯器蚕甥,引入了新的應(yīng)用簽名方案APK Signature Scheme v2(縮短應(yīng)用安裝時間和更多未授權(quán)APK文件更改保護),嚴(yán)格了權(quán)限訪問
android8.0 代號O? API26哪替,取消靜態(tài)廣播注冊,限制后臺進程調(diào)用手機資源菇怀,桌面圖標(biāo)自適應(yīng)
android9.0 代號P API27凭舶,加強電池管理晌块,系統(tǒng)界面添加了Home虛擬鍵,提供人工智能API帅霜,支持免打擾模式
4匆背、Requestlayout,onlayout身冀,onDraw钝尸,DrawChild區(qū)別與聯(lián)系
requestLayout()方法 :會導(dǎo)致調(diào)用measure()過程 和 layout()過程 。 說明:只是對View樹重新布局layout過程包括measure()和layout()過程搂根,如果view的l,t,r,b沒有必變珍促,那就不會觸發(fā)onDraw;但是如果這次刷新是在動畫里剩愧,mDirty非空猪叙,就會導(dǎo)致onDraw。
onLayout()方法(如果該View是ViewGroup對象仁卷,需要實現(xiàn)該方法穴翩,對每個子視圖進行布局)
onDraw()方法繪制視圖本身 (每個View都需要重載該方法,ViewGroup不需要實現(xiàn)該方法)
drawChild()去重新回調(diào)每個子視圖的draw()方法
5锦积、invalidate和postInvalidate的區(qū)別及使用
View.invalidate(): 層層上傳到父級芒帕,直到傳遞到ViewRootImpl后觸發(fā)了scheduleTraversals(),然后整個View樹開始重新按照View繪制流程進行重繪任務(wù)丰介。
invalidate:在ui線程刷新view
postInvalidate:在工作線程刷新view(底層還是handler)其實它的原理就是invalidate+handler
View.postInvalidate最終會調(diào)用ViewRootImpl.dispatchInvalidateDelayed()方法
??? public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
??????????? Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
??????????? mHandler.sendMessageDelayed(msg, delayMilliseconds);
??????? }
這里的mHandler是ViewRootHandler實例副签,在該Handler的handleMessage方法中調(diào)用了view.invalidate()方法。
??? case MSG_INVALIDATE:
??????????????????????? ((View) msg.obj).invalidate();
??????????????????????? break;
6基矮、Activity-Window-View三者的差別
Activity:是安卓四大組件之一淆储,負(fù)責(zé)界面展示、用戶交互與業(yè)務(wù)邏輯處理家浇;
Window:就是負(fù)責(zé)界面展示以及交互的職能部門本砰,就相當(dāng)于Activity的下屬,Activity的生命周期方法負(fù)責(zé)業(yè)務(wù)的處理钢悲;
View:就是放在Window容器的元素点额,Window是View的載體,View是Window的具體展示莺琳。
三者的關(guān)系: Activity通過Window來實現(xiàn)視圖元素的展示还棱,window可以理解為一個容器,盛放著一個個的view惭等,用來執(zhí)行具體的展示工作珍手。
7、談?wù)剬olley的理解
8、如何優(yōu)化自定義View
1)在要在onDraw或是onLayout()中去創(chuàng)建對象琳要,因為onDraw()方法可能會被頻繁調(diào)用寡具,可以在view的構(gòu)造函數(shù)中進行創(chuàng)建對象;
2)降低view的刷新頻率稚补,盡可能減少不必要的調(diào)用invalidate()方法童叠。或是調(diào)用帶四種參數(shù)不同類型的invalidate()课幕,而不是調(diào)用無參的方法厦坛。無參變量需要刷新整個view,而帶參數(shù)的方法只需刷新指定部分的view乍惊。在onDraw()方法中減少冗余代碼杜秸。
3)使用硬件加速,GPU硬件加速可以帶來性能增加污桦。
4)狀態(tài)保存與恢復(fù),如果因內(nèi)存不足匙监,Activity置于后臺被殺重啟時凡橱,View應(yīng)盡可能保存自己屬性,可以重寫onSaveInstanceState和onRestoreInstanceState方法亭姥,狀態(tài)保存稼钩。
9、低版本SDK如何實現(xiàn)高版本api达罗?
使用@TargetApi注解·
當(dāng)代碼中有比AndroidManifest中設(shè)置的android:minSdkVersion版本更高的方法坝撑,此時編譯器會提示警告,解決方法是在方法上加上@SuppressLint("NewApi")或者@TargetApi()粮揉。但它們僅是屏蔽了android lint錯誤巡李,在方法中還要判斷版本做不同的操作。
@SuppressLint("NewApi")屏蔽一切新api中才能使用的方法報的android lint錯誤
@TargetApi() 只屏蔽某一新api中才能使用的方法報的android lint錯誤扶认,如@TargetApi(11)如果在方法中用了只有API14才開始有的方法侨拦,還是會報錯。
10辐宾、描述一次網(wǎng)絡(luò)請求的流程
1)域名解析
瀏覽器會先搜索自身DNS緩存且對應(yīng)的IP地址沒有過期狱从;若未找到則搜索操作系統(tǒng)自身的DNS緩存;若還未找到則讀本地的hotsts文件叠纹;還未找到會在TCP/IP設(shè)置的本地DNS服務(wù)器上找季研,如果要查詢的域名在本地配置的區(qū)域資源中,則完成解析誉察;否則根據(jù)本地DNS服務(wù)器會請求根DNS服務(wù)器与涡;根DNS服務(wù)器是13臺根DNS,會一級一級往下找。
2)TCP三次握手
客戶端先發(fā)送SYN=1递沪,ACK=0豺鼻,序列號seq=x報文;(SYN在連接建立時用來同步序號款慨,SYN=1儒飒,ACK=0代表這是一個連接請求報文,對方若同意建立連接檩奠,則應(yīng)在響應(yīng)報文中使SYN=1桩了,ACK=1)
服務(wù)器返回SYN=1稿辙,ACK=1斥废,seq=y, ack=x+1;
客戶端再一次確認(rèn)怨绣,但不用SYN了整胃,回復(fù)服務(wù)端, ACK=1, seq=x+1, ack=y+1
3)建立TCP連接后發(fā)起HTTP請求
客戶端按照指定的格式開始向服務(wù)端發(fā)送HTTP請求颗圣,HTTP請求格式由四部分組成,分別是請求行屁使、請求頭在岂、空行、消息體蛮寂,服務(wù)端接收到請求后蔽午,解析HTTP請求,處理完成邏輯酬蹋,最后返回一個具有標(biāo)準(zhǔn)格式的HTTP響應(yīng)給客戶端及老。
4)服務(wù)器響應(yīng)HTTP請求
服務(wù)器接收處理完請求后返回一個HTTP響應(yīng)消息給客戶端,HTTP響應(yīng)信息格式包括:狀態(tài)行范抓、響應(yīng)頭骄恶、空行、消息體
5)瀏覽器解析HTML代碼匕垫,請求HTML代碼中的資源
瀏覽器拿到html文件后叠蝇,就開始解析其中的html代碼,遇到j(luò)s/css/image等靜態(tài)資源時年缎,向服務(wù)器發(fā)起一個http請求悔捶,如果返回304狀態(tài)碼,瀏覽器會直接讀取本地的緩存文件单芜。否則開啟線程向服務(wù)器請求下載蜕该。
6)瀏覽器對頁面進行渲染并呈現(xiàn)給用戶
7)TCP的四次揮手
當(dāng)客戶端沒有東西要發(fā)送時就要釋放連接(提出中斷連接可以是Client也可以是Server),客戶端會發(fā)送一個FIN=1的沒有數(shù)據(jù)的報文洲鸠,進入FIN_WAIT狀態(tài)堂淡,服務(wù)端收到后會給客戶端一個確認(rèn)馋缅,此時客戶端不能發(fā)送數(shù)據(jù),但可接收信息绢淀。
11萤悴、HttpUrlConnection 和 okhttp關(guān)系
兩者都可以用來實現(xiàn)網(wǎng)絡(luò)請求,android4.4之后的HttpUrlConnection的實現(xiàn)是基于okhttp
??? Bitmap對象的理解
??? looper架構(gòu)
??? ActivityThread皆的,AMS覆履,WMS的工作原理
??? 自定義View如何考慮機型適配
在onMeasure()的getDefaultSize()的默認(rèn)實現(xiàn)中,當(dāng)view的測量模式是AT_MOST或EXACTLY時费薄,View的大小都會被設(shè)置成子View MeasureSpec的specSize.子view的MeasureSpec值是根據(jù)子View的布局參數(shù)和父容器的MeasureSpec值計算得來硝全。當(dāng)子view的布局參數(shù)是wrap_content時,對應(yīng)的測量模式是AT_MOST楞抡,大小是parentSize,
??? 自定義View的事件
??? AstncTask+HttpClient 與 AsyncHttpClient有什么區(qū)別伟众?
??? LaunchMode應(yīng)用場景
??? AsyncTask 如何使用?
??? SpareArray原理
??? 請介紹下ContentProvider 是如何實現(xiàn)數(shù)據(jù)共享的?
??? AndroidService與Activity之間通信的幾種方式
??? IntentService原理及作用是什么召廷?
原理:IntentService是繼承Service的一個抽象類凳厢,它在onCreate()方法中創(chuàng)建了一個HandlerThread,并啟動該線程。HandlerThread是帶有自己消息隊列和Looper的線程竞慢,根據(jù)HandlerThread的looper創(chuàng)建一個Handler先紫,這樣IntentService的ServiceHandler的handleMessage()方法就運行在子線程中。handleMessage中調(diào)用了onHandleIntent()方法梗顺,它是一個抽象方法泡孩,繼承IntentService類需要實現(xiàn)該方法车摄,把耗時操作放在onHandleIntent()方法中寺谤,等耗時操作運行完成后,會調(diào)用stopSelf()方法吮播,服務(wù)會調(diào)用onDestory()方法消毀自己变屁。如果onHandleIntent()中的耗時操作未運行完前就調(diào)用了stopSelf()方法,服務(wù)調(diào)用onDestory()方法意狠,但耗時操作會繼續(xù)運行粟关,直至運行完畢。如果同時多次啟動IntentService环戈,任務(wù)會放在一個隊列中闷板,onCreate()和onDestory()方法都只會運行一次。
作用:用來處理后臺耗時操作院塞,如讀取數(shù)據(jù)庫或是本地文件等遮晚。
??? 說說Activity、Intent拦止、Service 是什么關(guān)系
??? ApplicationContext和ActivityContext的區(qū)別
??? SP是進程同步的嗎?有什么方法做到同步县遣?
??? 談?wù)劧嗑€程在Android中的使用
??? 進程和 Application 的生命周期
??? 封裝View的時候怎么知道view的大小
??? RecycleView原理
??? AndroidManifest的作用與理解
(三)常見的一些原理性問題
??? Handler機制和底層實現(xiàn)
??? Handler糜颠、Thread和HandlerThread的差別
1)Handler線程的消息通訊的橋梁,主要用來發(fā)送消息及處理消息萧求。
2)Thread普通線程其兴,如果需要有自己的消息隊列,需要調(diào)用Looper.prepare()創(chuàng)建Looper實例夸政,調(diào)用loop()去循環(huán)消息元旬。
3)HandlerThread是一個帶有Looper的線程,在HandleThread的run()方法中調(diào)用了Looper.prepare()創(chuàng)建了Looper實例秒梳,并調(diào)用Looper.loop()開啟了Loop循環(huán)法绵,循環(huán)從消息隊列中獲取消息并交由Handler處理。利用該線程的Looper創(chuàng)建Handler實例酪碘,此Handler的handleMessage()方法是運行在子線程中的朋譬。即Handler利用哪個線程的Looper創(chuàng)建的實例,它就和相應(yīng)的線程綁定到一起兴垦,處理該線程上的消息徙赢,它的handleMessage()方法就是在那個線程中運行的,無參構(gòu)造默認(rèn)是主線程探越。HandlerThread提供了quit()/quitSafely()方法退出HandlerThread的消息循環(huán)狡赐,它們分別調(diào)用Looper的quit和quitSafely方法,quit會將消息隊列中的所有消息移除钦幔,而quitSafely會將消息隊列所有延遲消息移除枕屉,非延遲消息派發(fā)出去讓Handler去處理。
HandlerThread適合處理本地IO讀寫操作(讀寫數(shù)據(jù)庫或文件)鲤氢,因為本地IO操作耗時不長搀擂,對于單線程+異步隊列不會產(chǎn)生較大阻塞,而網(wǎng)絡(luò)操作相對比較耗時卷玉,容易阻塞后面的請求哨颂,因此HandlerThread不適合加入網(wǎng)絡(luò)操作。
??? handler發(fā)消息給子線程相种,looper怎么啟動威恼?
??? 關(guān)于Handler,在任何地方new Handler 都是什么線程下?
??? ThreadLocal原理寝并,實現(xiàn)及如何保證Local屬性箫措?
??? 請解釋下在單線程模型中Message、Handler衬潦、Message Queue斤蔓、Looper之間的關(guān)系
??? 請描述一下View事件傳遞分發(fā)機制
??? Touch事件傳遞流程
??? 事件分發(fā)中的onTouch 和onTouchEvent 有什么區(qū)別,又該如何使用别渔?
??? View和ViewGroup分別有哪些事件分發(fā)相關(guān)的回調(diào)方法
??? View刷新機制
??? View繪制流程
??? 自定義控件原理
??? 自定義View如何提供獲取View屬性的接口附迷?
??? Android代碼中實現(xiàn)WAP方式聯(lián)網(wǎng)
??? AsyncTask機制
??? AsyncTask原理及不足
??? 如何取消AsyncTask惧互?
??? 為什么不能在子線程更新UI?
??? ANR產(chǎn)生的原因是什么喇伯?
??? ANR定位和修正
??? oom是什么喊儡?
oom(Out Of Memory)內(nèi)存溢出,
??? 什么情況導(dǎo)致oom稻据?
??? 有什么解決方法可以避免OOM艾猜?
??? Oom 是否可以try catch?為什么捻悯?
可以匆赃,當(dāng)
??? 內(nèi)存泄漏是什么?
內(nèi)存泄露就是指該被GC垃圾回收的今缚,但被一個生命周期比它長的對象仍然在引用它算柳,導(dǎo)致無法回收,造成內(nèi)存泄露姓言,過多的內(nèi)存泄露會導(dǎo)致OOM瞬项。
??? 什么情況導(dǎo)致內(nèi)存泄漏?
1)非靜態(tài)內(nèi)部類何荚、匿名內(nèi)部類:非靜態(tài)內(nèi)部類囱淋、匿名內(nèi)部類 都會持有外部類的一個引用,如果有一個靜態(tài)變量引用了非靜態(tài)內(nèi)部類或者匿名內(nèi)部類餐塘,導(dǎo)致非靜態(tài)內(nèi)部類或者匿名內(nèi)部類的生命周期比外部類(Activity)長妥衣,就會導(dǎo)致外部類在該被回收的時候,無法被回收掉戒傻,引起內(nèi)存泄露, 除非外部類被卸載税手。
解決辦法:將非靜態(tài)內(nèi)部類、匿名內(nèi)部類 改成靜態(tài)內(nèi)部類稠鼻,或者直接抽離成一個外部類冈止。 如果在靜態(tài)內(nèi)部類中狂票,需要引用外部類對象候齿,那么可以將這個引用封裝在一個WeakReference中。
2)靜態(tài)的View:當(dāng)一個Activity經(jīng)常啟動闺属,但是對應(yīng)的View讀取非常耗時慌盯,我們可以通過靜態(tài)View變量來保持對該Activity的rootView引用。這樣就可以不用每次啟動Activity都去讀取并渲染View了掂器。但View attach到我們的Window上亚皂,就會持有一個Context(即Activity)的引用。而我們的View有事一個靜態(tài)變量灭必,所以導(dǎo)致Activity不被回收。
解決辦法: 在使用靜態(tài)View時,需要確保在資源回收時,將靜態(tài)View detach掉减响。
3)Handler:在Activity中定義Handler對象,那么Handler持有Activty的引用据途。而每個Message對象是持有Handler的引用的(Message對象的target屬性持有Handler引用),從而導(dǎo)致Message間接引用到了Activity佛致。如果在Activty destroy之后罐脊,消息隊列中還有Message對象,Activty是不會被回收的辛块。
解決辦法: 將Handler放入單獨的類或者將Handler放入到靜態(tài)內(nèi)部類中(靜態(tài)內(nèi)部類不會持有外部類的引用)。如果想要在handler內(nèi)部去調(diào)用所在的外部類Activity,可以在handler內(nèi)部使用弱引用的方式指向所在Activity配紫,在onDestory時,調(diào)用相應(yīng)的方法移除回調(diào)和刪除消息籽懦。
4)監(jiān)聽器(各種需要注冊的Listener拖云,Watcher等):當(dāng)我們需要使用系統(tǒng)服務(wù)時汇荐,比如執(zhí)行某些后臺任務(wù)、為硬件訪問提供接口等等系統(tǒng)服務(wù)。我們需要把自己注冊到服務(wù)的監(jiān)聽器中言秸。然而俱恶,這會讓服務(wù)持有 activity 的引用,如果程序員忘記在 activity 銷毀時取消注冊玫锋,那就會導(dǎo)致 activity 泄漏了键思。
解決辦法:在onDestory中移除注冊
5. 資源對象沒關(guān)閉造成內(nèi)存泄漏:當(dāng)我們打開資源時,一般都會使用緩存纽竣。比如讀寫文件資源嗜侮、打開數(shù)據(jù)庫資源覆醇、使用Bitmap資源等等。當(dāng)我們不再使用時党瓮,應(yīng)該關(guān)閉它們瓷翻,使得緩存內(nèi)存區(qū)域及時回收敢朱。
解決辦法:使用try finally結(jié)合剪菱,在try塊中打開資源,在finally中關(guān)閉資源
6. 屬性動畫:在使用ValueAnimator或者ObjectAnimator時拴签,如果沒有及時做cancel取消動畫孝常,就可能造成內(nèi)存泄露。因為在cancel方法里蚓哩,最后調(diào)用了endAnimation(); 茫因,在endAnimation里,有個AnimationHandler的單例杖剪,會持有屬性動畫對象的引用冻押。
解決辦法:在onDestory中調(diào)用動畫的cancel方法
7. RxJava:在使用RxJava時,如果在發(fā)布了一個訂閱后盛嘿,由于沒有及時取消洛巢,導(dǎo)致Activity/Fragment無法銷毀,導(dǎo)致的內(nèi)存泄露次兆。
解決辦法:使用RxLifeCycle
??? 內(nèi)存泄漏和內(nèi)存溢出區(qū)別稿茉?
(1)內(nèi)存泄漏
1)內(nèi)存泄漏:指程序中已動態(tài)分配的堆內(nèi)存由于某種原因未釋放或無法釋放,造成系統(tǒng)內(nèi)存的浪費,導(dǎo)致程序運行速度減慢甚至系統(tǒng)奔潰等嚴(yán)重后果漓库。
2)一次內(nèi)存泄漏似乎不會有大的影響恃慧,但內(nèi)存泄漏后堆積的結(jié)果就是內(nèi)存溢出。
3)內(nèi)存泄漏具有隱蔽性渺蒿,積累性的特征痢士,比其他內(nèi)存非法訪問錯誤更難檢測。這是因為內(nèi)存泄漏產(chǎn)生的原因是內(nèi)存塊未被釋放茂装,屬于遺漏型缺陷而不是過錯型缺陷怠蹂。此外,內(nèi)存泄漏不會直接產(chǎn)生可觀察的錯誤少态,而是逐漸積累城侧,降低系統(tǒng)的整體性性能。
4)如何有效的進行內(nèi)存分配和釋放彼妻,防止內(nèi)存泄漏嫌佑,是軟件開發(fā)人員的關(guān)鍵問題,比如一個服務(wù)器應(yīng)用軟件要長時間服務(wù)多個客戶端侨歉,若存在內(nèi)存泄漏屋摇,則會逐漸堆積,導(dǎo)致一系列嚴(yán)重后果为肮。
(2)內(nèi)存溢出
指程序在申請內(nèi)存時摊册,沒有足夠的內(nèi)存供申請者使用,或者說颊艳,給了你一塊存儲int類型數(shù)據(jù)的存儲空間茅特,但是你卻存儲long類型的數(shù)據(jù),就會導(dǎo)致內(nèi)存不夠用棋枕,報錯OOM白修,即出現(xiàn)內(nèi)存溢出的錯誤。
??? LruCache默認(rèn)緩存大小
4MB
??? ContentProvider的權(quán)限管理(解答:讀寫分離重斑,權(quán)限控制-精確到表級兵睛,URL控制)
??? 如何通過廣播攔截和abort一條短信?
??? 廣播是否可以請求網(wǎng)絡(luò)窥浪?
??? 廣播引起anr的時間限制是多少祖很?
??? 計算一個view的嵌套層級
??? Activity棧
??? Android線程有沒有上限?
理論上是沒有上限的漾脂,但按一般寫法一般是線程最多開到2*CPU個數(shù)+1
??? 線程池有沒有上限假颇?
要根據(jù)用戶調(diào)用不同的線程池構(gòu)造函數(shù)。
??? ListView重用的是什么骨稿?
??? Android為什么引入Parcelable笨鸡?
??? 有沒有嘗試簡化Parcelable的使用姜钳?
(四)開發(fā)中常見的一些問題
??? ListView 中圖片錯位的問題是如何產(chǎn)生的?
??? 混合開發(fā)有了解嗎?
??? 知道哪些混合開發(fā)的方式形耗?說出它們的優(yōu)缺點和各自使用場景哥桥?(解答:比如:RN,weex激涤,H5拟糕,小程序,WPA等昔期。做Android的了解一些前端js等還是很有好處的)已卸;
??? 屏幕適配的處理技巧都有哪些?
??? 服務(wù)器只提供數(shù)據(jù)接收接口佛玄,在多線程或多進程條件下硼一,如何保證數(shù)據(jù)的有序到達?
??? 動態(tài)布局的理解
??? 怎么去除重復(fù)代碼梦抢?
??? 畫出 Android 的大體架構(gòu)圖
??? Recycleview和ListView的區(qū)別
??? ListView圖片加載錯亂的原理和解決方案
ListView item緩存機制:為了使得性能更優(yōu)般贼,ListView會緩存行item(某行對應(yīng)的View)。ListView通過adapter的getView函數(shù)獲得每行的item奥吩『咔滑動過程中,1)如果某行item已經(jīng)滑出屏幕霞赫,若該item不在緩存內(nèi)腮介,則put進緩存,否則更新緩存端衰;
2)獲取滑入屏幕的行item之前會先判斷緩存中是否有可用的item叠洗,如果有,做為convertView參數(shù)傳遞給adapter的getView旅东。
出現(xiàn)的問題:
1)行item圖片顯示重復(fù)灭抑,當(dāng)前行item顯示了之前某行item的圖片。
比如ListView滑動到第2行會異步加載某個圖片抵代,但是加載很慢腾节,加載過程中l(wèi)istView已經(jīng)滑動到了第14行,且滑動過程中該圖片加載結(jié)束荤牍,第2行已不在屏幕內(nèi)珊搀,根據(jù)上面介紹的緩存原理,第2行的view可能被第14行復(fù)用谱轨,這樣我們看到的就是第14行顯示了本該屬于第2行的圖片拣播,造成顯示重復(fù)。
2)行item圖片顯示閃爍
如果第14行圖片又很快加載結(jié)束涎才,所以我們看到第14行先顯示了第2行的圖片鞋既,立馬又顯示了自己的圖片進行覆蓋造成閃爍錯亂力九。
解決方法
通過上面的分析我們知道了出現(xiàn)錯亂的原因是異步加載及對象被復(fù)用造成的,如果每次getView能給對象一個標(biāo)識邑闺,在異步加載完成時比較標(biāo)識與當(dāng)前行item的標(biāo)識是否一致跌前,一致則顯示,否則不做處理即可陡舅。
??? 動態(tài)權(quán)限適配方案抵乓,權(quán)限組的概念
??? Android系統(tǒng)為什么會設(shè)計ContentProvider?
??? 下拉狀態(tài)欄是不是影響activity的生命周期
??? 如果在onStop的時候做了網(wǎng)絡(luò)請求靶衍,onResume的時候怎么恢復(fù)灾炭?
??? Bitmap 使用時候注意什么?
??? Bitmap的recycler()
??? Android中開啟攝像頭的主要步驟
??? ViewPager使用細(xì)節(jié)颅眶,如何設(shè)置成每次只初始化當(dāng)前的Fragment蜈出,其他的不初始化?
??? 點擊事件被攔截涛酗,但是想傳到下面的View铡原,如何操作?
??? 微信主頁面的實現(xiàn)方式
??? 微信上消息小紅點的原理
??? CAS介紹
三商叹、混合開發(fā)面試題
大廠除了技術(shù)深度之外燕刻,還要求你具備一些廣度的知識,比如你要會前端知識剖笙,會混合開發(fā)卵洗,至少會一種腳本語言,C c++更不用說了弥咪,也是必會的过蹂。
??? Hybrid做過嗎?
??? Hybrid通信原理是什么酪夷,有做研究嗎榴啸?
??? react native有多少了解?講一下原理晚岭。
??? weex了解嗎鸥印?如何自己實現(xiàn)類似技術(shù)?
??? flutter了解嗎坦报?內(nèi)部是如何實現(xiàn)跨平臺的库说?
??? Dart語言有研究貴嗎?
??? 快應(yīng)用了解嗎片择?跟其她方式相比有什么優(yōu)缺點潜的?
??? 說說你用過的混合開發(fā)技術(shù)有哪些?各有什么優(yōu)缺點字管?
??? Python會嗎啰挪?
??? 會不會PHP信不?
??? Gradle了解多少?groovy語法會嗎亡呵?
四抽活、高端技術(shù)面試題
這里講的是大公司需要用到的一些高端Android技術(shù),這里專門整理了一個文檔锰什,希望大家都可以看看下硕。這些題目有點技術(shù)含量,需要好點時間去研究一下的汁胆。
(一)圖片
1梭姓、圖片庫對比
2、LRUCache原理
LruCache是個泛型類嫩码,主要原理是:把最近使用的對象用強引用存儲在LinkedHashMap中誉尖,當(dāng)緩存滿時,把最近最少使用的對象從內(nèi)存中移除谢谦,并提供get/put方法完成緩存的獲取和添加释牺。LruCache是線程安全的萝衩,因為使用了synchronized關(guān)鍵字回挽。
當(dāng)調(diào)用put()方法,將元素加到鏈表頭猩谊,如果鏈表中沒有該元素千劈,大小不變,如果沒有牌捷,需調(diào)用trimToSize方法判斷是否超過最大緩存量墙牌,trimToSize()方法中有一個while(true)死循環(huán),如果緩存大小大于最大的緩存值,會不斷刪除LinkedHashMap中隊尾的元素暗甥,即最少訪問的喜滨,直到緩存大小小于最大緩存值。當(dāng)調(diào)用LruCache的get方法時撤防,LinkedHashMap會調(diào)用recordAccess方法將此元素加到鏈表頭部虽风。
3、圖片加載原理
4寄月、自己去實現(xiàn)圖片庫辜膝,怎么做?
5漾肮、Glide源碼解析
1)Glide.with(context)創(chuàng)建了一個RequestManager厂抖,同時實現(xiàn)加載圖片與組件生命周期綁定:在Activity上創(chuàng)建一個透明的ReuqestManagerFragment加入到FragmentManager中,通過添加的Fragment感知Activty\Fragment的生命周期克懊。因為添加到Activity中的Fragment會跟隨Activity的生命周期忱辅。在RequestManagerFragment中的相應(yīng)生命周期方法中通過liftcycle傳遞給在lifecycle中注冊的LifecycleListener
2)RequestManager.load(url) 創(chuàng)建了一個RequestBuilder<T>對象 T可以是Drawable對象或是ResourceType等
3) RequestBuilder.into(view)
-->into(glideContext.buildImageViewTarget(view, transcodeClass))返回的是一個DrawableImageViewTarget, Target用來最終展示圖片的七蜘,buildImageViewTarget-->ImageViewTargetFactory.buildTarget()根據(jù)傳入class參數(shù)不同構(gòu)建不同的Target對象,這個Class是根據(jù)構(gòu)建Glide時是否調(diào)用了asBitmap()方法墙懂,如果調(diào)用了會構(gòu)建出BitmapImageViewTarget崔梗,否則構(gòu)建的是GlideDrawableImageViewTarget對象。
-->GenericRequestBuilder.into(Target),該方法進行了構(gòu)建Request垒在,并用RequestTracker.runRequest()
??? Request request = buildRequest(target);//構(gòu)建Request對象蒜魄,Request是用來發(fā)出加載圖片的,它調(diào)用了buildRequestRecursive()方法以场躯,內(nèi)部調(diào)用了GenericRequest.obtain()方法
??? target.setRequest(request);
??? lifecycle.addListener(target);
??? requestTracker.runRequest(request);//判斷Glide當(dāng)前是不是處于暫停狀態(tài)谈为,若不是則調(diào)用Request.begin()方法來執(zhí)行Request,否則將Request添加到待執(zhí)行隊列里踢关,等暫停態(tài)解除了后再執(zhí)行
-->GenericRequest.begin()
1)onSizeReady()--> Engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
??????????? priority, isMemoryCacheable, diskCacheStrategy, this) --> a)先構(gòu)建EngineKey; b) loadFromCache從緩存中獲取EngineResource伞鲫,如果緩存中獲取到cache就調(diào)用cb.onResourceReady(cached); c)如果緩存中不存在調(diào)用loadFromActiveResources從active中獲取签舞,如果獲取到就調(diào)用cb.onResourceReady(cached)秕脓;d)如果active中也不存在,調(diào)用EngineJob.start(EngineRunnable), 從而調(diào)用decodeFromSource()/decodeFromCache()-->如果是調(diào)用decodeFromSource()-->ImageVideoFetcher.loadData()-->HttpUrlFetcher()調(diào)用HttpUrlConnection進行網(wǎng)絡(luò)請求資源-->得于InputStream()后,調(diào)用decodeFromSourceData()-->loadProvider.getSourceDecoder().decode()方法解碼-->GifBitmapWrapperResourceDecoder.decode()-->decodeStream()先從流中讀取2個字節(jié)判斷是GIF還是普通圖儒搭,若是GIF調(diào)用decodeGifWrapper()來解碼吠架,若是普通靜圖則調(diào)用decodeBitmapWrapper()來解碼-->bitmapDecoder.decode()
6、Glide使用什么緩存搂鲫?
1) 內(nèi)存緩存:LruResourceCache(memory)+弱引用activeResources
Map<Key, WeakReference<EngineResource<?>>> activeResources正在使用的資源傍药,當(dāng)acquired變量大于0,說明圖片正在使用魂仍,放到activeResources弱引用緩存中拐辽,經(jīng)過release()后,acquired=0,說明圖片不再使用擦酌,會把它放進LruResourceCache中
2)磁盤緩存:DiskLruCache,這里分為Source(原始圖片)和Result(轉(zhuǎn)換后的圖片)
第一次獲取圖片俱诸,肯定網(wǎng)絡(luò)取,然后存active\disk中赊舶,再把圖片顯示出來睁搭,第二次讀取相同的圖片,并加載到相同大小的imageview中锯岖,會先從memory中取介袜,沒有再去active中獲取。如果activity執(zhí)行到onStop時出吹,圖片被回收遇伞,active中的資源會被保存到memory中,active中的資源被回收捶牢。當(dāng)再次加載圖片時鸠珠,會從memory中取巍耗,再放入active中,并將memory中對應(yīng)的資源回收渐排。
之所以需要activeResources炬太,它是一個隨時可能被回收的資源,memory的強引用頻繁讀寫可能造成內(nèi)存激增頻繁GC驯耻,而造成內(nèi)存抖動亲族。資源在使用過程中保存在activeResources中,而activeResources是弱引用可缚,隨時被系統(tǒng)回收霎迫,不會造成內(nèi)存過多使用和泄漏。
7帘靡、Glide內(nèi)存緩存如何控制大兄?
Glide內(nèi)存緩存最大空間(maxSize)=每個進程可用最大內(nèi)存*0.4(低配手機是?? 每個進程可用最大內(nèi)存*0.33)
磁盤緩存大小是250MB?? int DEFAULT_DISK_CACHE_SIZE = 250 * 1024 * 1024;
(二)網(wǎng)絡(luò)和安全機制
??? 網(wǎng)絡(luò)框架對比和源碼分析
??? 自己去設(shè)計網(wǎng)絡(luò)請求框架描姚,怎么做涩赢?
??? okhttp源碼
??? 網(wǎng)絡(luò)請求緩存處理,okhttp如何處理網(wǎng)絡(luò)緩存的
(1)網(wǎng)絡(luò)緩存優(yōu)先考慮強制緩存轩勘,再考慮對比緩存
??? 首先判斷強制緩存中的數(shù)據(jù)的是否在有效期內(nèi)筒扒。如果在有效期,則直接使用緩存赃阀。如果過了有效期霎肯,則進入對比緩存。
??? 在對比緩存過程中榛斯,判斷ETag是否有變動,如果服務(wù)端返回沒有變動搂捧,說明資源未改變驮俗,使用緩存。如果有變動允跑,判斷Last-Modified王凑。
??? 判斷Last-Modified,如果服務(wù)端對比資源的上次修改時間沒有變化聋丝,則使用緩存索烹,否則重新請求服務(wù)端的數(shù)據(jù),并作緩存工作弱睦。
(2)okhttp緩存
開啟使用Okhttp的緩存其實很簡單百姓,只需要給OkHttpClient對象設(shè)置一個Cache對象即可,創(chuàng)建一個Cache時指定緩存保存的目錄和緩存最大的大小即可况木。
??? //新建一個cache垒拢,指定目錄為外部目錄下的okhttp_cache目錄旬迹,大小為100M
??? Cache cache = new Cache(new File(Environment.getExternalStorageDirectory() + "/okhttp_cache/"), 100 * 1024 * 1024);
??? //將cache設(shè)置到OkHttpClient中,這樣緩存就開始生效了求类。
??? OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();
相關(guān)的類有:
1)CacheControl( HTTP中的Cache-Control和Pragma緩存控制):指定緩存規(guī)則
2)Cache(緩存類)
3)DiskLruCache(文件化的LRU緩存類)
(1)讀取緩存:先獲限OkHttpClient的Cache緩存對象奔垦,就是上面創(chuàng)建OkHttpClient設(shè)置的Cahce; 傳Request請求到Cache的get方法查找緩存響應(yīng)數(shù)據(jù)Response;構(gòu)造一個緩存策略尸疆,再調(diào)用它的get去決策使用網(wǎng)絡(luò)請求還是緩存響應(yīng)椿猎。若使用緩存,它的cacheResponse不為空,networkRequest為空寿弱,用緩存構(gòu)造響應(yīng)直接返回鸵贬。若使用請求,則cacheResponse為空,networkRequest不為空脖捻,開始網(wǎng)絡(luò)請求流程阔逼。
Cache的get獲取緩存方法,計算request的key值(請求url進行md5加密)地沮,根據(jù)key值去DisLruCache查找是否存在緩存內(nèi)容嗜浮,存則則創(chuàng)建繪存Entry實體。ENTRY_METADATA代表響應(yīng)頭信息摩疑,ENTRY_BODY代表響應(yīng)體信息危融。如果緩存存在,在指定目錄下會有兩個文件****.0??? *****.1分別存儲某個請求緩存響應(yīng)頭和響應(yīng)體信息雷袋。
CacheStrategy的get方法:1)若緩存響應(yīng)為空或 2)請求是https但緩存響應(yīng)沒有握手信息吉殃;3)請求和緩存響應(yīng)都是不可緩存的;4)請求是onCache楷怒,并且又包含if-Modified-Since或If-None-Match則不使用緩存蛋勺; 再計算請求有效時間是否符合響應(yīng)的過期時間,若響應(yīng)在有效范圍內(nèi)鸠删,則緩存策略使用緩存抱完,否則創(chuàng)建一個新的有條件的請求,返回有條件的緩存策略刃泡。
(2)存儲緩存流程:從HttpEngine的readResponse()發(fā)送請求開始巧娱,判斷hasBody(userResponse),如果緩存的話,maybeCache()緩存響應(yīng)頭信息烘贴,unzip(cacheWritingResponse(storeRequest, userResponse))緩存響應(yīng)體禁添。
??? 從網(wǎng)絡(luò)加載一個10M的圖片,說下注意事項
??? TCP的3次握手和四次揮手
??? TCP與UDP的區(qū)別
??? TCP與UDP的應(yīng)用
??? HTTP協(xié)議
??? HTTP1.0與2.0的區(qū)別
??? HTTP報文結(jié)構(gòu)
??? HTTP與HTTPS的區(qū)別以及如何實現(xiàn)安全性
??? 如何驗證證書的合法性?
??? https中哪里用了對稱加密桨踪,哪里用了非對稱加密老翘,對加密算法(如RSA)等是否有了解?
??? client如何確定自己發(fā)送的消息被server收到?
??? 談?wù)勀銓ebSocket的理解
??? WebSocket與socket的區(qū)別
??? 談?wù)勀銓Π沧亢灻睦斫狻?/p>
??? 請解釋安卓為啥要加簽名機制?
??? 視頻加密傳輸
??? App 是如何沙箱化,為什么要這么做?
??? 權(quán)限管理系統(tǒng)(底層的權(quán)限是如何進行 grant 的)酪捡?
(三)數(shù)據(jù)庫
??? sqlite升級叁征,增加字段的語句
??? 數(shù)據(jù)庫框架對比和源碼分析
??? 數(shù)據(jù)庫的優(yōu)化
??? 數(shù)據(jù)庫數(shù)據(jù)遷移問題
(四)算法
??? 排序算法有哪些?
??? 最快的排序算法是哪個逛薇?
??? 手寫一個冒泡排序
??? 手寫快速排序代碼
??? 快速排序的過程捺疼、時間復(fù)雜度、空間復(fù)雜度
??? 手寫堆排序
??? 堆排序過程永罚、時間復(fù)雜度及空間復(fù)雜度
??? 寫出你所知道的排序算法及時空復(fù)雜度啤呼,穩(wěn)定性
??? 二叉樹給出根節(jié)點和目標(biāo)節(jié)點,找出從根節(jié)點到目標(biāo)節(jié)點的路徑
??? 給阿里2萬多名員工按年齡排序應(yīng)該選擇哪個算法呢袱?
??? GC算法(各種算法的優(yōu)缺點以及應(yīng)用場景)
??? 蟻群算法與蒙特卡洛算法
??? 子串包含問題(KMP 算法)寫代碼實現(xiàn)
??? 一個無序官扣,不重復(fù)數(shù)組,輸出N個元素羞福,使得N個元素的和相加為M惕蹄,給出時間復(fù)雜度、空間復(fù)雜度治专。手寫算法
??? 萬億級別的兩個URL文件A和B卖陵,如何求出A和B的差集C(提示:Bit映射->hash分組->多文件讀寫效率->磁盤尋址以及應(yīng)用層面對尋址的優(yōu)化)
??? 百度POI中如何試下查找最近的商家功能(提示:坐標(biāo)鏡像+R樹)。
??? 兩個不重復(fù)的數(shù)組集合中张峰,求共同的元素泪蔫。
??? 兩個不重復(fù)的數(shù)組集合中,這兩個集合都是海量數(shù)據(jù)喘批,內(nèi)存中放不下撩荣,怎么求共同的元素?
??? 一個文件中有100萬個整數(shù)饶深,由空格分開餐曹,在程序中判斷用戶輸入的整數(shù)是否在此文件中。說出最優(yōu)的方法
??? 一張Bitmap所占內(nèi)存以及內(nèi)存占用的計算
一張圖片(bitmap)占用的內(nèi)存影響因素:圖片原始長粥喜、寬凸主,手機屏幕密度,圖片存放路徑下的密度额湘,單位像素占用字節(jié)數(shù)
bitmapSize=圖片長度*(inTargetDensity手機的density / inDensity圖片存放目錄的density)*寬度*(手機的inTargetDensity / inDensity目標(biāo)存放目錄的density)*單位像素占用的字節(jié)數(shù)(圖片長寬單位是像素)
1)圖片長寬單位是像素:單位像素字節(jié)數(shù)由其參數(shù)BitmapFactory.Options.inPreferredConfig變量決定,它是Bitmap.Config類型旁舰,包括以下幾種值:ALPHA_8圖片只有alpha值锋华,占用一個字節(jié);ARGB_4444 一個像素占用2個字節(jié),A\R\G\B各占4bits箭窜;ARGB_8888一個像素占用4個字節(jié)毯焕,A\R\G\B各占8bits(高質(zhì)量圖片格式,bitmap默認(rèn)格式);ARGB_565一個像素占用2字節(jié)纳猫,不支持透明和半透明婆咸,R占5bit, Green占6bit, Blue占用5bit. 從Android4.0開始該項無效。
2) inTargetDensity 手機的屏幕密度(跟手機分辨率有關(guān)系)
inDensity原始資源密度(mdpi:160;?? hdpi:240;?? xhdpi:320;?? xxhdpi:480; xxxhdpi:640)
當(dāng)Bitmap對象在不使用時芜辕,應(yīng)該先調(diào)用recycle()尚骄,再將它設(shè)置為null,雖然Bitmap在被回收時可通過BitmapFinalizer來回收內(nèi)存侵续。但只有系統(tǒng)垃圾回收時才會回收倔丈。Android4.0之前,Bitmap內(nèi)存分配在Native堆中状蜗,Android4.0開始需五,Bitmap的內(nèi)存分配在dalvik堆中,即Java堆中轧坎,調(diào)用recycle()并不能立即釋放Native內(nèi)存宏邮。
??? 2000萬個整數(shù),找出第五十大的數(shù)字缸血?
??? 燒一根不均勻的繩蜜氨,從頭燒到尾總共需要1個小時。現(xiàn)在有若干條材質(zhì)相同的繩子属百,問如何用燒繩的方法來計時一個小時十五分鐘呢记劝?
??? 求1000以內(nèi)的水仙花數(shù)以及40億以內(nèi)的水仙花數(shù)
??? 5枚硬幣,2正3反如何劃分為兩堆然后通過翻轉(zhuǎn)讓兩堆中正面向上的硬8幣和反面向上的硬幣個數(shù)相同
??? 時針走一圈族扰,時針分針重合幾次
??? N*N的方格紙,里面有多少個正方形
??? x個蘋果厌丑,一天只能吃一個、兩個渔呵、或者三個怒竿,問多少天可以吃完?
(五)插件化扩氢、模塊化耕驰、組件化、熱修復(fù)录豺、增量更新朦肘、Gradle
??? 對熱修復(fù)和插件化的理解
??? 插件化原理分析
??? 模塊化實現(xiàn)(好處,原因)
??? 熱修復(fù),插件化
??? 項目組件化的理解
??? 描述清點擊 Android Studio 的 build 按鈕后發(fā)生了什么
(六)架構(gòu)設(shè)計和設(shè)計模式
??? 談?wù)勀銓ndroid設(shè)計模式的理解
??? MVC MVP MVVM原理和區(qū)別
??? 你所知道的設(shè)計模式有哪些双饥?
??? 項目中常用的設(shè)計模式
??? 手寫生產(chǎn)者/消費者模式
??? 寫出觀察者模式的代碼
??? 適配器模式媒抠,裝飾者模式,外觀模式的異同咏花?
??? 用到的一些開源框架趴生,介紹一個看過源碼的,內(nèi)部實現(xiàn)過程。
??? 談?wù)剬xJava的理解
RxJava是基于響應(yīng)式編程苍匆,基于事件流刘急、實現(xiàn)異步操(類似于Android中的AsyncTask、Handler作用)作的庫浸踩,基于事件流的鏈?zhǔn)秸{(diào)用叔汁,使得RxJava邏輯簡潔、使用簡單民轴。RxJava原理是基于一種擴展的觀察者模式攻柠,有四種角色:被觀察者Observable 觀察者Observer 訂閱subscribe 事件Event。RxJava原理可總結(jié)為:被觀察者Observable通過訂閱(subscribe)按順序發(fā)送事件(Emitter)給觀察者(Observer)后裸, 觀察者按順序接收事件&作出相應(yīng)的響應(yīng)動作瑰钮。
RxJava中的操作符:
1)defer():直到有觀察者(Observer)訂閱時,才會動態(tài)創(chuàng)建被觀察者對象(Observer)&發(fā)送事件微驶,通過Observer工廠方法創(chuàng)建被觀察者對象浪谴,每次訂閱后,都會得到一個剛創(chuàng)建的最新的Observer對象因苹,可以確保Observer對象里的數(shù)據(jù)是最新的苟耻。defer()方法只會定義Observable對象,只有訂閱操作才會創(chuàng)建對象扶檐。
??? Observable<T> observable = Observable.defer(new Callable<ObservableSource<? extends T>>() {
??????? @Override
??????? public ObservableSource<? extends T> call() throws Exception {
??????????? return Observable.just();
??????? }
??? }
2)timer() 快速創(chuàng)建一個被觀察者(Observable)凶杖,延遲指定時間后,再發(fā)送事件
??? Observable.timer(2, TimeUnit.SECONDS)//也可以自定義線程timer(long, TimeUnit, Scheduler)
??????? .subscribe(new Observer<Long>() {
??????????? @Override
??????????? public void onSubscribe(Disposable d) {
??????????? }
??????????? ...
???????? });
3) interval() intervalRange() 快速創(chuàng)建一個被觀察者對象(Observable)款筑,每隔指定時間就發(fā)送事件
??? //interval三個參數(shù)智蝠,參數(shù)1:第一次延遲時間? 參數(shù)2:間隔時間數(shù)字?? 參數(shù)3:時間單位
??? Observable.interval(3, 1, TimeUnit.SECONDS).subscribe();
??? //intervalRange五個參數(shù),參數(shù)1:事件序列起始點? 參數(shù)2:事件數(shù)量? 參數(shù)3:第一次延遲時間 參數(shù)4:間隔時間數(shù)字?? 參數(shù)5:時間單位
??? Observable.intervalRange(3, 10, 2, 1, TimeUnit.SECONDS).subscribe();
??? RxJava的功能與原理實現(xiàn)
Rxjava發(fā)送事件步驟:
1)創(chuàng)建被觀察者對象Observable&定義需要發(fā)送的事件
??? Observable.create(new ObservableOnSubscribe<T>(){
??????? @Override
??????? public void subscribe(ObservableEmitter<T> emitter) throws Exception {
??????????? //定義發(fā)送事件的行為
??????? }
??? });
Observable.create()方法實際創(chuàng)建了一個ObservableCreate對象奈梳,它是Observable的子類杈湾,傳入一個ObservableOnSubscribe對象,復(fù)寫了發(fā)送事件行為的subscribe()方法攘须。
2)創(chuàng)建觀察者對象Observer&定義響應(yīng)事件的行為
??? Observer observer = new Observer<T>() {
??????? @Override
??????? public void onSubscribe(Disposable d){//Disposable對象可用于結(jié)束事件
??????????? //默認(rèn)最先調(diào)用
??????? }
??????? @Override
??????? public void onNext(T t){
??????? }
??????? @Override
??????? public void onError(Throwable d){
??????? }
??????? @Override
??????? public void onComplete(){
??????? }
??? }
3)通過subscribe()方法使觀察者訂閱被觀察者
??? Observable.subscribe(Observer observer);//實際調(diào)用的是ObservableCreate.subscribeActual()方法漆撞,具體實現(xiàn)如下
??? protected void subscribeActual(Observer<? super T> observer) {
????????????????? // 1. 創(chuàng)建1個CreateEmitter對象用于發(fā)射事件(封裝成1個Disposable對象)
??????????????? CreateEmitter<T> parent = new CreateEmitter<T>(observer);
??????????????? // 2. 調(diào)用觀察者(Observer)的onSubscribe()
??????????????? observer.onSubscribe(parent);
??????????????? try {
??????????????????? // 3. 調(diào)用source對象的(ObservableOnSubscribe對象)subscribe()
??????????????????? source.subscribe(parent);
??????????????? } catch (Throwable ex) {
??????????????????? Exceptions.throwIfFatal(ex);
??????????????????? parent.onError(ex);
??????????????? }
??????? }
??? RxJava的作用,與平時使用的異步操作來比的優(yōu)缺點
??? 說說EventBus作用于宙,實現(xiàn)方式浮驳,代替EventBus的方式
??? 從0設(shè)計一款A(yù)pp整體架構(gòu),如何去做捞魁?
??? 說一款你認(rèn)為當(dāng)前比較火的應(yīng)用并設(shè)計(比如:直播APP抹恳,P2P金融,小視頻等)
??? 談?wù)剬ava狀態(tài)機理解
??? Fragment如果在Adapter中使用應(yīng)該如何解耦拟杉?
??? Binder機制及底層實現(xiàn)
??? 對于應(yīng)用更新這塊是如何做的胆建?(解答:灰度碎浇,強制更新赊淑,分區(qū)域更新)?
??? 實現(xiàn)一個Json解析器(可以通過正則提高速度)
??? 統(tǒng)計啟動時長,標(biāo)準(zhǔn)
(七)性能優(yōu)化
??? 如何對Android 應(yīng)用進行性能分析以及優(yōu)化?
??? ddms 和 traceView
??? 性能優(yōu)化如何分析systrace死相?
??? 用IDE如何分析內(nèi)存泄漏?
??? Java多線程引發(fā)的性能問題,怎么解決窃这?
??? 啟動頁白屏及黑屏解決?
??? 啟動太慢怎么解決征候?
在冷啟動系統(tǒng)要執(zhí)行三個任務(wù):加載和啟動應(yīng)用程序杭攻;在app啟動后立即顯示一個空白窗體;創(chuàng)建APP進程疤坝。
應(yīng)用啟動后會執(zhí)行:創(chuàng)建應(yīng)用程序?qū)ο笳捉猓粏又骶€程;創(chuàng)建Main Activity跑揉;初始化構(gòu)造View锅睛;在屏幕上布局;執(zhí)行初始化繪制操作历谍;
應(yīng)用啟動现拒,空白窗口會一直存在直到系統(tǒng)完成了應(yīng)用的首次繪制操作,此時望侈,系統(tǒng)會替換啟動窗口印蔬,讓用戶能和APP進行交互。
對于熱啟動脱衙,如果應(yīng)用的Activity駐留在內(nèi)存中侥猬,應(yīng)用就可避免重復(fù)進行對象初始化。如果系統(tǒng)執(zhí)行了內(nèi)存回收并觸發(fā)GC岂丘,如onTrimMemory()陵究,熱啟動時對象仍需重建,這樣系統(tǒng)進程也會一直顯示白屏直到應(yīng)用完成Activity的渲染奥帘。
測量應(yīng)用啟動時間:1) 可通過logcat中查看Displayed中顯示啟動類耗時; 2) 通過adb shell am start -S -W 包名/啟動類全限定名铜邮,-S表示重啟當(dāng)前應(yīng)用,命令進行檢測啟動app的耗時寨蹋。3) 使用reportFullyDrawn()方法來測量應(yīng)用啟動到所有資源和視圖層次結(jié)構(gòu)完整顯示之間的所經(jīng)過的時間松蒜。
優(yōu)化方法:1)減少view的層級,減少復(fù)用和布局嵌套使布局扁平化已旧,不要加載對用戶不可見的布局秸苗,如使用ViewStub;
2)將需要在主線程中初始化但可不立即完成的延遲加載,部分組件放到子線程中初始化运褪。
3)減少Application.onCreate和啟動頁和第一個界面onCreate中方法的耗時操作惊楼。
4)設(shè)置閃屏頁玖瘸,將閃屏頁設(shè)置為啟動頁的activity窗口背景windowBackground屬性,為啟動屏幕提供一個背景檀咙,
??? 怎么保證應(yīng)用啟動不卡頓雅倒?
應(yīng)用卡頓的主要原因有:速度曲線不夠流暢,掉幀弧可、觸摸響應(yīng)速度
Android顯示機制:app->SurfaceFlinger->Display
開發(fā)者選項->GPU呈現(xiàn)模式分析->在屏幕上顯示為條形圖蔑匣,可以在屏幕上看到顯示每幀繪制花費的時間,有條基準(zhǔn)線是16ms,超過這條基線很可能出現(xiàn)掉幀棕诵。如果藍(lán)線很長裁良,則說明軟件draw太費時,可通過traceview來繼續(xù)分析draw的java代碼校套。如果中間紅色部分很長則說明是openGL ES繪制太費時价脾,用gltrace來分析OpernGL ES調(diào)用過程。用systrace分析搔确,用traceview來看代碼彼棍,
??? App啟動崩潰異常捕捉
??? 自定義View注意事項
??? 現(xiàn)在下載速度很慢,試從網(wǎng)絡(luò)協(xié)議的角度分析原因,并優(yōu)化(提示:網(wǎng)絡(luò)的5層都可以涉及)。
??? Https請求慢的解決辦法(提示:DNS膳算,攜帶數(shù)據(jù)座硕,直接訪問IP)
??? 如何保持應(yīng)用的穩(wěn)定性
1)需求明確清楚,編碼時明確知道要實現(xiàn)的功能和實現(xiàn)方法涕蜂,技術(shù)選型等华匾,對一些庫進行封裝再使用。防止代碼冗余机隙、避免多線程導(dǎo)致的問題蜘拉;
2)異常崩潰處理捕獲,在使用對象前做判空處理等
3)提高編碼質(zhì)量有鹿,用lint\findbugs進行代碼靜態(tài)分析旭旭;
4)OOM和內(nèi)存泄漏檢測
5)框架測試,兼容性測試葱跋、單元測試持寄、monkey測試
6)發(fā)布維度,灰度娱俺,選擇部分渠道進行發(fā)布稍味,收集問題;
7)熱更新荠卷。
??? RecyclerView和ListView的性能對比
??? ListView的優(yōu)化
??? RecycleView優(yōu)化
??? View渲染
??? Bitmap如何處理大圖模庐,如一張30M的大圖,如何預(yù)防OOM
??? java中的四種引用的區(qū)別以及使用場景
??? 強引用置為null油宜,會不會被回收掂碱?
如果對象沒有被GC Roots引用到怜姿,會被GC回收到,但什么時候回收需根據(jù)JVM的特性什么時候觸發(fā)GC操作顶吮。即使調(diào)用了System.gc() JVM也不一定會觸發(fā)GC社牲。
(八)NDK、jni悴了、Binder、AIDL违寿、進程通信有關(guān)
??? 請介紹一下NDK
??? 什么是NDK庫?
??? jni用過嗎湃交?
??? 如何在jni中注冊native函數(shù),有幾種注冊方式?
??? Java如何調(diào)用c藤巢、c++語言搞莺?
??? jni如何調(diào)用java層代碼?
1)Java類中要調(diào)用jni方法掂咒,需要在java類中聲明本地方法才沧,public native void methodName();//本地方法。還要在類的靜態(tài)代碼塊中導(dǎo)入so庫 static { System.loadLibrary("MyJni");}
2)在C/C++獲取類的對象的方法有兩種:
a)通過c/c++創(chuàng)建java對象绍刮,通過對象獲取類温圆,通過類獲取類的構(gòu)造方法的ID,基于方法ID和類孩革,創(chuàng)建新對象岁歉。
??? JNIEXPORT void JNICALL JAVA_nativeMethod(JNIEnv *env, jobject this, jint i) {
??????? jclass clazz = (*env).GetObjectClass(thiz);
??????? jmethodID mid = (*env).GetMethodID(clazz, "<init>","()V");
??????? jobject obj = (*env).NewObject(clazz, mid);
??? }
b) 通過c/c++創(chuàng)建不同類對象,通過FindClass方法獲取需要的類膝蜈;通過類獲取類的構(gòu)造方法的ID锅移,基于方法ID和類,創(chuàng)建對象
??? JNIEXPORT void JNICALL JAVA_nativeMethod(JNIEnv *env, jobject this, jint i) {
??????? jclass clazz = (*env).FindClass("com/packagepath/className");
??????? jmethodID mid = (*env).GetMethodID(clazz, "<init>","()V");
??????? jobject obj = (*env).NewObject(clazz, mid);
??? }
調(diào)用java方法跟上面調(diào)用構(gòu)造函數(shù)類似饱搏,獲取類的方法ID非剃,基于對象的方法id調(diào)用Java方法
??? JNIEXPORT void JNICALL JAVA_nativeMethod(JNIEnv *env, jobject thiz, jint i) {
??????? jclass clazz = (*env).GetObjectClass(thiz);
??????? m_Object = (*env).NewGlobalRef(thiz);
??????? m_mid = (*env).GetMethodID(clazz, "methodName", "()V");//獲取Java方法的ID
??????? m_fid = (*env).GetFieldID(clazz, "a","I");//獲取Java變量的ID
??????? (*env).SetIntField(m_Object, m_fid, i);
??????? (*env).CallVoidMethod(m_Object, m_mid);
??? }
??? 進程間通信的方式?
??? Binder機制
??? 簡述IPC推沸?
??? 什么是AIDL备绽?
??? AIDL解決了什么問題?
??? AIDL如何使用坤学?
??? Android 上的 Inter-Process-Communication 跨進程通信時如何工作的疯坤?
??? 多進程場景遇見過么?
??? Android進程分類深浮?
前臺進行(當(dāng)前正在前臺運行的進程压怠,說明用戶當(dāng)前正在與該進程交互), 滿足以下至少一個條件的叫做 foreground progcess:
? a.有一個Activity在前臺獲得焦點可與用戶互動
? b.有一個 BroadcastReceiver組件正在運行onReceive()方法
? c.有一個Sevice組件正在運行onCreate()/onStart()/onDestory()方法
可見進程(可見飞苇,但用戶不能直接與之交互)滿足以下條件之一稱為可見進程:a.有一個Activity能被用戶看見但是失去焦點(處于onPause()狀態(tài)) b.有一個 Service調(diào)用了startForeground()方法 c.綁定了一個Service菌瘫,系統(tǒng)將該Service作為一個特殊的用戶知道的功能使用如自動更換壁紙蜗顽,輸入法服務(wù)等。
服務(wù)進程(擁有service的進程雨让,一般在后臺為用戶服務(wù)的)雇盖,通過startService()方法開啟的沒有綁定在activity上的Service的進程,Service長時間運行 (超過30分鐘以上)會被降級到cached process
后臺進程(對用戶作用不大栖忠,缺少該進程一般不會影響用戶對系統(tǒng)的體驗)
空進程(一般作為緩存機制服務(wù)的)
??? 進程和 Application 的生命周期崔挖?
??? 進程調(diào)度
??? 談?wù)剬M程共享和線程安全的認(rèn)識
Android進程共享可通過共享用戶ID來實現(xiàn),
對于SharedPreferences想實現(xiàn)多進程共享需要設(shè)置MODE_MULTI_PROCESS庵寞,設(shè)置了這個Flag后狸相,每次調(diào)用Context.getSharedPreferences時系統(tǒng)會重新從SP
SharedPreferences myPrefs = context.getSharedPreferences(MY_FILE_NAME, Context.MODE_MULTI_PROCESS | Context.MODE_PRIVATE);
??? 談?wù)剬Χ噙M程開發(fā)的理解以及多進程應(yīng)用場景
??? 什么是協(xié)程?
(九)framework層捐川、ROM定制脓鹃、Ubuntu、Linux之類的問題
??? java虛擬機的特性
??? 談?wù)剬vm的理解
??? JVM內(nèi)存區(qū)域古沥,開線程影響哪塊內(nèi)存
??? 對Dalvik瘸右、ART虛擬機有什么了解?
??? Art和Dalvik對比
??? 虛擬機原理岩齿,如何自己設(shè)計一個虛擬機(內(nèi)存管理太颤,類加載,雙親委派)
??? 談?wù)勀銓﹄p親委派模型理解
??? JVM內(nèi)存模型纯衍,內(nèi)存區(qū)域
??? 類加載機制
??? 談?wù)剬lassLoader(類加載器)的理解
??? 談?wù)剬討B(tài)加載(OSGI)的理解
??? 內(nèi)存對象的循環(huán)引用及避免
??? 內(nèi)存回收機制栋齿、GC回收策略、GC原理時機以及GC對象
??? 垃圾回收機制與調(diào)用System.gc()區(qū)別
System.gc()只是通知垃圾回收器要進行垃圾回收操作襟诸,但并沒有立即執(zhí)行垃圾回收瓦堵。它只是建議JVM安排GC運行,還有可能被拒絕歌亲。
??? Ubuntu編譯安卓系統(tǒng)
??? 系統(tǒng)啟動流程是什么菇用?(提示:Zygote進程 –> SystemServer進程 –> 各種系統(tǒng)服務(wù) –> 應(yīng)用進程)
??? 大體說清一個應(yīng)用程序安裝到手機上時發(fā)生了什么
??? 簡述Activity啟動全部過程
1)Activity.startActivity-->startActivityForResult()
2)-->Instrumentation.execStartActivity()-->execStartActivity()
3)ActivityManager.getService().startActivity()通過Binder到ActivityManagerService.startActivity()
4)-->ActivityStarter.startActivityMayWait()-->startActivityLocked()-->startActivityUnchecked()
5)--ActivityStackSupervisor.resumeFocusedStackTopActivityLocked()-->ApplicationThread$scheduleLaunchActivity
6)ApplicationThread.schedulelaunchActivity()通過ActivityThread.sendMessage,再處理消息陷揪,進入handleLaunchActivity
-->Instrumentation$newActivity創(chuàng)建Activity的實例惋鸥,使用類加載器創(chuàng)建Activity對象。
-->makeApplication創(chuàng)建Application對象悍缠,調(diào)用它的Application.onCreate()方法
Instrumentation這個類就是完成對Application和Activity初始化和生命周期的工具類卦绣。
??? App啟動流程,從點擊桌面開始
1)點擊桌面App圖標(biāo)飞蚓,Launcher進程采用Binder IPC向system_server進程發(fā)送startActivity()
2)system_server進程向Zygote發(fā)送創(chuàng)建進程的請求(AMS中通過startActivity()方法滤港,調(diào)用startProcessLocked()函數(shù)),Zygote通過socket通信的方式讓Zygote進程 fork一個新進程出來作為App進程趴拧;
3)App進程通過Binder IPC向system_server進程發(fā)起attachApplication請求(ActivityThread的main()函數(shù)里會創(chuàng)建Application,還調(diào)用ActivityStackSupervisor.attachApplicationLocked)溅漾;
4)system_server進程收到請求后山叮,進行一系列準(zhǔn)備工作,再通過binder IPC向APP進程發(fā)送scheduleLaunchActivity請求添履;
5)App進程的binder線程(ApplicationThread)收到請求后屁倔,通過handler向主線程發(fā)送LAUNCHER_ACTIVITY消息;
6)主線程收到Message消息后暮胧,通過反射機制創(chuàng)建出Activity并回調(diào)Activity.onCreate()等方法锐借;
7)App正式啟動,開始進入Activity的生命周期叔壤。
??? 邏輯地址與物理地址瞎饲,為什么使用邏輯地址?
??? Android為每個應(yīng)用程序分配的內(nèi)存大小是多少炼绘?
根據(jù)應(yīng)用實際使用情況分配,初始給進程分配為8M妄田,應(yīng)用最大可分配的可能是64M\128M\256M等
??? Android中進程內(nèi)存的分配俺亮,能不能自己分配定額內(nèi)存?
進程內(nèi)存分配跟手機配置有關(guān)疟呐,不同手機可能不一樣脚曾,有64M\128M\256M等,heapgrowthlimit是一個普通應(yīng)用的內(nèi)存限制启具,可通過ActivityManager.getLargeMemoryClass()獲得本讥,在mainfest中設(shè)置了largeHeap=true后,可以使應(yīng)用可用內(nèi)存增大到原來兩倍鲁冯。并不能自己定額分配內(nèi)存拷沸,android系統(tǒng)是根據(jù)應(yīng)用所需要內(nèi)存大小,先分配初始大小heapstartsize薯演,當(dāng)應(yīng)用申請更多內(nèi)存撞芍,系統(tǒng)會再進行分配,但不得超過最大內(nèi)存跨扮,超過了會報OOM序无。
??? 進程保活的方式
1)模擬前臺進程衡创,startForeground()將當(dāng)前進程偽裝成前臺進程帝嗡,將進程優(yōu)先級提高到最高,現(xiàn)在前臺進程會顯示在通知欄中璃氢,取消不掉哟玷。
2)JobScheduler機制喚醒,系統(tǒng)會根據(jù)自己實現(xiàn)定時去調(diào)用改接口傳遞進程去實現(xiàn)一些操作拔莱,且這個接口被強制停止后仍能正常啟動碗降。在調(diào)用JobSchedule.schedule()來啟動任務(wù)隘竭。
3)實現(xiàn)Service類時,將onStartCommand()返回值設(shè)置為START_STICKY讼渊,利用系統(tǒng)機制在service掛掉后自動拉活动看,但這種方式只適合原生系統(tǒng),像小米爪幻、華為等定制化比較高的第三方廠商菱皆,這些都限制了。
4)一像素的Activity挨稿,
5)應(yīng)用之間相互喚醒仇轻。
??? 如何保證一個后臺服務(wù)不被殺死?(相同問題:如何保證service在后臺不被kill奶甘?)比較省電的方式是什么篷店?
??? App中喚醒其他進程的實現(xiàn)方式
1)啟動其他進程的Activity\Service或是發(fā)送一條廣播給相應(yīng)的應(yīng)用(該應(yīng)用得靜態(tài)注冊此廣播)
OOM定位與分析,如何定位哪塊原因?qū)е聭?yīng)用最終發(fā)生OOM臭家?
OOM發(fā)生后疲陕,可以用Android Studio自帶的Android Monitor dump出HPROF文件,再用SDK中hprof-conv工具轉(zhuǎn)換為標(biāo)準(zhǔn)的Java堆轉(zhuǎn)儲文件格式钉赁,再用MAT繼續(xù)分析蹄殃。切換到histogram視圖你踩,按shadow heap降序排序诅岩,對實例對象占用內(nèi)存大小排序钱慢,再查看實例到GC ROOT的路徑览绿。
一般可能導(dǎo)致的如圖片:直接加載超大尺寸圖片(對圖片尺寸縮放預(yù)處理后再加載)倔韭、圖片加載后未及時釋放(利用LRU機制保證圖片個數(shù)和占用內(nèi)存)硕并;在頁面中,加載非常多的圖片(避免同時加載大量圖片)
JNI層的crash如何捕獲?
參考:JNI定位c++錯誤
通過ndk安裝包中的addr2line objdump? ndk-stack工具進行分析crash梧疲,ndk針對不同的CPU架構(gòu)實現(xiàn)了多套相同的工具韭畸,在選擇add2line objdump時要根據(jù)目標(biāo)機器CPU架構(gòu)來選擇机蔗。
一般JNI發(fā)生異常,會出現(xiàn)一個Fatal signal信號量,大概知道是哪個函數(shù)引起的咸这,再看下面的backtrace日志侄刽,backtrace是JNI調(diào)用堆棧信息,以“#兩位數(shù)字 pc”開頭,找到對應(yīng)的函數(shù),再用addr2line進行定位出錯的位置劫谅。addr2line -C -f -e ./obj/armeabi/xxx.so 000eea70
使用ndk-stack協(xié)助我們獲取底層崩潰的堆棧信息见坑,adb logcat | ndk-stack -sym ./obj/armeabi/xxx.so
應(yīng)用卡頓定位
1)使用UI線程的Looper打印日志
Android主線程更新UI,如果1S鐘刷新少于60次捏检,即FPS小于60荞驴,一幀加載超過16.67ms的話,用戶就會產(chǎn)生卡頓的感覺贯城。Android使用消息機制進行UI更新熊楼,UI線程中有個Looper,其loop方法會不斷提取message能犯,調(diào)用其綁定的Handler在UI線程執(zhí)行孙蒙。如果handler.dispatchMessage方法中有耗時操作,就會發(fā)生卡頓悲雳。如果有卡頓,就打印出UI線程的堆棧信息香追。
優(yōu)點:用戶使用app就可以監(jiān)控卡頓情況合瓢,但因需另開子線程獲取堆棧信息,會消耗系統(tǒng)資源透典。
2)使用Choreographer.FrameCallback監(jiān)控卡頓
Android系統(tǒng)每16ms會發(fā)出SYNC信息晴楔,通知界面重繪、渲染峭咒,每一次同步的周期為16.6ms税弃,代表一幀的刷新頻率可以在兩次回調(diào)時間周期來判斷是否發(fā)生卡頓。(Android4.1以上才支持)凑队≡蚬可以通過Choreographer.FrameCallback回調(diào)doFrame(long)函數(shù),如果兩次doFrame之間間隔大于16.67ms說明發(fā)生了卡頓。這種方法從app層面來監(jiān)控卡頓西壮,同時可實時計算幀率和掉幀數(shù)遗增,實時監(jiān)測APP頁面的幀率數(shù)據(jù),一旦發(fā)現(xiàn)幀率過低款青,可自動保存現(xiàn)場堆棧信息做修。
卡頓監(jiān)控系統(tǒng)處理流程:開發(fā)修復(fù)-》用戶上報(后臺配置下灰度0.2%的用戶量進行卡頓監(jiān)控和上報,每個用戶一天上報一次抡草,上報后刪除文件不影響存儲空間)-》后臺解析(過濾饰及、去重、分類康震、反解堆棧燎含、入庫)-》平臺展示-》自動提單
Http2.0有關(guān)多路復(fù)用:
多路復(fù)用原理:HTTP2流和多路復(fù)用?? HTTP2.0原理詳細(xì)解析
原理是二進制分幀層+流實現(xiàn)了多路復(fù)用,OKHttp是怎么支持的呢签杈,那就是讀幀瘫镇,讀流,Okhttp對http2的支持簡單分析
ViewStub是怎么實現(xiàn)延時加載的答姥?
ViewStub是一個不可見铣除、大小為0的View。具體體現(xiàn)在ViewStub的構(gòu)造函數(shù)中會進行設(shè)置setVisibility(GONE)設(shè)置控件不可見鹦付,同時會設(shè)置setWillNotDraw(true),即本View不會調(diào)用onDraw()方法繪制內(nèi)容尚粘。在它的onMeasure函數(shù)中會調(diào)用setMeasureDimenssion(0, 0)即不會測量視圖,直接設(shè)置一個大小為0的View.
對于ViewStub.inflate()機制是:1)調(diào)用LayoutInflate.flate(mLayoutResource, parent, false)來加載ViewStub中android:layout設(shè)置的布局view(最后一個參數(shù)false是代表attachToRoot設(shè)置成false敲长,說明忽略android:layout中布局根節(jié)點的layoutParams參數(shù))郎嫁;2)從父視圖中獲取當(dāng)前ViewStub在父視圖中位置(在加載父視圖時會用一個占位符來代表ViewStub);3)將當(dāng)前ViewStub從parent中移除祈噪;4)將android:layout中的布局view add到父視圖中泽铛,如果StubView中設(shè)置了layoutParams屬性就會用ViewStub中設(shè)置的。
應(yīng)用場景:如網(wǎng)絡(luò)加載失敗頁面辑鲤,評論區(qū)域內(nèi)的listView(當(dāng)沒有評論或是請求失敗的時候不加載)
加載方式:findViewById(R.id.stubViewId).setVisibility(View.VISIBLE);或是((ViewStub)findViewById(R.id.StubViewId)).inflate();其實設(shè)置Visibility最終也是調(diào)用inflate來加載布局的盔腔。
如果ViewStub標(biāo)簽下寫上width/height,在ViewStub相應(yīng)的layout xml文件中也進行了寬高定義月褥,會以誰為準(zhǔn)弛随?
其實上面也分析過了,會以ViewStub中設(shè)置的layoutParams為準(zhǔn)宁赤。
ViewStub可不可以加載多次呢舀透?
不能,上面也分析過了决左,ViewStub調(diào)用inflate()方法后愕够,會把自己從父視圖中移除掉走贪,并把自身所包含的內(nèi)容添加到父視圖中,再重新加載链烈,找不到在父視圖了厉斟,就會拋出ViewStub must have a non-null ViewGroup viewparent。
merge標(biāo)簽
merge一般可以和include/ViewStub結(jié)合使用强衡,當(dāng)include/ViewStub從外部導(dǎo)入xml結(jié)構(gòu)時擦秽,可以將被導(dǎo)入的xml用merge作為根節(jié)點表示,當(dāng)被加載到父布局中可以將它們?nèi)诤系礁讣壗Y(jié)構(gòu)中漩勤,而不會出現(xiàn)冗余的節(jié)點感挥。因為它是直接將其中的子元素添加到merge標(biāo)簽的parent中,這樣就保證不會引入額外的層級了越败。
注意:1)<merge />只可以作為xml layout的根節(jié)點触幼;2)當(dāng)需要擴展的xml layout本身的根節(jié)點也是merge時,需要將被導(dǎo)入的xml layout置于ViewGroup中究飞,且設(shè)置attachToRoot為true