Android高級面試題整理一

1.android 事件分發(fā)機制换吧,分析整體流程

image.png

2.android View繪制機制和加載過程折晦,詳細說一
下整體流程

一個 Activity 包含一個Window,Window是一個抽象基類沾瓦,是 Activity 和整個 View 系統(tǒng)交互的接口满着,只有一個實現(xiàn)子類PhoneWindow,提供了一系列窗口的方法贯莺,比如設(shè)置背景风喇,標題等。一個PhoneWindow 對應一個DecorView 跟 一個 ViewRootImpl缕探,DecorView 是ViewTree 里面的頂層布局魂莫,是繼承于FrameLayout,包含兩個子View爹耗,一個id=statusBarBackground 的 View 和 LineaLayout耙考,LineaLayout 里面包含 title 跟content,title就是平時用的TitleBar或者ActionBar潭兽, content也是FrameLayout倦始,activity通過 setContent()加載布局的時候加載到這個View上。ViewRootImpl就是建立 DecorView 和 Window 之間的聯(lián)系

image

ViewRootImpl 類

performTraversals 方法中調(diào)用了performMeasure()


image.png
  1. viewRootImpl會調(diào)用performTraversals()山卦,其內(nèi)部會調(diào)用performMeasure(),performLayout鞋邑,performDraw() 方法
    2.performMeasure()會調(diào)用最外層的ViewGroup的measure()--->onMeasure() ---->ViewGroup的onMeasure() 方法是抽象方法,但其提供了measeureChilden()方法怒坯,這個會遍歷子View 然后循環(huán)調(diào)用measureChilden() 炫狱,這個方法中會調(diào)用getChildMeasureSpec() + 父View的MeasureSpec + 子View的LayoutParam 一起獲取到本身View的MeasueSpec,然后調(diào)用子View的measure()到view的onMeasure()--->setMeasuredDimension(getDefaultSize(),getDefaultSize()) 默認返回measureSpec的測量數(shù)值 ,所以繼承View 進行自定義的wrap_content 需要重寫
    3.performLayout() 會調(diào)用最外層的ViewGroup的layou(l,t,r,b) ,本身View在其中使用setFrame(),設(shè)置本View的四個頂點位置剔猿,在onLayout(抽象方法)中確定子View的位置 视译,比如LinearLayout 會遍歷子View ,循環(huán)調(diào)用 setChildFrame--->子View的layout方法
    4.performDraw()會調(diào)用最外層的ViewGroup的draw(),其中會先后調(diào)用background.draw () 繪制背景,onDraw 方法 繪制自己本身View ---> 調(diào)用dispatchDraw() 進行子View 繪制---->onDrawScrollBars() 繪制裝飾
    5.MeasureSpec 由2位SpecMode(UNSPECIFIED,EXACTILY(對應精確值和match_parent),AT_MOST 對應warp_content) 和30位SpecSize 組成一個int归敬,DecorView的MeasureSpec 是由窗口大小與其LayoutParams決定酷含,其他View 是由父View的MeasureSpec 和本身的View的layoutParams 來決定 ,ViewGroup 中有g(shù)etChildenMeasureSpec() 來獲取子View 的measureSpec

EXACTLY:父容器已經(jīng)測量出子View的大小汪茧。對應是 View 的LayoutParams的match_parent 或者精確數(shù)值椅亚。
AT_MOST:父容器已經(jīng)限制子view的大小,View 最終大小不可超過這個值舱污。對應是 View 的LayoutParams的wrap_content
UNSPECIFIED:父容器不對View有任何限制呀舔,要多大給多大,這種情況一般用于系統(tǒng)內(nèi)部扩灯,表示一種測量的狀態(tài)媚赖。

6.三種方式獲取measure()后的寬高值
a.activity中的onWindowFocusChange() 方法中調(diào)用獲取
b.view.post(Runnable) 將在run方法中進行獲取
c.view.setViewTreeObserbable 監(jiān)聽中進行獲取

