Android開發四年面試相關知識整理 [復制鏈接]

2019-11-8 10:33
搞點大事情 閱讀:379 評論:0 贊:0
Tag:  面試

一. Android相關

1. mvc mvp mvvm三種架構模式

  • mvc:業務邏輯、數據、界面分離的一種模式,簡單的來說,就是通過controller來操作model層的數據,并且返回給view顯示。 activity不是標準的controller,隨著界面邏輯交互的復雜度提升,activity類的職責不斷增加,變得臃腫。 view和model相互耦合,不利于開發。
  • mvp:主要是提出了presenter層,作為view和model之間溝通的橋梁。 程序邏輯放在presenter中處理,完全將view和model進行了分離,不允許他們之間溝通。
  • mvvm:主要是將presenter改為了viewmodel,和mvp類似,不同的是viewmodel跟view和model進行雙向綁定。 使用了data binding

二. Android系統結構層次

Android系統架構分為5層,從下到上依次為 Linux內核層,硬件抽象層,系統運行庫層(Native),應用框架層,應用層。

  • Linux內核層:Android的核心基于Linux內核,在此基礎上添加了Android的專用驅動(比如Binder)、系統的安全性、內存管理、進程管理等等。
  • 硬件抽象層(HAL):有了核心還不行,你得需要運行到相應的硬件上才能實現自己的價值吧。而硬件抽象層就是硬件和Linux內核之間的接口,目的就是將硬件抽象化,保護硬件廠商的知識產權(Linux是有開源協議的)
  • 系統運行庫層:怎么操縱硬件,顯示圖像到屏幕?這一層就是干這個的,它分為兩部分,分別是C++程序庫和Android運行時。 C++程序庫:被Android系統中的不同組件使用,可以通過應用框架層被開發者使用,下面是主要的程序庫: openGL ES 3D繪圖函數庫 Media Framework 多媒體庫 SQLite 關系型數據庫引擎 SSL 安全套接層 Android Runtime:ART虛擬機(5.0之后,Dalvik虛擬機被ART取代),ART在應用第一次安裝的時候,就會將字節碼預編譯成機器碼存儲到本地,這樣應用每次運行就無須執行編譯了(Dalvik是每次打開都要即時編譯),典型的以空間換時間 應用框架層:Framework層,這層代碼是用java編寫的,為開發人員提供了API。 應用層。

三. Activity活動的啟動模式及應用場景

  1. standard: 默認的模式,新建一個Activity就在棧中新建一個activity實例。
  2. singleTop:棧頂復用模式,與standard相比棧頂復用可以有效減少activity重復創建對資源的消耗 。 登錄頁面 ,wxpay等支付頁面
  3. singleTask:棧內單例模式,棧內只有一個activity實例,棧內已存activity實例,在其他activity中start這個activity,Android直接把這個實例上面其他activity實例踢出棧GC掉。主頁面 ,WebView頁面、掃一掃頁面 ,付款界面
  4. singleInstance:開辟一個新的棧存放activity。系統Launcher、鎖屏鍵、來電顯示等系統應用 。

四. Android進程間通信的方式

1.)傳統的IPC通信方式

Android系統是基于Linux內核的,Linux提供了管道、消息隊列、共享內存和socket等IPC機制。那為什么Android還要提供Binder來實現IPC呢?主要是基于性能、穩定性和安全性方面的考慮。

性能:socket作為通用接口,傳輸效率低,開銷大,主要用到跨網絡進程通信。消息隊列、共享內存和管道采用存儲-轉發模式,數據拷貝至少需要兩次,共享內存雖然無需拷貝,但是控制復雜,難以使用。而binder只需要拷貝一次,性能上只次于共享內存。

穩定性:Binder 基于 C/S 架構,客戶端(Client)有什么需求就丟給服務端(Server)去完成,架構清晰、職責明確又相互獨立,自然穩定性更好。

安全性:Android 為每個安裝好的 APP 分配了自己的 UID,故而進程的 UID 是鑒別進程身份的重要標志。傳統的 IPC 只能由用戶在數據包中填入 UID/PID,但這樣不可靠,容易被惡意程序利用。可靠的身份標識只有由 IPC 機制在內核中添加。其次傳統的 IPC 訪問接入點是開放的,只要知道這些接入點的程序都可以和對端建立連接,不管怎樣都無法阻止惡意程序通過猜測接收方地址獲得連接。

2.)傳統IPC通信原理

