因爲我的緣由在一個公司連續呆了四年之久,然而此次面試也是人生中第一次面試,對於工做四年工做內容我分爲三點:1.產品籌劃、2.產品設計、3.安卓開發java
通常面試時間短則30分鐘,多則1個小時,這麼點時間要全面考察一我的難度很大,須要一些技巧,這裏我不侷限於回答題主的問題,而是分享一下我我的關於如何作好Android技術面試的一些經驗:android
- 簡歷調查
簡歷到你手上的時候,你要作好充分的調查分析,不只僅是對公司負責,也是對本身與候選人時間的尊重,明顯不match的簡歷,就不要抱着「來試試看」的想法了,候選人也許很不錯,但若是跟你的崗位不match, 也不要浪費你們時間,你要想清楚如今須要的人是有潛力能夠培養的,仍是亟需幫忙幹活的。另外若是簡歷裏附帶了博客連接,GitHub地址,相關做品的,能夠提早去看看,直接看人家多年積累的文章與代碼,比這短短一小時的面試來得靠譜的多。面試
- 準備問題
瞭解清楚候選人背景後,要根據簡歷,有針對性的準備問題,能夠是他做品或作過項目裏的某個技術細節的實現方式,也能夠是他聲稱精通的某些領域的相關問題。總之不要等到面試過程當中現想問題,特別是剛開始面試別人的同窗,每每經驗不足稍帶緊張致使大腦短路,其實也是很尷尬的,把要問的問題提早寫下來,準備充分。算法
在面試以前看到不少朋友在博客,簡書、csdn、掘金等發佈本身的面試總結,其中有不少知識點都是模糊的,由於項目中不多用到,或者是用到了沒有深刻去研究。其實在過去,我經常有這種心理,以爲項目中不經常使用或者幾乎不用普及的大可沒必要去研究。徹底是爲了開發而開發。長此以往我發現我所作的項目或多或少會出現一些bug,而這些bug有時候會困擾我幾個小時,甚至大半天。後面當我去研究那些我認爲項目中不多用,或者幾乎用不到的知識點後,才發現本身所犯的錯,並且你會很清楚的明白錯誤起因,以及解決辦法。我之因此說這些就想說明要多去研究知識點,不要爲了開發而開發。對一些不理解的api要學會看源碼。學會讀源碼。好了,言歸正算。下面我就彙總下咱們日常面試中常見的問題(我認爲)及本身的答題。數據庫
- activity生命週期?
onCreate() : 該方法是在Activity被建立時回調,它是生命週期第一個調用的方法,咱們在建立Activity時通常都須要重寫該方法,而後在該方法中作一些初始化的操做,如經過setContentView設置界面佈局的資源,初始化所須要的組件信息等。canvas
onStart : 此方法被回調時表示Activity正在啓動,此時Activity已處於可見狀態,只是尚未在前臺顯示,所以沒法與用戶進行交互。能夠簡單理解爲Activity已顯示而咱們沒法看見擺了。設計模式
onResume() : 當此方法回調時,則說明Activity已在前臺可見,可與用戶交互了(處於前面所說的Active/Running形態),onResume方法與onStart的相同點是二者都表示Activity可見,只不過onStart回調時Activity仍是後臺沒法與用戶交互,而onResume則已顯示在前臺,可與用戶交互。固然從流程圖,咱們也能夠看出當Activity中止後(onPause方法和onStop方法被調用),從新回到前臺時也會調用onResume方法,所以咱們也能夠在onResume方法中初始化一些資源,好比從新初始化在onPause或者onStop方法中釋放的資源。api
onPause() : 此方法被回調時則表示Activity正在中止(Paused形態),通常狀況下onStop方法會緊接着被回調。但經過流程圖咱們還能夠看到一種狀況是onPause方法執行後直接執行了onResume方法,這屬於比較極端的現象了,這多是用戶操做使當前Activity退居後臺後又迅速地再回到到當前的Activity,此時onResume方法就會被回調。固然,在onPause方法中咱們能夠作一些數據存儲或者動畫中止或者資源回收的操做,可是不能太耗時,由於這可能會影響到新的Activity的顯示——onPause方法執行完成後,新Activity的onResume方法纔會被執行。數組
onStop() : 通常在onPause方法執行完成直接執行,表示Activity即將中止或者徹底被覆蓋(Stopped形態),此時Activity不可見,僅在後臺運行。一樣地,在onStop方法能夠作一些資源釋放的操做(不能太耗時)。緩存
onRestart() :表示Activity正在從新啓動,當Activity由不可見變爲可見狀態時,該方法被回調。這種狀況通常是用戶打開了一個新的Activity時,當前的Activity就會被暫停(onPause和onStop被執行了),接着又回到當前Activity頁面時,onRestart方法就會被回調。
onDestroy() :此時Activity正在被銷燬,也是生命週期最後一個執行的方法,通常咱們能夠在此方法中作一些回收工做和最終的資源釋放。
2.兩個activity分別是AB,在A中啓動B,而後返回A,請問各自的生命週期?
當A中啓動B時:A:onPause()進入暫停狀態,當啓動B時:onCreate()-onStart-onResume後B可見,A再執行onStop()中止 返回A時B的生命週期:先onPause()進入暫停狀態,當返回A時:A生命週期:onReStart()-onStart()-onResume()後A從新可見。B再執行onStop()-onDestory()銷燬界面
總結:當從一個activity到另外一個acitvity的時候,第一個activity會先進入一個暫停狀態,只有當另一個activity可見(調用onResume())的時候第一個acitvity纔會中止或者銷燬
3.activity啓動模式有幾種並簡單說明下各自的應用場景
1.Fragment的生命週期?
onAttach(): 這個時候 activity已經傳進來了,得到activity的傳遞的值,就能夠進行 與activity的通訊裏,固然也可使用getActivity(),前提是這個fragment已經和宿主的activity關聯,而且沒有脫離他只調用一次。
onCreate(): 系統建立fragment的時候回調他,在他裏面實例化一些變量 這些個變量主要是:當你 暫停 中止的時候 你想保持的數據,若是咱們要爲fragment啓動一個後臺線程,能夠考慮將代碼放於此處。參數是:Bundle savedInstance, 用於保存 Fragment 參數,Fragement也能夠重寫 onSaveInstanceState(BundleoutState)方法, 保存Fragement狀態;能夠用於 文件保護他也只調用一次。
onCreateView():第一次使用的時候 fragment會在這上面畫一個layout出來,爲了能夠畫控件 要返回一個 佈局的view,也能夠返回null當系統用到fragment的時候 fragment就要返回他的view,越快越好,因此儘可能在這裏不要作耗時操做,好比從數據庫加載大量數據顯示listview,固然線程仍是能夠的。給當前的fragment繪製ui佈局,可使用線程更新UI說白了就是加載fragment的佈局的。這裏通常都先判斷是否爲null
if(text==null){
Bundle args=getArguments();
text=args.getString("text");
}
if (view == null) {
view = inflater.inflate(R.layout.hello, null);
}
複製代碼
這樣進行各判斷免得每次都要加載,減小資源消耗
-onStart():和activity等同啓動, Fragement 啓動時回調, 此時Fragement可見;
onResume():和activity等同在activity中運行是可見的激活, Fragement 進入前臺, 可獲取焦點時激活;
onPause():和activity等同 其餘的activity得到焦點,這個仍然可見第一次調用的時候,指的是用戶離開這個fragment(並非被銷燬)一般用於 用戶的提交(可能用戶離開後不會回來了)
onStop():和activity等同fragment不可見的,可能狀況:activity被stopped了 OR fragment被移除但被加入到回退棧中一個stopped的fragment仍然是活着的若是長時間不用也會被移除
onDestroyView():Fragment中的佈局被移除時調用。表示fragemnt銷燬相關聯的UI佈局清除全部跟視圖相關的資源,之前覺得這裏沒什麼用處其實 大有文章可作,相信你們都用過ViewPager+Fragment,因爲ViewPager的緩存機制,每次都會加載3頁。 例如:有四個 fragment 當滑動到第四頁的時候 第一頁執行onDestroyView(),但沒有執行onDestroy。 他依然和activity關聯。當在滑動到第一頁的時候又執行了 onCreateView()。 生命週期能夠本身試一下。 那麼問題來了。會出現重複加載view的局面,因此這麼作(下面是先人的代碼)
@Override
public void onDestroyView() {
if(view!=null){
((ViewGroup)view.getParent()).removeView(view);
}
super.onDestroyView();
}
複製代碼
onDestroy():銷燬fragment對象跟activity相似了。
onDetach(): Fragment和Activity解除關聯的時候調用。脫離activity
2.Fragemnt棧管理方式?
3.Fragment中出現內存泄露並致使閃退,請舉例說出一種場景?
回答這個問題,咱們首先須要知道什麼是內存泄露,什麼會致使內存泄露。
內存泄露:在android中再也不使用的對象,Gc垃圾回收機制沒法對其回收就會產生內存泄漏注:過多的內存泄漏會致使內存溢出OOM
4.activtiy,fragment數據傳遞通信方式
1.service的啓動方式且各自的生命週期?
提示:若是咱們的service繼承的時intentservice,通常這種狀況就是咱們要在service中作耗時操做,然而intentservice在 onHandleIntent()中建立一個工做線程。而後在onDestory()中會自動關閉線程
2.BroadCastReceiver有幾種分類及註冊方式?
分類:(1)有序廣播(2)標準廣播
註冊方式:(1)動態註冊:就是代碼註冊廣播(2)靜態註冊:在註冊文件中註冊
ContentProvider:
四大組件的內容提供者,主要用於對外提供數據
實現各個應用程序之間的(跨應用)數據共享,好比聯繫人應用中就使用了ContentProvider,你在本身的應用中能夠讀取和修改聯繫人的數據,不過須要得到相應的權限。其實它也只是一箇中間人,真正的數據源是文件或者SQLite等
一個應用實現ContentProvider來提供內容給別的應用來操做,經過ContentResolver來操道別的應用數據,固然在本身的應用中也能夠
ContentResolver:
內容解析者,用於獲取內容提供者提供的數據
ContentResolver.notifyChange(uri)發出消息
ContentObserver:
內容監聽器,能夠監聽數據的改變狀態
目的是觀察(捕捉)特定Uri引發的數據庫的變化,繼而作一些相應的處理,它相似於數據庫技術中的觸發器(Trigger),當ContentObserver所觀察的Uri發生變化時,便會觸發它。觸發器分爲表觸發器、行觸發器,相應地ContentObsever也分爲表ContentObserver、行ContentObserver,固然這是與它所監聽的Uri MIME Type有關的
ContentResolver.registerContentObserver()監聽消息
什麼狀況會致使內存泄露?
Fragment中出現內存泄露並閃退說明內存泄露頻繁致使oom.
內存優化
這個問題就不是三言兩語了,內存優化是個比較廣的知識面,他包括內存泄漏,佈局優化,資源優化,內存溢出等知識點
我這裏就總結內存優化的幾點吧:
此處我說下MVP模式,既然是設計模式那麼寫法確定不是固定的,所以每一個人對其理解都不同,我就在此說下我對mvp模式的理解吧。
MVP是MVC的升級版,其中M-Model數據模型,V-View就是咱們的視圖,P-Presenter控制層,他控制M,V邏輯,使M,V徹底解耦。通常來講咱們在M層定義一個接口和一個實現類,實現類中獲取網絡數據或者進行一些數據操做,P層中獲取到,M,V層引用,把M層返回的結果交給V層,最後在V層作處理(更新ui一些操做)。
自定義view涉及到的知識點比較全面,也是個難點,通常來講自定義view就是去實現一些咱們系統控件實現不了的效果,其具體流程就是:
其中onMeasue()就是測量,這個通常在組合控件中比較常見,onLayout()就是控制view的顯示位置,onDraw()就是繪製view,繪製view涉及到canvas與paint一個畫布一個畫筆
說說跨進程通信? 跨進程通信即IPC,可是跨進行通信也很常見
對於android開發者來講對於ANR這個詞並不陌生,那麼ANR是什麼?什麼狀況會ANR?怎麼避免?
所謂gc機制就是垃圾處理器一共須要兩部:檢測和回收垃圾
1.引用計數法:一個對象引用一次計數+1,引用失效-1
2.根搜索法:以根集對象爲起始點進行搜索,若是有對象不可達的話,即爲垃圾對象。這裏的根集通常包括:java棧中的引用對象、本地方法棧中JNI的引用對象、方法區中運行常量池中的引用對象、方法區中靜態屬性引用的對象、運行中的線程、由引導類加載器加載的對象、GC控制的對象。總之,JVM在作垃圾回收的時候,會檢查堆中的全部對象是否被這些根集中的對象所引用,不可以被引用的對象就會被垃圾回收器回收。
1.標記-清除:將全部須要回收的對象進行標記,而後統一清除
2.複製算法:將內存分兩個區域,只使用其中一個區域存儲對象,垃圾回收時遍歷使用區域的全部對象並將使用對象複製到另一個區域。
3.標記-整理:此算法爲前兩個算法的結合體,分兩個階段,第一部將全部被使用的對象標記,第二部遍歷堆中全部對象將未被標記的對象進行回收並整理存活對象
4.分代收集算法:年輕代:複製算法,老年代:標記-整理
1.對於HaspMap原理我也是才經過一些資料研究了一下,我先根據個人理解說說HashMap原理及結構
(1)HaspMap結構在jdk1.8之前:數組+鏈表也就是散列表形式,在jdk1.8加了一個紅黑樹其結構:數組+鏈表+紅黑樹 至於其意義接下來請看HashMap原理
(2)HashMap原理:首先咱們經過源碼看HashMap他默認的數組大小16,每次擴容爲其2倍,且數組大小爲2的N次方。
數據由Entry實體類以鍵值對形式存儲,而每一個實體類對應一個HashCode.在java中每一個對象都有一個hashcode()方法,它是一個由32位整數組成的,而在HashMap中咱們只須要9位Int整數型,當咱們put一個鍵值對的時候,會首先判斷key是否位null,(爲null默認返回第一個)而後根據K找到獲取HashCode值而後對其進行hash運算獲取到hash值,接着循環table根據其hash值及key判斷是否相同若是相同就替換,若是不相同就添加一個Entry
另外特別注意:有可能hash衝突,也就是說咱們隨機參數的int整數型重複了,這時候咱們就經過拉鍊表的方式進行處理,讓每一個Entry以單向鏈表形式存在,當鏈表長度達到8就會採用紅黑樹提升性能,當鏈表長度小於8就從新由轉換成單向鏈表
總結:HashMap默認數組大小爲16,每一個鍵值對都是以Entry實體類存儲的,而後每一個K會對應一個HashCode也就是Hash值,當咱們put一個數據的時候,首先會根據這個K獲取到對應的hashcode經過hashcode獲取到hash值,而後循環散列表也就是循環table判斷k,hash值是否相等,若是相等就表示是更新數據,若是有一個不相等就表示添加數據(包括hash衝突,上面已經說到)。最後咱們也能夠經過不一樣構造函數設置數組默認大小,負載因子。
寫在前面:說到android動畫咱們腦海裏就會想起自定義,平移,旋轉等一些特效。其實android動畫也是個知識面比較廣的。
1.android動畫分幾類,說說他們的區別與特色?
總結:幀動畫與補間動畫歸爲:視圖動畫。屬性動畫爲另外一類,此外我推薦另外兩個動畫,共享動畫和過渡動畫,有興趣的朋友能夠研究下
首先:字體用sp設置大小能夠跟隨系統字體大小改變而改變,控件用dp至少對不一樣分辨率適配了
接下來咱們瞭解下sp,dp,dpi這幾個單位:
px=dp*(dpi/160)
特別注意:假設如今我有兩部手機分辨率不同,可是手機尺寸大小同樣,假如第一部手機的像素密度及dpi=320,第二部手機的像素密度及dpi=160,我設置了一個2dp的寬的控件根據px=dp*(dpi/160)公式可得像素密度爲160的px=dp及1px1dp,像素密度320的px=2*dp及1dp=2px.咱們能夠想象像素密度越大那麼說明像素之間很緊密,反之就稀疏。那麼當我在160dpi手機上設置寬爲2dp的時候此時2dp=2px,在320dpi手機上設置寬的爲2dp的時候此時2dp=4px.上面說到像素密度越大像素之間就緊密,那麼此時在手機尺寸大小同樣的狀況下。此時2px與4px寬度相差不大的。你能夠把一個像素想象成一個點,像素密度(dpi)越大每一個點的距離就越小,反正就越大。這就是爲何設置寬高要用dp了,由於它適配了不一樣分辨率。
線程池的做用及原理?
首先咱們看下使用線程池的緣由:在咱們開發中咱們有時候須要頻繁建立工做線程,而後這些工做線程及有可能致使線程阻塞,並且頻繁建立線程也會下降性能
那麼線程池的做用是什麼吶?
根據上訴咱們知道:線程池就是用來管理一個個線程的,它不會頻繁建立線程,並且對其進行復用這樣就不會頻繁調用gc,提升了效率及性能。
那麼線程池的原理是什麼?
要知道線程池原理首先咱們看下其構造函數:
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
複製代碼
corePoolSize:核心線程最大數量
maximumPoolSize:最大線程數量
keepAliveTime:非核心線程的保活時間,就是說當非核心線程在空閒狀態在保活時間,這樣當工做任務時間短,能夠避免頻繁建立線程。提升效率及性能
unit:上面時間屬性的單位
workQueue:任務隊列
threadFactory:線程工廠,可用於設置線程名字等等
經過構造函數推出線程池的原理:
1.當有新的任務進入的時候(execute一個線程以後)會首先判斷當前核心線程是否達到最大,若是沒有就直接建立一個核心線程開執行任務
2.當有新任務進入的時候(execute一個線程以後)若是核心線程達到最大可是任務隊列未滿,那麼次任務就會進入任務隊列等待
3.當有新的任務進入的時候(execute一個線程以後)若是核心線程達到最大而且任務隊列已經滿了,可是線程數量未超過非核心線程最大數量,就建立一個新非核心線程執行任務
4.當有新任務進入的時候(execute一個線程以後)若是線程池中的線程數已經超過非核心線程數,則拒絕執行該任務,採起飽和策略,並拋出RejectedExecutionException異常