image.png
   private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
            int desiredWindowHeight) {
        mLayoutRequested = false;
        mScrollMayChange = true;
        mInLayout = true;

        final View host = mView;
        if (host == null) {
            return;
        }
        if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
            Log.v(mTag, "Laying out " + host + " to (" +
                    host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
        }

        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
        try {
            host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());

            mInLayout = false;
            int numViewsRequestingLayout = mLayoutRequesters.size();
            if (numViewsRequestingLayout > 0) {
                // requestLayout() was called during layout.
                // If no layout-request flags are set on the requesting views, there is no problem.
                // If some requests are still pending, then we need to clear those flags and do
                // a full request/measure/layout pass to handle this situation.
                ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
                        false);
                if (validLayoutRequesters != null) {
                    // Set this flag to indicate that any further requests are happening during
                    // the second pass, which may result in posting those requests to the next
                    // frame instead
                    mHandlingLayoutInLayoutRequest = true;

                    // Process fresh layout requests, then measure and layout
                    int numValidRequests = validLayoutRequesters.size();
                    for (int i = 0; i < numValidRequests; ++i) {
                        final View view = validLayoutRequesters.get(i);
                        Log.w("View", "requestLayout() improperly called by " + view +
                                " during layout: running second layout pass");
                        view.requestLayout();
                    }
                    measureHierarchy(host, lp, mView.getContext().getResources(),
                            desiredWindowWidth, desiredWindowHeight);
                    mInLayout = true;
                    host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());

                    mHandlingLayoutInLayoutRequest = false;

                    // Check the valid requests again, this time without checking/clearing the
                    // layout flags, since requests happening during the second pass get noop'd
                    validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
                    if (validLayoutRequesters != null) {
                        final ArrayList<View> finalRequesters = validLayoutRequesters;
                        // Post second-pass requests to the next frame
                        getRunQueue().post(new Runnable() {
                            @Override
                            public void run() {
                                int numValidRequests = finalRequesters.size();
                                for (int i = 0; i < numValidRequests; ++i) {
                                    final View view = finalRequesters.get(i);
                                    Log.w("View", "requestLayout() improperly called by " + view +
                                            " during second layout pass: posting in next frame");
                                    view.requestLayout();
                                }
                            }
                        });
                    }
                }

            }
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        mInLayout = false;
    }

Draw繪制流程


image.png

draw 過程中一共分成7步霜瘪,其中兩步我們直接直接跳過不分析了。

第一步:drawBackground(canvas): 作用就是繪制 View 的背景惧磺。

第二步:onDraw(canvas) :繪制 View 的內(nèi)容颖对。View 的內(nèi)容是根據(jù)自己需求自己繪制的,所以方法是一個空方法磨隘,View的繼承類自己復寫實現(xiàn)繪制內(nèi)容缤底。

第三步:dispatchDraw(canvas):遍歷子View進行繪制內(nèi)容。在 View 里面是一個空實現(xiàn)番捂,ViewGroup 里面才會有實現(xiàn)个唧。在自定義 ViewGroup 一般不用復寫這個方法,因為它在里面的實現(xiàn)幫我們實現(xiàn)了子 View 的繪制過程白嘁,基本滿足需求坑鱼。

第四步:onDrawForeground(canvas):對前景色跟滾動條進行繪制膘流。

第五步:drawDefaultFocusHighlight(canvas):繪制默認焦點高亮
image.png

3.android 四大組件加載過程絮缅,詳細介紹下

4.Activity 的啟動模式
1.standard 標準模式
不指定其他模式的情況下,默認是用standard 這種模式來啟動activity,誰啟動的activity,就歸宿到對應的activity任務棧中呼股,standard模式默認按照任務棧的順序進行壓棧處理

image.png

singleTop 模式
singleTop 模式耕魄,如果當前打開的activity處于任務棧,棧頂activity就復用彭谁,不用創(chuàng)建新的activity實例吸奴,此時回調(diào)onNewIntent方法,如果當前打開的activity不處于任務棧棧頂缠局,那么依然創(chuàng)建新的activity實例则奥,并處于任務棧頂

image.png

SingleTask 模式
首先會根據(jù)taskAffinity 去尋找當前是否存在一個對應的名字的任務棧,如果不存在狭园,則會創(chuàng)建新的Task任務棧读处,如果存在,則會查找當前任務棧中是否有當前的activity實例唱矛,如果有清除掉當前activity任務棧的所有的activity實例罚舱,并且當前的activity處于任務棧棧頂,并且回調(diào)activity中的onNewIntent方法绎谦,如果不存在當前activity的實例管闷,在當前的任務棧中創(chuàng)建activity的實例,并處于任務棧棧頂


image.png