通常的做法是消息發送方將要發送的數據存放在內存緩存區中,通過系統調用進入內核態。然后內核程序在內核空間分配內存,開辟一塊內核緩存區,調用 copy_from_user() 函數將數據從用戶空間的內存緩存區拷貝到內核空間的內核緩存區中。同樣的,接收方進程在接收數據時在自己的用戶空間開辟一塊內存緩存區,然后內核程序調用 copy_to_user() 函數將數據從內核緩存區拷貝到接收進程的內存緩存區。這樣數據發送方進程和數據接收方進程就完成了一次數據傳輸,我們稱完成了一次進程間通信。

一次數據傳遞需要經歷:內存緩存區 --> 內核緩存區 --> 內存緩存區,需要 2 次數據拷貝

接收數據的緩存區由數據接收進程提供,但是接收進程并不知道需要多大的空間來存放將要傳遞過來的數據,因此只能開辟盡可能大的內存空間或者先調用 API 接收消息頭來獲取消息體的大小,這兩種做法不是浪費空間就是浪費時間。

3.)Binder IPC實現

Binder IPC 機制中涉及到的內存映射通過 mmap() 來實現,mmap() 是操作系統中一種內存映射的方法。內存映射簡單的講就是將用戶空間的一塊內存區域映射到內核空間。映射關系建立后,用戶對這塊內存區域的修改可以直接反應到內核空間;反之內核空間對這段區域的修改也能直接反應到用戶空間。

五. 多線程的實現方法(synchronized和lock的異同)

  1. 繼承Thread類創建線程
  2. 實現Runnable接口創建線程,推薦使用這種方式,可以復用runnable
  3. 實現Callbale接口,通過FutureTask包裝器來創建一個帶返回值的線程

synchronized

在用法上,它是java的關鍵字,一般我們不太需要關注他的鎖的釋放,代碼執行完畢或者報錯會自動釋放鎖,并且無法判斷鎖的狀態。

lock

是一個接口,我們使用ReentrantLock 比較多,有多個獲取鎖的方式,可以trylock直接返回獲取成功或者失敗,線程不用一直等待。在finally中必須要釋放該鎖。

六. 說一下View的事件分發機制

為什么要有事件分發

注:引用G神的博客:點擊鏈接直達

Android中的view是樹形結構的,view可能會重疊在一起,當我們點擊的地方有多個view的時候,這個時間該給誰,這就是為什么要有事件分發。

先來看看view的樹形結構:

上面多出來兩個東西是phonewindow和decorview,其中,主題顏色和標題欄內容等主要就是decorview來負責顯示的,那PhoneWindow是做什么的呢?

PhoneWindow 繼承window,并且是window唯一的實現類,window是一個抽象類,是所有視圖的最頂層容器,視圖的外觀和行為都歸他管,不論是背景顯示,標題欄還是事件處理都是他管理的范疇,它其實就像是View界的太上皇。

`DecorView` 是 `PhoneWindow` 的一個內部類,其職位相當于小太監,就是跟在 `PhoneWindow` 身邊專業為 `PhoneWindow` 服務的,除了自己要干活之外,也負責消息的傳遞,`PhoneWindow` 的指示通過 `DecorView` 傳遞給下面的 View,而下面 View 的信息也通過 `DecorView` 回傳給 `PhoneWindow`

事件分發、攔截、消費

類型 相關方法 Activity ViewGroup View 事件分發 dispatchTouchEvent √ √ √ 事件攔截 onInterceptTouchEvent X √ X 事件消費 onTouchEvent √ √ √

Activity作為原始的事件分發者,不需要攔截事件,如果需要這個事件不分發下去就行了。

同樣的,view在事件傳遞的最末端,也不需要攔截事件,不處理回傳回去就行了。

事件在收集之后最先傳遞給Activity,然后依次向下傳遞:

Activity -> PhoneWindow -> DectorView -> ViewGroup -> ... -> view

如果沒有任何View消費掉事件,那么這個事件會按照反方向回傳,最終傳回給Activity,如果最后 Activity 也沒有處理,本次事件才會被拋棄 :

Activity <- PhoneWindow <- DecorView <- ViewGroup <- ... <- View

上面的模式是一個非常經典的責任鏈模式

七、說一下View從app啟動到顯示在界面上的繪制流程

注:參考鏈接

在activity的attach方法里面,會創建一個PhoneWindow。

在onCreate中調用setContentView,setContentView是window的一個抽象方法,真正實現類是PhoneWindow:

 @Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {

//1.初始化
//創建DecorView對象和mContentParent對象 ,并將mContentParent關聯到DecorView上
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();//Activity轉場動畫相關
}

//2.填充Layout
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);//Activity轉場動畫相關
} else {
//將Activity設置的布局文件,加載到mContentParent中
mLayoutInflater.inflate(layoutResID, mContentParent);
}

//讓DecorView的內容區域延伸到systemUi下方,防止在擴展時被覆蓋,達到全屏、沉浸等不同體驗效果。
mContentParent.requestApplyInsets();