SingleInstance 模式
SingleInstance比較特殊窃肠,是全局單例模式包个,是一種加強的SingleTask模式。它除了具有它所有特性外冤留,還加強了一點:具有此模式的Activity僅僅能單獨位于一個任務棧中碧囊。(以singleInstance模式開啟的activity 具有獨占性 )

5.Activity緩存方法

6.Service的生命周期恃锉,兩種啟動方法,有什么區(qū)別

7.怎么保證Service 不被殺死

8.靜態(tài)的Broadcast和動態(tài)BroadCast 有什么區(qū)別

  1. Intent可以傳遞那些數(shù)據(jù)類型

10.Json有什么優(yōu)劣勢呕臂,解析的原理

11.一個語言的編譯過程

12.動畫有幾類破托,各有什么特點

13.Handler,Looper 消息隊列模型,每個部分的作用是什么

14.怎么退出終止App

15.Android IPC Binder原理

16.描述一次跨進程通信

17.android 重要話術(shù)語解釋

18 .理解Window和WindowMananger

19.Bitmap的處理

20如何實現(xiàn)一個網(wǎng)絡框架 (參考Okhttp歧蒋,volley)

21.ClassLoader 的基礎(chǔ)知識

22.插件化框架描述 (ps:dynamicLoadApk)

23.熱修復 ( ps:AndFix)

24.線程同步的問題土砂,常用的線程同步

25.Asynctask 和線程池,GC相關(guān) (怎么判斷哪些內(nèi)存GC谜洽,GC算法)

26.網(wǎng)絡相關(guān)

27.APK 打包流程和其內(nèi)容

28.網(wǎng)絡劫持的類型原理

29.Java類加載過程

30.Retrofit的了解

31.Bundle的數(shù)據(jù)結(jié)構(gòu)萝映,如何存儲數(shù)據(jù)

32.ListView內(nèi)點擊Button并移動的事件流完整攔截過程

33.Service 的意義

34.Android的IPC通信方式 ,線程進程間通信機制有哪些

35.操作系統(tǒng)進程和線程的區(qū)別

36.HashMap的實現(xiàn)過程:Capacity就是Buckets的數(shù)目阐虚,Load factor就是Buckets填滿程度的最大比例序臂,如果對迭代性要求很高的話不要把capacity設(shè)置過大,也不要把load factor 設(shè)置過小

37.MVC实束,MVP,MVVM

38.Java的線程如何實現(xiàn)

39.ArrList 如何刪除重復的元素或者指定的元素

40 .如何設(shè)計在UDP上層保證UDP的可靠行傳輸

參考文檔
Android大廠面試題錦集附答案(BAT TMD JD 小米)
2020 Android 面試重難點
快手奥秆、小紅書、最右面試題

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末咸灿,一起剝皮案震驚了整個濱河市构订,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌避矢,老刑警劉巖悼瘾,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異审胸,居然都是意外死亡亥宿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門砂沛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烫扼,“玉大人,你說我怎么就攤上這事尺上〔闹耄” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵怎抛,是天一觀的道長卑吭。 經(jīng)常有香客問我,道長马绝,這世上最難降的妖魔是什么豆赏? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上掷邦,老公的妹妹穿的比我還像新娘白胀。我一直安慰自己,他們只是感情好抚岗,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布或杠。 她就那樣靜靜地躺著,像睡著了一般宣蔚。 火紅的嫁衣襯著肌膚如雪向抢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天胚委,我揣著相機與錄音挟鸠,去河邊找鬼。 笑死亩冬,一個胖子當著我的面吹牛艘希,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播硅急,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼覆享,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了铜秆?” 一聲冷哼從身側(cè)響起淹真,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎连茧,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體巍糯,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡啸驯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了祟峦。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罚斗。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖宅楞,靈堂內(nèi)的尸體忽然破棺而出针姿,到底是詐尸還是另有隱情,我是刑警寧澤厌衙,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布距淫,位于F島的核電站,受9級特大地震影響婶希,放射性物質(zhì)發(fā)生泄漏榕暇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望彤枢。 院中可真熱鬧狰晚,春花似錦、人聲如沸缴啡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽业栅。三九已至讨衣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間式镐,已是汗流浹背反镇。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留娘汞,地道東北人歹茶。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像你弦,于是被迫代替她去往敵國和親惊豺。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354