//3. 通知Activity布局改變
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {

//觸發Activity的onContentChanged方法
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}

核心方法就兩個:installDecor() 和 mLayoutInflater.inflate(layoutResID, mContentParent) ;

installDecor會創建一個DecorView 對象,該對象將作為整個應用窗口的根視圖。然后配置不同窗口修飾屬性(style theme等)。

mLayoutInflater.inflate就是解析xml,深度優先地遞歸解析xml,一層層添加到root view上,最終返回root view.解析的部分大致包含兩點:1.解析出View對象,2.解析View對應的Params,并設置給View。

八、知道什么會引起ANR嗎 怎么避免

有四種情況會造成ANR發生:

  1. 5秒內無法響應屏幕觸摸事件或鍵盤輸出
  2. 在執行前臺廣播的onReceive()函數時10秒沒有處理完成,后臺為20秒
  3. 前臺服務20秒內,后臺服務在200秒內沒有執行完成
  4. ContentProvider的publish在10s內沒進行完

如何避免:

盡量避免在主線程中做耗時操作。 多線程==>引出如何實現多線程,線程池的使用

如何分析ANR:

  1. 產生anr之后,會在data/anr/目錄下生成一個文件traces.txt
  2. Logcat中查看
  3. Java線程調用分析
  4. DDMS分析

九、有做過app的性能優化嗎

  1. app啟動加速:一個app的啟動分為三種不同的狀態,其中,我們只需要對第一種狀態做優化。對于App來說, 我們可以控制的啟動時間線無外乎Application的onCreate,首屏Activity的渲染。 冷啟動:App沒有啟動過或者App進程被kill,系統中不存在該App進程。此時App的啟動需要創建App進程,加載相關資源,啟動main thread,初始化首屏Activity等。 熱啟動:App進程只是處于后臺, 系統只是將其從后臺帶到前臺, 展示給用戶。屏幕會顯示一個空白的窗口(顏色基于主題), 直至activity渲染完畢。 溫啟動:介于冷啟動和熱啟動之間, 一般來說在以下兩種情況下發生, 用戶back退出了App, 然后又啟動. App進程可能還在運行, 但是activity需要重建 用戶退出App后, 系統可能由于內存原因將App殺死, 進程和activity都需要重啟, 但是可以在onCreate中將被動殺死鎖保存的狀態(saved instance state)恢復
  2. 布局優化 減少不必要的嵌套 盡量不要嵌套使用RelativeLayout 盡量不要在嵌套的LinearLayout中都使用weight屬性 ConstraintLayout 善用TextView的Drawable減少布局層級
  3. 響應優化
  4. 內存優化 bitmap的使用,options的jusdecodeBounds屬性,設置只解析bitmap的寬高等,然后使用insimplesize對bitmap進行壓縮。在android2.3的時代,bitmap的回收需要調用recycler方法,并且置空,但是之后只需要進行置空操作。 加載一張大圖:使用BitmapRegionDecode進行局部解碼, decodeRegion(Rect rect, BitmapFactory.Options options) 指定rect區域獲取圖像,options參數不支持inPurgeable,其他都支持 lru算法的實現=> LinkedHashMap
  5. 電池使用優化
  6. 網絡優化 參考:Android App優化, 要怎么做?

十、了解過Android最新技術嗎 使用過嗎

flutter

一步手機的刷新率為60hz,當一幀圖像繪制完畢后準備繪制下一幀時,顯示器會發出一個垂直同步信號(如VSync), 60Hz的屏幕就會一秒內發出 60次這樣的信號。而這個信號主要是用于同步CPU、GPU和顯示器的。

一般地來說,計算機系統中,CPU、GPU和顯示器以一種特定的方式協作:CPU將計算好的顯示內容提交給 GPU,GPU渲染后放入幀緩沖區,然后視頻控制器按照同步信號從幀緩沖區取幀數據傳遞給顯示器顯示。


我來說兩句
您需要登錄后才可以評論 登錄 | 立即注冊
facelist
所有評論(0)
領先的中文移動開發者社區
18620764416
7*24全天服務
意見反饋:[email protected]

掃一掃關注我們

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粵ICP備15117877號 )

龙江福彩p62开奖 股票型基金赚钱比例 最热门赚钱软件 开油边厂赚钱吗 兼职赚钱比较快的工作 捕鸟达人ipa 小米路由宝赚钱宝 四川麻将上下分找谁 舒城县有手工活在家赚钱 天龙八部手游能不能赚钱 捕鱼大富翁安卓版下载 小学门口卖台湾饭团赚钱吗 大满贯2单机二人麻将 开插画培训机构赚钱吗 超级力量2 赚钱 欢乐麻将单机版 wifi赚钱宝官网下载