【建議收藏】2020年中高級Android大廠面試祕籍,爲你保駕護航金三銀四,直通大廠(Android基礎篇)

前言

成爲一名優秀的Android開發,須要一份完備的知識體系,在這裏,讓咱們一塊兒成長爲本身所想的那樣~。

🔥 A awesome android expert interview questions and answers(continuous updating ...)javascript

從幾十份頂級面試倉庫和300多篇高質量面經中總結出一份全面成體系化的Android高級面試題集。前端

歡迎來到2020年中高級Android大廠面試祕籍,爲你保駕護航金三銀四,直通大廠的Android基礎篇。java

Android基礎面試題 (⭐⭐⭐)


一、什麼是ANR 如何避免它?

答:在Android上,若是你的應用程序有一段時間響應不夠靈敏,系統會向用戶顯示一個對話框,這個對話框稱做應 用程序無響應(ANR:Application NotResponding)對話框。 用戶能夠選擇讓程序繼續運行,可是,他們在使用你的 應用程序時,並不但願每次都要處理這個對話框。所以 ,在程序裏對響應性能的設計很重要這樣,這樣系統就不會顯 示ANR給用戶。android

不一樣的組件發生ANR的時間不同,Activity是5秒,BroadCastReceiver是10秒,Service是20秒(均爲前臺)。git

若是開發機器上出現問題,咱們能夠經過查看/data/anr/traces.txt便可,最新的ANR信息在最開始部分。github

  • 主線程被IO操做(從4.0以後網絡IO不容許在主線程中)阻塞。
  • 主線程中存在耗時的計算
  • 主線程中錯誤的操做,好比Thread.wait或者Thread.sleep等 Android系統會監控程序的響應情況,一旦出現下面兩種狀況,則彈出ANR對話框
  • 應用在5秒內未響應用戶的輸入事件(如按鍵或者觸摸)
  • BroadcastReceiver未在10秒內完成相關的處理
  • Service在特定的時間內沒法處理完成 20秒

修正:web

一、使用AsyncTask處理耗時IO操做。面試

二、使用Thread或者HandlerThread時,調用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)設置優先級,不然仍然會下降程序響應,由於默認Thread的優先級和主線程相同。算法

三、使用Handler處理工做線程結果,而不是使用Thread.wait()或者Thread.sleep()來阻塞主線程。shell

四、Activity的onCreate和onResume回調中儘可能避免耗時的代碼。 BroadcastReceiver中onReceive代碼也要儘可能減小耗時,建議使用IntentService處理。

解決方案:

將全部耗時操做,好比訪問網絡,Socket通訊,查詢大 量SQL 語句,複雜邏輯計算等都放在子線程中去,然 後經過handler.sendMessage、runonUIThread、AsyncTask、RxJava等方式更新UI。不管如何都要確保用戶界面的流暢 度。若是耗時操做須要讓用戶等待,那麼能夠在界面上顯示度條。

深刻回答

二、Activity和Fragment生命週期有哪些?

image

三、橫豎屏切換時候Activity的生命週期

不設置Activity的android:configChanges時,切屏會從新回調各個生命週期,切橫屏時會執行一次,切豎屏時會執行兩次。 設置Activity的android:configChanges=」orientation」時,切屏仍是會調用各個生命週期,切換橫豎屏只會執行一次 設置Activity的android:configChanges=」orientation |keyboardHidden」時,切屏不會從新調用各個生命週期,只會執行onConfigurationChanged方法

四、AsyncTask的缺陷和問題,說說他的原理。

AsyncTask是什麼?

AsyncTask是一種輕量級的異步任務類,它能夠在線程池中執行後臺任務,而後把執行的進度和最終結果傳遞給主線程並在主線程中更新UI。

AsyncTask是一個抽象的泛型類,它提供了Params、Progress和Result這三個泛型參數,其中Params表示參數的類型,Progress表示後臺任務的執行進度和類型,而Result則表示後臺任務的返回結果的類型,若是AsyncTask不須要傳遞具體的參數,那麼這三個泛型參數能夠用Void來代替。

關於線程池:

AsyncTask對應的線程池ThreadPoolExecutor都是進程範圍內共享的,且都是static的,因此是Asynctask控制着進程範圍內全部的子類實例。因爲這個限制的存在,當使用默認線程池時,若是線程數超過線程池的最大容量,線程池就會爆掉(3.0後默認串行執行,不會出現個問題)。針對這種狀況,能夠嘗試自定義線程池,配合Asynctask使用。

關於默認線程池:

AsyncTask裏面線程池是一個核心線程數爲CPU + 1,最大線程數爲CPU * 2 + 1,工做隊列長度爲128的線程池,線程等待隊列的最大等待數爲28,可是能夠自定義線程池。線程池是由AsyncTask來處理的,線程池容許tasks並行運行,須要注意的是併發狀況下數據的一致性問題,新數據可能會被老數據覆蓋掉。因此但願tasks可以串行運行的話,使用SERIAL_EXECUTOR。

AsyncTask在不一樣的SDK版本中的區別:

調用AsyncTask的execute方法不能當即執行程序的緣由及改善方案經過查閱官方文檔發現,AsyncTask首次引入時,異步任務是在一個獨立的線程中順序的執行,也就是說一次只執行一個任務,不能並行的執行,從1.6開始,AsyncTask引入了線程池,支持同時執行5個異步任務,也就是說只能有5個線程運行,超過的線程只能等待,等待前的線程直到某個執行完了才被調度和運行。換句話說,若是進程中的AsyncTask實例個數超過5個,那麼假如前5都運行很長時間的話,那麼第6個只能等待機會了。這是AsyncTask的一個限制,並且對於2.3之前的版本沒法解決。若是你的應用須要大量的後臺線程去執行任務,那麼只能放棄使用AsyncTask,本身建立線程池來管理Thread。不得不說,雖然AsyncTask較Thread使用起來方便,可是它最多隻能同時運行5個線程,這也大大侷限了它的做用,你必需要當心設計你的應用,錯開使用AsyncTask時間,盡力作到分時,或者保證數量不會大於5個,否就會遇到上面提到的問題。多是Google意識到了AsynTask的侷限性了,從Android 3.0開始對AsyncTask的API作出了一些調整:每次只啓動一個線程執行一個任務,完了以後再執行第二個任務,也就是至關於只有一個後臺線程在執行所提交的任務。

一些問題:

1.生命週期

不少開發者會認爲一個在Activity中建立的AsyncTask會隨着Activity的銷燬而銷燬。然而事實並不是如此。AsynTask會一直執行,直到doInBackground()方法執行完畢,而後,若是cancel(boolean)被調用,那麼onCancelled(Result result)方法會被執行;不然,執行onPostExecute(Result result)方法。若是咱們的Activity銷燬以前,沒有取消AsyncTask,這有可能讓咱們的應用崩潰(crash)。由於它想要處理的view已經不存在了。因此,咱們是必須確保在銷燬活動以前取消任務。總之,咱們使用AsyncTask須要確保AsyncTask正確的取消。

2.內存泄漏

若是AsyncTask被聲明爲Activity的非靜態內部類,那麼AsyncTask會保留一個對Activity的引用。若是Activity已經被銷燬,AsyncTask的後臺線程還在執行,它將繼續在內存裏保留這個引用,致使Activity沒法被回收,引發內存泄漏。

3.結果丟失

屏幕旋轉或Activity在後臺被系統殺掉等狀況會致使Activity的從新建立,以前運行的AsyncTask會持有一個以前Activity的引用,這個引用已經無效,這時調用onPostExecute()再去更新界面將再也不生效。

4.並行仍是串行

在Android1.6以前的版本,AsyncTask是串行的,在1.6以後的版本,採用線程池處理並行任務,可是從Android 3.0開始,爲了不AsyncTask所帶來的併發錯誤,又採用一個線程來串行執行任務。能夠使用executeOnExecutor()方法來並行地執行任務。

AsyncTask原理
  • AsyncTask中有兩個線程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一個Handler(InternalHandler),其中線程池SerialExecutor用於任務的排隊,而線程池THREAD_POOL_EXECUTOR用於真正地執行任務,InternalHandler用於將執行環境從線程池切換到主線程。
  • sHandler是一個靜態的Handler對象,爲了可以將執行環境切換到主線程,這就要求sHandler這個對象必須在主線程建立。因爲靜態成員會在加載類的時候進行初始化,所以這就變相要求AsyncTask的類必須在主線程中加載,不然同一個進程中的AsyncTask都將沒法正常工做。

五、onSaveInstanceState() 與 onRestoreIntanceState()

Activity的 onSaveInstanceState() 和 onRestoreInstanceState()並非生命週期方法,它們不一樣於 onCreate()、onPause()等生命週期方法,它們並不必定會被觸發。當應用遇到意外狀況(如:內存不足、用戶直接按Home鍵)由系統銷燬一個Activity時,onSaveInstanceState() 會被調用。可是當用戶主動去銷燬一個Activity時,例如在應用中按返回鍵,onSaveInstanceState()就不會被調用。由於在這種狀況下,用戶的行爲決定了不須要保存Activity的狀態。一般onSaveInstanceState()只適合用於保存一些臨時性的狀態,而onPause()適合用於數據的持久化保存。 在activity被殺掉以前調用保存每一個實例的狀態,以保證該狀態能夠在onCreate(Bundle)或者onRestoreInstanceState(Bundle) (傳入的Bundle參數是由onSaveInstanceState封裝好的)中恢復。這個方法在一個activity被殺死前調用,當該activity在未來某個時刻回來時能夠恢復其先前狀態。 例如,若是activity B啓用後位於activity A的前端,在某個時刻activity A由於系統回收資源的問題要被殺掉,A經過onSaveInstanceState將有機會保存其用戶界面狀態,使得未來用戶返回到activity A時能經過onCreate(Bundle)或者onRestoreInstanceState(Bundle)恢復界面的狀態

深刻理解

六、android中進程的優先級?

1. 前臺進程:

即與用戶正在交互的Activity或者Activity用到的Service等,若是系統內存不足時前臺進程是最晚被殺死的

2. 可見進程:

能夠是處於暫停狀態(onPause)的Activity或者綁定在其上的Service,即被用戶可見,但因爲失了焦點而不能與用戶交互

3. 服務進程:

其中運行着使用startService方法啓動的Service,雖然不被用戶可見,可是倒是用戶關心的,例如用戶正在非音樂界面聽的音樂或者正在非下載頁面下載的文件等;當系統要空間運行,前二者進程纔會被終止

4. 後臺進程:

其中運行着執行onStop方法而中止的程序,可是卻不是用戶當前關心的,例如後臺掛着的QQ,這時的進程系統一旦沒了有內存就首先被殺死

5. 空進程:

不包含任何應用程序的進程,這樣的進程系統是通常不會讓他存在的

七、Bunder傳遞對象爲何須要序列化?Serialzable和Parcelable的區別?

由於bundle傳遞數據時只支持基本數據類型,因此在傳遞對象時須要序列化轉換成可存儲或可傳輸的本質狀態(字節流)。序列化後的對象能夠在網絡、IPC(好比啓動另外一個進程的Activity、Service和Reciver)之間進行傳輸,也能夠存儲到本地。

Serializable(Java自帶):

Serializable 是序列化的意思,表示將一個對象轉換成存儲或可傳輸的狀態。序列化後的對象能夠在網絡上進傳輸,也能夠存儲到本地。

Parcelable(android專用):

除了Serializable以外,使用Parcelable也能夠實現相同的效果,不過不一樣於將對象進行序列化,Parcelable方式的實現原理是將一個完整的對象進行分解,而分解後的每一部分都是Intent所支持的數據類型,這也就實現傳遞對象的功能了。

區別總結以下圖所示:

image

八、動畫

  • tween 補間動畫。經過指定View的初末狀態和變化方式,對View的內容完成一系列的圖形變換來實現動畫效果。 Alpha, Scale ,Translate, Rotate。
  • frame 幀動畫。AnimationDrawable控制animation-list.xml佈局
  • PropertyAnimation 屬性動畫3.0引入,屬性動畫核心思想是對值的變化。

Property Animation 動畫有兩個步聚:

1.計算屬性值

2.爲目標對象的屬性設置屬性值,即應用和刷新動畫

image

計算屬性分爲3個過程:

過程一:

計算已完成動畫分數 elapsed fraction。爲了執行一個動畫,你須要建立一個ValueAnimator,而且指定目標對象屬性的開始、結束和持續時間。在調用 start 後的整個動畫過程當中,ValueAnimator 會根據已經完成的動畫時間計算獲得一個0 到 1 之間的分數,表明該動畫的已完成動畫百分比。0表示 0%,1 表示 100%。

過程二:

計算插值(動畫變化率)interpolated fraction 。當 ValueAnimator計算完已完成的動畫分數後,它會調用當前設置的TimeInterpolator,去計算獲得一個interpolated(插值)分數,在計算過程當中,已完成動畫百分比會被加入到新的插值計算中。

過程三:

計算屬性值當插值分數計算完成後,ValueAnimator會根據插值分數調用合適的 TypeEvaluator去計算運動中的屬性值。 以上分析引入了兩個概念:已完成動畫分數(elapsed fraction)、插值分數( interpolated fraction )。

原理及特色:

1.屬性動畫:

插值器:做用是根據時間流逝的百分比來計算屬性變化的百分比

估值器:在1的基礎上由這個東西來計算出屬性到底變化了多少數值的類

其實就是利用插值器和估值器,來計出各個時刻View的屬性,而後經過改變View的屬性來實現View的動畫效果。

2.View動畫:

只是影像變化,view的實際位置還在原來地方。

3.幀動畫:

是在xml中定義好一系列圖片以後,使用AnimatonDrawable來播放的動畫。

它們的區別:

屬性動畫纔是真正的實現了 view 的移動,補間動畫對view 的移動更像是在不一樣地方繪製了一個影子,實際對象仍是處於原來的地方。 當動畫的 repeatCount 設置爲無限循環時,若是在Activity退出時沒有及時將動畫中止,屬性動畫會致使Activity沒法釋放而致使內存泄漏,而補間動畫卻沒問題。 xml 文件實現的補間動畫,複用率極高。在 Activity切換,窗口彈出時等情景中有着很好的效果。 使用幀動畫時須要注意,不要使用過多特別大的圖,容致使內存不足。

爲何屬性動畫移動後仍可點擊?

播放補間動畫的時候,咱們所看到的變化,都只是臨時的。而屬性動畫呢,它所改變的東西,卻會更新到這個View所對應的矩陣中,因此當ViewGroup分派事件的時候,會正確的將當前觸摸座標,轉換成矩陣變化後的座標,這就是爲何播放補間動畫不會改變觸摸區域的緣由了。

九、Context相關

  • 一、Activity和Service以及Application的Context是不同的,Activity繼承自ContextThemeWraper.其餘的繼承自ContextWrapper。

  • 二、每個Activity和Service以及Application的Context是一個新的ContextImpl對象。

  • 三、getApplication()用來獲取Application實例的,可是這個方法只有在Activity和Service中才能調用的到。那也許在絕大多數狀況下咱們都是在Activity或者Servic中使用Application的,可是若是在一些其它的場景,好比BroadcastReceiver中也想得到Application的實例,這時就能夠藉助getApplicationContext()方法,getApplicationContext()比getApplication()方法的做用域會更廣一些,任何一個Context的實例,只要調用getApplicationContext()方法均可以拿到咱們的Application對象。

  • 四、建立對話框時不能夠用Application的context,只能用Activity的context。

  • 五、Context的數量等於Activity的個數 + Service的個數 +1,這個1爲Application。

十、Android各版本新特性

Android5.0新特性
  • MaterialDesign設計風格

  • 支持64位ART虛擬機(5.0推出的ART虛擬機,在5.0以前都是Dalvik。他們的區別是: Dalvik,每次運行,字節碼都須要經過即時編譯器轉換成機器碼(JIT)。 ART,第一次安裝應用的時候,字節碼就會預先編譯成機器碼(AOT))

  • 通知詳情能夠用戶本身設計

Android6.0新特性
  • 動態權限管理

  • 支持快速充電的切換

  • 支持文件夾拖拽應用

  • 相機新增專業模式

Android7.0新特性
  • 多窗口支持

  • V2簽名

  • 加強的Java8語言模式

  • 夜間模式

Android8.0(O)新特性
  • 優化通知

    通知渠道 (Notification Channel) 通知標誌 休眠 通知超時 通知設置 通知清除

  • 畫中畫模式:清單中Activity設置android:supportsPictureInPicture

  • 後臺限制

  • 自動填充框架

  • 系統優化

  • 等等優化不少

Android9.0(P)新特性
  • 室內WIFI定位

  • 「劉海」屏幕支持

  • 安全加強

  • 等等優化不少

Android10.0(Q)目前曝光的新特性
  • 夜間模式:包括手機上的全部應用均可覺得其設置暗黑模式。
  • 桌面模式:提供相似於PC的體驗,可是遠遠不能代替PC。
  • 屏幕錄製:經過長按「電源」菜單中的"屏幕快照"來開啓。

十一、Json

JSON的全稱是JavaScript Object Notation,也就是JavaScript 對象表示法 JSON是存儲和交換文本信息的語法,相似XML,可是比XML更小、更快,更易解析 JSON是輕量級的文本數據交換格式,獨立於語言,具備可描述性,更易理解,對象能夠包含多個名稱/值對,好比:

{"name":"zhangsan" , "age":25}
複製代碼

使用谷歌的GSON包進行解析,在 Android Studio 裏引入依賴:

compile 'com.google.code.gson:gson:2.7'
複製代碼

值得注意的是實體類中變量名稱必須和json中的值名字相同。

使用示例:

一、解析成實體類:

Gson gson = new Gson();
Student student = gson.fromJson(json1, Student.class);
複製代碼

二、解析成int數組:

Gson gson = new Gson();
int[] ages = gson.fromJson(json2, int[].class);
複製代碼

三、直接解析成List.

Gson gson = new Gson();
List<Integer> ages = gson.fromJson(json2,  newTypeToken<List<Integer>>(){}.getType);

Gson gson = new Gson();
List<Student> students = gson.fromJson(json3, newTypeToke<List<Student>>(){}.getType);
複製代碼
優勢:
  • 輕量級的數據交換格式
  • 讀寫更加容易
  • 易於機器的解析和生成
缺點:
  • 語義性較差,不如 xml 直觀

十二、android中有哪幾種解析xml的類,官方推薦哪一種?以及它們的原理和區別?

DOM解析

優勢:

1.XML樹在內存中完整存儲,所以能夠直接修改其數據結構.

2.能夠經過該解析器隨時訪問XML樹中的任何一個節點.

3.DOM解析器的API在使用上也相對比較簡單.

缺點:

若是XML文檔體積比較大時,將文檔讀入內存是非消耗系統資源的.

使用場景:

  • DOM 是與平臺和語言無關的方式表示 XML文檔的官方 W3C 標準.
  • DOM 是以層次結構組織的節點的集合.這個層次結構容許開人員在樹中尋找特定信息.分析該結構一般須要加載整個文檔和構造層次結構,而後才能進行任何工做.
  • DOM 是基於對象層次結構的.
SAX解析

優勢:

SAX 對內存的要求比較低,由於它讓開發人員本身來決定所要處理的標籤.特別是當開發人員只須要處理文檔中包含的部分數據時,SAX 這種擴展能力獲得了更好的體現.

缺點:

用SAX方式進行XML解析時,須要順序執行,因此很難訪問同一文檔中的不一樣數據.此外,在基於該方式的解析編碼程序也相對複雜.

使用場景:

對於含有數據量十分巨大,而又不用對文檔的全部數據行遍歷或者分析的時候,使用該方法十分有效.該方法不將整個文檔讀入內存,而只需讀取到程序所需的文檔標記處便可.

Xmlpull解析

android SDK提供了xmlpullapi,xmlpull和sax相似,是基於流(stream)操做文件,後者根據節點事件回調開發者編寫的處理程序.由於是基於流的處理,所以xmlpull和sax都比較節約內存資源,不會像dom那樣要把全部節點以對象樹的形式展示在內存中.xmpull比sax更簡明,並且不須要掃描完整個流.

1三、Jar和Aar的區別

Jar包裏面只有代碼,aar裏面不光有代碼還包括資源文件,好比 drawable 文件,xml資源文件。對於一些不常變更的 Android Library,咱們能夠直接引用 aar,加快編譯速度。

1四、Android爲每一個應用程序分配的內存大小是多少

android程序內存通常限制在16M,也有的是24M。近幾年手機發展較快,通常都會分配兩百兆左右,和具體機型有關。

1五、更新UI方式

  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable),View.postDelay(Runnable, long)(能夠理解爲在當前操做視圖UI線程添加隊列)
  • Handler
  • AsyncTask
  • Rxjava
  • LiveData

1六、ContentProvider使用方法。

進行跨進程通訊,實現進程間的數據交互和共享。經過Context 中 getContentResolver() 得到實例,經過 Uri匹配進行數據的增刪改查。ContentProvider使用表的形式來組織數據,不管數據的來源是什麼,ConentProvider 都會認爲是一種表,而後把數據組織成表格。

1七、Thread、AsyncTask、IntentService的使用場景與特色。

  1. Thread線程,獨立運行與於 Activity 的,當Activity 被 finish 後,若是沒有主動中止 Thread或者 run 方法沒有執行完,其會一直執行下去。

  2. AsyncTask 封裝了兩個線程池和一個Handler(SerialExecutor用於排隊,THREAD_POOL_EXECUTOR爲真正的執行任務,Handler將工做線程切換到主線程),其必須在 UI線程中建立,execute 方法必須在 UI線程中執行,一個任務實例只容許執行一次,執行屢次拋出異常,用於網絡請求或者簡單數據處理。

  3. IntentService:處理異步請求,實現多線程,在onHandleIntent中處理耗時操做,多個耗時任務會依次執行,執行完畢自動結束。

1八、Merge、ViewStub 的做用。

Merge: 減小視圖層級,能夠刪除多餘的層級。

ViewStub: 按需加載,減小內存使用量、加快渲染速度、不支持 merge 標籤。

1九、activity的startActivity和context的startActivity區別?

(1)、從Activity中啓動新的Activity時能夠直接mContext.startActivity(intent)就好

(2)、若是從其餘Context中啓動Activity則必須給intent設置Flag:

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) ; 
mContext.startActivity(intent);
複製代碼
20、怎麼在Service中建立Dialog對話框?

1.在咱們取得Dialog對象後,需給它設置類型,即:

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
複製代碼

2.在Manifest中加上權限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINOW" />
複製代碼

2一、Asset目錄與res目錄的區別?

assets:不會在 R 文件中生成相應標記,存放到這裏的資源在打包時會打包到程序安裝包中。(經過 AssetManager 類訪問這些文件)

res:會在 R 文件中生成 id 標記,資源在打包時若是使用到則打包到安裝包中,未用到不會打入安裝包中。

res/anim:存放動畫資源。

res/raw:和 asset 下文件同樣,打包時直接打入程序安裝包中(會映射到 R 文件中)。

2二、Android怎麼加速啓動Activity?

  • onCreate() 中不執行耗時操做 把頁面顯示的 View 細分一下,放在 AsyncTask 裏逐步顯示,用 Handler 更好。這樣用戶的看到的就是有層次有步驟的一個個的 View 的展現,不會是先看到一個黑屏,而後一下顯示全部 View。最好作成動畫,效果更天然。
  • 利用多線程的目的就是儘量的減小 onCreate() 和 onReume() 的時間,使得用戶能儘快看到頁面,操做頁面。
  • 減小主線程阻塞時間。
  • 提升 Adapter 和 AdapterView 的效率。
  • 優化佈局文件。

2三、Handler機制

Android消息循環流程圖以下所示:

image

主要涉及的角色以下所示:

  • message:消息。
  • MessageQueue:消息隊列,負責消息的存儲與管理,負責管理由 Handler 發送過來的 Message。讀取會自動刪除消息,單鏈表維護,插入和刪除上有優點。在其next()方法中會無限循環,不斷判斷是否有消息,有就返回這條消息並移除。
  • Looper:消息循環器,負責關聯線程以及消息的分發,在該線程下從 MessageQueue獲取 Message,分發給Handler,Looper建立的時候會建立一個 MessageQueue,調用loop()方法的時候消息循環開始,其中會不斷調用messageQueue的next()方法,當有消息就處理,不然阻塞在messageQueue的next()方法中。當Looper的quit()被調用的時候會調用messageQueue的quit(),此時next()會返回null,而後loop()方法也就跟着退出。
  • Handler:消息處理器,負責發送並處理消息,面向開發者,提供 API,並隱藏背後實現的細節。

整個消息的循環流程仍是比較清晰的,具體說來:

  • 一、Handler經過sendMessage()發送消息Message到消息隊列MessageQueue。
  • 二、Looper經過loop()不斷提取觸發條件的Message,並將Message交給對應的target handler來處理。
  • 三、target handler調用自身的handleMessage()方法來處理Message。

事實上,在整個消息循環的流程中,並不僅有Java層參與,不少重要的工做都是在C++層來完成的。咱們來看下這些類的調用關係。

image

注:虛線表示關聯關係,實線表示調用關係。

在這些類中MessageQueue是Java層與C++層維繫的橋樑,MessageQueue與Looper相關功能都經過MessageQueue的Native方法來完成,而其餘虛線鏈接的類只有關聯關係,並無直接調用的關係,它們發生關聯的橋樑是MessageQueue。

總結
  • Handler 發送的消息由 MessageQueue 存儲管理,並由 Looper 負責回調消息到 handleMessage()。
  • 線程的轉換由 Looper 完成,handleMessage() 所在線程由 Looper.loop() 調用者所在線程決定。
Handler 引發的內存泄露緣由以及最佳解決方案

Handler 容許咱們發送延時消息,若是在延時期間用戶關閉了 Activity,那麼該 Activity 會泄露。 這個泄露是由於 Message 會持有 Handler,而又由於 Java 的特性,內部類會持有外部類,使得 Activity 會被 Handler 持有,這樣最終就致使 Activity 泄露。

解決:將 Handler 定義成靜態的內部類,在內部持有 Activity 的弱引用,並在Acitivity的onDestroy()中調用handler.removeCallbacksAndMessages(null)及時移除全部消息。

爲何咱們能在主線程直接使用 Handler,而不須要建立 Looper ?

一般咱們認爲 ActivityThread 就是主線程。事實上它並非一個線程,而是主線程操做的管理者。在 ActivityThread.main() 方法中調用了 Looper.prepareMainLooper() 方法建立了 主線程的 Looper ,而且調用了 loop() 方法,因此咱們就能夠直接使用 Handler 了。

所以咱們能夠利用 Callback 這個攔截機制來攔截 Handler 的消息。如大部分插件化框架中Hook ActivityThread.mH 的處理。

主線程的 Looper 不容許退出

主線程不容許退出,退出就意味 APP 要掛。

Handler 裏藏着的 Callback 能幹什麼?

Handler.Callback 有優先處理消息的權利 ,當一條消息被 Callback 處理並攔截(返回 true),那麼 Handler 的 handleMessage(msg) 方法就不會被調用了;若是 Callback 處理了消息,可是並無攔截,那麼就意味着一個消息能夠同時被 Callback 以及 Handler 處理。

建立 Message 實例的最佳方式

爲了節省開銷,Android 給 Message 設計了回收機制,因此咱們在使用的時候儘可能複用 Message ,減小內存消耗:

  • 經過 Message 的靜態方法 Message.obtain();
  • 經過 Handler 的公有方法 handler.obtainMessage()。
子線程裏彈 Toast 的正確姿式

本質上是由於 Toast 的實現依賴於 Handler,按子線程使用 Handler 的要求修改便可,同理的還有 Dialog。

妙用 Looper 機制
  • 將 Runnable post 到主線程執行;
  • 利用 Looper 判斷當前線程是不是主線程。
主線程的死循環一直運行是否是特別消耗CPU資源呢?

並非,這裏就涉及到Linux pipe/epoll機制,簡單說就是在主線程的MessageQueue沒有消息時,便阻塞在loop的queue.next()中的nativePollOnce()方法裏,此時主線程會釋放CPU資源進入休眠狀態,直到下個消息到達或者有事務發生,經過往pipe管道寫端寫入數據來喚醒主線程工做。這裏採用的epoll機制,是一種IO多路複用機制,能夠同時監控多個描述符,當某個描述符就緒(讀或寫就緒),則馬上通知相應程序進行讀或寫操做,本質是同步I/O,即讀寫是阻塞的。因此說,主線程大多數時候都是處於休眠狀態,並不會消耗大量CPU資源。

handler postDelay這個延遲是怎麼實現的?

handler.postDelay並非先等待必定的時間再放入到MessageQueue中,而是直接進入MessageQueue,以MessageQueue的時間順序排列和喚醒的方式結合實現的。

如何保證在msg.postDelay狀況下保證消息次序?

Handler 都沒搞懂,拿什麼去跳槽啊?

2四、程序A可否接收到程序B的廣播?

能,使用全局的BroadCastRecevier能進行跨進程通訊,可是注意它只能被動接收廣播。此外,LocalBroadCastRecevier只限於本進程的廣播間通訊。

2五、數據加載更多涉及到分頁,你是怎麼實現的?

分頁加載就是一頁一頁加載數據,當滑動到底部、沒有更多數據加載的時候,咱們能夠手動調用接口,從新刷新RecyclerView。

2六、經過google提供的Gson解析json時,定義JavaBean的規則是什麼?

1). 實現序列化 Serializable

2). 屬性私有化,並提供get,set方法

3). 提供無參構造

4). 屬性名必須與json串中屬性名保持一致 (由於Gson解析json串底層用到了Java的反射原理)

2七、json解析方式的兩種區別?

1,SDK提供JSONArray,JSONObject

2,google提供的 Gson 經過fromJson()實現對象的反序列化(即將json串轉換爲對象類型) 經過toJson()實現對象的序列化 (即將對象類型轉換爲json串)

2八、線程池的相關知識。

Android中的線程池都是直接或間接經過配置ThreadPoolExecutor來實現不一樣特性的線程池.Android中最多見的類具備不一樣特性的線程池分別爲FixThreadPool、CachedhreadPool、SingleThreadPool、ScheduleThreadExecutr.

1).FixThreadPool

只有核心線程,而且數量固定的,也不會被回收,全部線程都活動時,由於隊列沒有限制大小,新任務會等待執行.

優勢:更快的響應外界請求.

2).SingleThreadPool

只有一個核心線程,確保全部的任務都在同一線程中按序完成.所以不須要處理線程同步的問題.

3).CachedThreadPool

只有非核心線程,最大線程數很是大,全部線程都活動時會爲新任務建立新線程,不然會利用空閒線程(60s空閒時間,過了就會被回收,因此線程池中有0個線程的可能)處理任務.

優勢:任何任務都會被當即執行(任務隊列SynchronousQuue至關於一個空集合);比較適合執行大量的耗時較少的任務.

4).ScheduledThreadPool

核心線程數固定,非核心線程(閒着沒活幹會被當即回收數)沒有限制.

優勢:執行定時任務以及有固定週期的重複任務

2九、內存泄露,怎樣查找,怎麼產生的內存泄露?

1.資源對象沒關閉形成的內存泄漏

描述: 資源性對象好比(Cursor,File文件等)每每都用了一些緩衝,咱們在不使用的時候,應該及時關閉它們,以便它們的緩衝及時回收內存。它們的緩衝不只存在於 java虛擬機內,還存在於java虛擬機外。若是咱們僅僅是把它的引用設置爲null,而不關閉它們,每每會形成內存泄漏。由於有些資源性對象,好比SQLiteCursor(在析構函數finalize(),若是咱們沒有關閉它,它本身會調close()關閉),若是咱們沒有關閉它,系統在回收它時也會關閉它,可是這樣的效率過低了。所以對於資源性對象在不使用的時候,應該調用它的close()函數,將其關閉掉,而後才置爲null.在咱們的程序退出時必定要確保咱們的資源性對象已經關閉。

程序中常常會進行查詢數據庫的操做,可是常常會有使用完畢Cursor後沒有關閉的狀況。若是咱們的查詢結果集比較小,對內存的消耗不容易被發現,只有在常時間大量操做的狀況下才會復現內存問題,這樣就會給之後的測試和問題排查帶來困難和風險。

2.構造Adapter時,沒有使用緩存的convertView

描述: 以構造ListView的BaseAdapter爲例,在BaseAdapter中提供了方法: public View getView(int position, ViewconvertView, ViewGroup parent) 來向ListView提供每個item所須要的view對象。初始時ListView會從BaseAdapter中根據當前的屏幕布局實例化必定數量的 view對象,同時ListView會將這些view對象緩存起來。當向上滾動ListView時,原先位於最上面的list item的view對象會被回收,而後被用來構造新出現的最下面的list item。這個構造過程就是由getView()方法完成的,getView()的第二個形參View convertView就是被緩存起來的list item的view對象(初始化時緩存中沒有view對象則convertView是null)。由此能夠看出,若是咱們不去使用 convertView,而是每次都在getView()中從新實例化一個View對象的話,即浪費資源也浪費時間,也會使得內存佔用愈來愈大。 ListView回收list item的view對象的過程能夠查看: android.widget.AbsListView.java --> voidaddScrapView(View scrap) 方法。 示例代碼:

public View getView(int position, ViewconvertView, ViewGroup parent) {
View view = new Xxx(...); 
... ... 
return view; 
}
複製代碼

修正示例代碼:

public View getView(int position, ViewconvertView, ViewGroup parent) {
View view = null; 
if (convertView != null) { 
view = convertView; 
populate(view, getItem(position)); 
... 
} else { 
view = new Xxx(...); 
... 
} 
return view; 
}
複製代碼

3.Bitmap對象不在使用時調用recycle()釋放內存

描述: 有時咱們會手工的操做Bitmap對象,若是一個Bitmap對象比較佔內存,當它不在被使用的時候,能夠調用Bitmap.recycle()方法回收此對象的像素所佔用的內存,但這不是必須的,視狀況而定。能夠看一下代碼中的註釋:

/* •Free up the memory associated with thisbitmap's pixels, and mark the •bitmap as "dead", meaning itwill throw an exception if getPixels() or •setPixels() is called, and will drawnothing. This operation cannot be •reversed, so it should only be called ifyou are sure there are no •further uses for the bitmap. This is anadvanced call, and normally need •not be called, since the normal GCprocess will free up this memory when •there are no more references to thisbitmap. /

4.試着使用關於application的context來替代和activity相關的context

這是一個很隱晦的內存泄漏的狀況。有一種簡單的方法來避免context相關的內存泄漏。最顯著地一個是避免context逃出他本身的範圍以外。使用Application context。這個context的生存週期和你的應用的生存週期同樣長,而不是取決於activity的生存週期。若是你想保持一個長期生存的對象,而且這個對象須要一個context,記得使用application對象。你能夠經過調用 Context.getApplicationContext() or Activity.getApplication()來得到。更多的請看這篇文章如何避免 Android內存泄漏。

5.註冊沒取消形成的內存泄漏

一些Android程序可能引用咱們的Anroid程序的對象(好比註冊機制)。即便咱們的Android程序已經結束了,可是別的引用程序仍然還有對咱們的Android程序的某個對象的引用,泄漏的內存依然不能被垃圾回收。調用registerReceiver後未調用unregisterReceiver。 好比:假設咱們但願在鎖屏界面(LockScreen)中,監聽系統中的電話服務以獲取一些信息(如信號強度等),則能夠在LockScreen中定義一個 PhoneStateListener的對象,同時將它註冊到TelephonyManager服務中。對於LockScreen對象,當須要顯示鎖屏界面的時候就會建立一個LockScreen對象,而當鎖屏界面消失的時候LockScreen對象就會被釋放掉。 可是若是在釋放 LockScreen對象的時候忘記取消咱們以前註冊的PhoneStateListener對象,則會致使LockScreen沒法被垃圾回收。若是不斷的使鎖屏界面顯示和消失,則最終會因爲大量的LockScreen對象沒有辦法被回收而引發OutOfMemory,使得system_process 進程掛掉。 雖然有些系統程序,它自己好像是能夠自動取消註冊的(固然不及時),可是咱們仍是應該在咱們的程序中明確的取消註冊,程序結束時應該把全部的註冊都取消掉。

6.集合中對象沒清理形成的內存泄漏

咱們一般把一些對象的引用加入到了集合中,當咱們不須要該對象時,並無把它的引用從集合中清理掉,這樣這個集合就會愈來愈大。若是這個集合是static的話,那狀況就更嚴重了。

查找內存泄漏能夠使用Android Studio 自帶的AndroidProfiler工具或MAT,也能夠使用Square產品的LeakCanary.

一、使用AndroidProfiler的MEMORY工具:

運行程序,對每個頁面進行內存分析檢查。首先,反覆打開關閉頁面5次,而後收到GC(點擊Profile MEMORY左上角的垃圾桶圖標),若是此時total內存尚未恢復到以前的數值,則可能發生了內存泄露。此時,再點擊Profile MEMORY左上角的垃圾桶圖標旁的heap dump按鈕查看當前的內存堆棧狀況,選擇按包名查找,找到當前測試的Activity,若是引用了多個實例,則代表發生了內存泄露。

二、使用MAT:

一、運行程序,全部功能跑一遍,確保沒有改出問題,徹底退出程序,手動觸發GC,而後使用adb shell dumpsys meminfo packagename -d命令查看退出界面後Objects下的Views和Activities數目是否爲0,若是不是則經過Leakcanary檢查可能存在內存泄露的地方,最後經過MAT分析,如此反覆,改善滿意爲止。

一、在使用MAT以前,先使用as的Profile中的Memory去獲取要分析的堆內存快照文件.hprof,若是要測試某個頁面是否產生內存泄漏,能夠先dump出沒進入該頁面的內存快照文件.hprof,而後,一般執行5次進入/退出該頁面,而後再dump出此刻的內存快照文件.hprof,最後,將二者比較,若是內存相除明顯,則可能發生內存泄露。(注意:MAT須要標準的.hprof文件,所以在as的Profiler中GC後dump出的內存快照文件.hprof必須手動使用android sdk platform-tools下的hprof-conv程序進行轉換才能被MAT打開)

二、而後,使用MAT打開前面保存的2份.hprof文件,打開Overview界面,在Overview界面下面有4中action,其中最經常使用的就是Histogram和Dominator Tree。

Dominator Tree:支配樹,按對象大小降序列出對象和其所引用的對象,注重引用關係分析。選擇Group by package,找到當前要檢測的類(或者使用頂部的Regex直接搜索),查看它的Object數目是否正確,若是多了,則判斷髮生了內存泄露。而後,右擊該類,選擇Merge Shortest Paths to GC Root中的exclude all phantom/weak/soft etc.references選項來查看該類的GC強引用鏈。最後,經過引用鏈便可看到最終強引用該類的對象。

Histogram:直方圖注重量的分析。使用方式與Dominator Tree相似。

三、對比hprof文件,檢測出複雜狀況下的內存泄露:

通用對比方式:在Navigation History下面選擇想要對比的dominator_tree/histogram,右擊選擇Add to Compare Basket,而後在Compare Basket一欄中點擊紅色感嘆號(Compare the results)生成對比表格(Compared Tables),在頂部Regex輸入要檢測的類,查看引用關係或對象數量去進行分析便可。

針對於Historam的快速對比方式:直接選擇Histogram上方的Compare to another Heap Dump選擇要比較的hprof文件的Historam便可。

30、類的初始化順序依次是?

(靜態變量、靜態代碼塊)>(變量、代碼塊)>構造方法

3一、JSON的結構?

json是一種輕量級的數據交換格式, json簡單說就是對象和數組,因此這兩種結構就是對象和數組兩種結構,經過這兩種結構能夠表示各類複雜的結構

一、對象:對象表示爲「{}」擴起來的內容,數據結構爲 {key:value,key:value,...}的鍵值對的結構,在面向對象的語言中,key爲對象的屬性,value爲對應的屬性值,因此很容易理解,取值方法爲 對象.key 獲取屬性值,這個屬性值的類型能夠是 數字、字符串、數組、對象幾種。

二、數組:數組在json中是中括號「[]」擴起來的內容,數據結構爲 ["java","javascript","vb",...],取值方式和全部語言中同樣,使用索引獲取,字段值的類型能夠是 數字、字符串、數組、對象幾種。 通過對象、數組2種結構就能夠組合成複雜的數據結構了。

3二、ViewPager使用細節,如何設置成每次只初始化當前的Fragment,其餘的不初始化(提示:Fragment懶加載)?

自定義一個 LazyLoadFragment 基類,利用 setUserVisibleHint 和 生命週期方法,經過對 Fragment 狀態判斷,進行數據加載,並將數據加載的接口提供開放出去,供子類使用。而後在子類 Fragment 中實現 requestData 方法便可。這裏添加了一個 isDataLoaded 變量,目的是避免重複加載數據。考慮到有時候須要刷新數據的問題,便提供了一個用於強制刷新的參數判斷。

public abstract class LazyLoadFragment extends BaseFragment {
    protected boolean isViewInitiated;
    protected boolean isDataLoaded;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        isViewInitiated = true;
        prepareRequestData();
    }
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        prepareRequestData();
    }
    public abstract void requestData();
    public boolean prepareRequestData() {
        return prepareRequestData(false);
    }
    public boolean prepareRequestData(boolean forceUpdate) {
        if (getUserVisibleHint() && isViewInitiated && (!isDataLoaded || forceUpdate)) {
            requestData();
            isDataLoaded = true;
            return true;
        }
        return false;
    }
}
複製代碼

3五、Android爲何引入Parcelable?

能夠確定的是,二者都是支持序列化和反序列化的操做。

二者最大的區別在於 存儲媒介的不一樣,Serializable 使用 I/O 讀寫存儲在硬盤上,而 Parcelable 是直接 在內存中讀寫。很明顯,內存的讀寫速度一般大於 IO 讀寫,因此在 Android 中傳遞數據優先選擇 Parcelable。

Serializable 會使用反射,序列化和反序列化過程須要大量 I/O 操做, Parcelable 自已實現封送和解封(marshalled &unmarshalled)操做不須要用反射,數據也存放在 Native 內存中,效率要快不少。

3六、有沒有嘗試簡化Parcelable的使用?

使用Parcelable插件(Android Parcelable code generator)進行實體類的序列化的實現。

3七、Bitmap 使用時候注意什麼?

一、要選擇合適的圖片規格(bitmap類型):

ALPHA_8   每一個像素佔用1byte內存        
ARGB_4444 每一個像素佔用2byte內存       
ARGB_8888 每一個像素佔用4byte內存(默認)      
RGB_565 每一個像素佔用2byte內存
複製代碼

二、下降採樣率。BitmapFactory.Options 參數inSampleSize的使用,先把options.inJustDecodeBounds設爲true,只是去讀取圖片的大小,在拿到圖片的大小以後和要顯示的大小作比較經過calculateInSampleSize()函數計算inSampleSize的具體值,獲得值以後。options.inJustDecodeBounds設爲false讀圖片資源。

三、複用內存。即,經過軟引用(內存不夠的時候纔會回收掉),複用內存塊,不須要再從新給這個bitmap申請一塊新的內存,避免了一次內存的分配和回收,從而改善了運行效率。

四、使用recycle()方法及時回收內存。

五、壓縮圖片。

3八、Oom 是否能夠try catch ?

只有在一種狀況下,這樣作是可行的:

在try語句中聲明瞭很大的對象,致使OOM,而且能夠確認OOM是由try語句中的對象聲明致使的,那麼在catch語句中,能夠釋放掉這些對象,解決OOM的問題,繼續執行剩餘語句。

可是這一般不是合適的作法。

Java中管理內存除了顯式地catch OOM以外還有更多有效的方法:好比SoftReference, WeakReference, 硬盤緩存等。 在JVM用光內存以前,會屢次觸發GC,這些GC會下降程序運行的效率。 若是OOM的緣由不是try語句中的對象(好比內存泄漏),那麼在catch語句中會繼續拋出OOM。

3九、多進程場景碰見過麼?

一、在新的進程中,啓動前臺Service,播放音樂。 二、一個成熟的應用必定是多模塊化的。首先多進程開發能爲應用解決了OOM問題,由於Android對內存的限制是針對於進程的,因此,當咱們須要加載大圖之類的操做,能夠在新的進程中去執行,避免主進程OOM。並且假如圖片瀏覽進程打開了一個過大的圖片,java heap 申請內存失敗,該進程崩潰並不影響我主進程的使用。

40、Canvas.save()跟Canvas.restore()的調用時機

save:用來保存Canvas的狀態。save以後,能夠調用Canvas的平移、放縮、旋轉、錯切、裁剪等操做。

restore:用來恢復Canvas以前保存的狀態。防止save後對Canvas執行的操做對後續的繪製有影響。

save和restore要配對使用(restore能夠比save少,但不能多),若是restore調用次數比save多,會引起Error。save和restore操做執行的時機不一樣,就能形成繪製的圖形不一樣。

4一、數據庫升級增長表和刪除表都不涉及數據遷移,可是修改表涉及到對原有數據進行遷移。升級的方法以下所示:

將現有表命名爲臨時表。 建立新表。 將臨時表的數據導入新表。 刪除臨時表。

若是是跨版本數據庫升級,能夠有兩種方式,以下所示:

逐級升級,肯定相鄰版本與如今版本的差異,V1升級到V2,V2升級到V3,依次類推。 跨級升級,肯定每一個版本與如今數據庫的差異,爲每一個case編寫專門升級大代碼。

public class DBservice extends SQLiteOpenHelper{
    private String CREATE_BOOK = "create table book(bookId integer primarykey,bookName text);";
    private String CREATE_TEMP_BOOK = "alter table book rename to _temp_book";
    private String INSERT_DATA = "insert into book select *,'' from _temp_book";
    private String DROP_BOOK = "drop table _temp_book";
    public DBservice(Context context, String name, CursorFactory factory,int version) {
    super(context, name, factory, version);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    switch (newVersion) {
        case 2:
            db.beginTransaction();

            db.execSQL(CREATE_TEMP_BOOK);
            db.execSQL(CREATE_BOOK);
            db.execSQL(INSERT_DATA);
            db.execSQL(DROP_BOOK);

            db.setTransactionSuccessful();
            db.endTransaction();

            break;
    }
}
複製代碼

4二、編譯期註解跟運行時註解

運行期註解(RunTime)利用反射去獲取信息仍是比較損耗性能的,對應@Retention(RetentionPolicy.RUNTIME)。

編譯期(Compile time)註解,以及處理編譯期註解的手段APT和Javapoet,對應@Retention(RetentionPolicy.CLASS)。 其中apt+javaPoet目前也是應用比較普遍,在一些大的開源庫,如EventBus3.0+,頁面路由 ARout、Dagger、Retrofit等均有使用的身影,註解不只僅是經過反射一種方式來使用,也能夠使用APT在編譯期處理

4三、bitmap recycler 相關

在Android中,Bitmap的存儲分爲兩部分,一部分是Bitmap的數據,一部分是Bitmap的引用。 在Android2.3時代,Bitmap的引用是放在堆中的,而Bitmap的數據部分是放在棧中的,須要用戶調用recycle方法手動進行內存回收,而在Android2.3以後,整個Bitmap,包括數據和引用,都放在了堆中,這樣,整個Bitmap的回收就所有交給GC了,這個recycle方法就不再須要使用了。

bitmap recycler引起的問題:當圖像的旋轉角度小余兩個像素點之間的夾角時,圖像即便旋轉也沒法顯示,所以,系統徹底能夠認爲圖像沒有發生變化。這時系統就直接引用同一個對象來進行操做,避免內存浪費。

4四、強引用置爲null,會不會被回收?

不會當即釋放對象佔用的內存。 若是對象的引用被置爲null,只是斷開了當前線程棧幀中對該對象的引用關係,而 垃圾收集器是運行在後臺的線程,只有當用戶線程運行到安全點(safe point)或者安全區域纔會掃描對象引用關係,掃描到對象沒有被引用則會標記對象,這時候仍然不會當即釋放該對象內存,由於有些對象是可恢復的(在 finalize方法中恢復引用 )。只有肯定了對象沒法恢復引用的時候纔會清除對象內存。

4五、Bundle傳遞數據爲何須要序列化?

序列化,表示將一個對象轉換成可存儲或可傳輸的狀態。序列化的緣由基本三種狀況:

1.永久性保存對象,保存對象的字節序列到本地文件中;

2.對象在網絡中傳遞;

3.對象在IPC間傳遞。

4六、廣播傳輸的數據是否有限制,是多少,爲何要限制?

Intent在傳遞數據時是有大小限制的,大約限制在1MB以內,你用Intent傳遞數據,實際上走的是跨進程通訊(IPC),跨進程通訊須要把數據從內核copy到進程中,每個進程有一個接收內核數據的緩衝區,默認是1M;若是一次傳遞的數據超過限制,就會出現異常。

不一樣廠商表現不同有多是廠商修改了此限制的大小,也可能一樣的對象在不一樣的機器上大小不同。

傳遞大數據,不該該用Intent;考慮使用ContentProvider或者直接匿名共享內存。簡單狀況下能夠考慮分段傳輸。

4七、是否瞭解硬件加速?

硬件加速就是運用GPU優秀的運算能力來加快渲染的速度,而一般的基於軟件的繪製渲染模式是徹底利用CPU來完成渲染。

1.硬件加速是從API 11引入,API 14以後才默認開啓。對於標準的繪製操做和控件都是支持的,可是對於自定義View的時候或者一些特殊的繪製函數就須要考慮是否須要關閉硬件加速。

2.咱們面對不支持硬件加速的狀況,就須要限制硬件加速,這個兼容性的問題是由於硬件加速是把View的繪製函數轉化爲使用OpenGL的函數來進完成實際的繪製的,那麼必然會存在OpenGL中不支持原始回執函數的狀況,對於這些繪製函數,就會失效。

3.硬件加速的消耗問題,由於是使用OpenGL,須要把系統中OpenGL加載到內存中,OpenGL API調用就會佔用8MB,而實際上會佔用更多內存,而且使用了硬件必然增長耗電量了。

4.硬件加速的優點還有display list的設計,使用這個咱們不須要每次重繪都執行大量的代碼,基於軟件的繪製模式會重繪髒區域內的全部控件,而display只會更新列表,而後繪製列表內的控件。

  1. CPU更擅長複雜邏輯控制,而GPU得益於大量ALU和並行結構設計,更擅長數學運算。

4八、ContentProvider的權限管理(讀寫分離,權限控制-精確到表級,URL控制)。

 對於ContentProvider暴露出來的數據,應該是存儲在本身應用內存中的數據,對於一些存儲在外部存儲器上的數據,並不能限制訪問權限,使用ContentProvider就沒有意義了。對於ContentProvider而言,有不少權限控制,能夠在AndroidManifest.xml文件中對節點的屬性進行配置,通常使用以下一些屬性設置:

  • android:grantUriPermssions:臨時許可標誌。
  • android:permission:Provider讀寫權限。
  • android:readPermission:Provider的讀權限。
  • android:writePermission:Provider的寫權限。
  • android:enabled:標記容許系統啓動Provider。
  • android:exported:標記容許其餘應用程序使用這個Provider。
  • android:multiProcess:標記容許系統啓動Provider相同的進程中調用客戶端。

4九、Fragment狀態保存

Fragment狀態保存入口:

一、Activity的狀態保存, 在Activity的onSaveInstanceState()裏, 調用了FragmentManger的saveAllState()方法, 其中會對mActive中各個Fragment的實例狀態和View狀態分別進行保存.

二、FragmentManager還提供了public方法: saveFragmentInstanceState(), 能夠對單個Fragment進行狀態保存, 這是提供給咱們用的。

三、FragmentManager的moveToState()方法中, 當狀態回退到ACTIVITY_CREATED, 會調用saveFragmentViewState()方法, 保存View的狀態.

50、直接在Activity中建立一個thread跟在service中建立一個thread之間的區別?

在Activity中被建立:該Thread的就是爲這個Activity服務的,完成這個特定的Activity交代的任務,主動通知該Activity一些消息和事件,Activity銷燬後,該Thread也沒有存活的意義了。

在Service中被建立:這是保證最長生命週期的Thread的惟一方式,只要整個Service不退出,Thread就能夠一直在後臺執行,通常在Service的onCreate()中建立,在onDestroy()中銷燬。因此,在Service中建立的Thread,適合長期執行一些獨立於APP的後臺任務,比較常見的就是:在Service中保持與服務器端的長鏈接。

5一、如何計算一個Bitmap佔用內存的大小,怎麼保證加載Bitmap不產生內存溢出?

Bitamp 佔用內存大小 = 寬度像素 x (inTargetDensity / inDensity) x 高度像素 x (inTargetDensity / inDensity)x 一個像素所佔的內存
複製代碼

注:這裏inDensity表示目標圖片的dpi(放在哪一個資源文件夾下),inTargetDensity表示目標屏幕的dpi,因此你能夠發現inDensity和inTargetDensity會對Bitmap的寬高進行拉伸,進而改變Bitmap佔用內存的大小。

在Bitmap裏有兩個獲取內存佔用大小的方法。

getByteCount():API12 加入,表明存儲 Bitmap 的像素須要的最少內存。 getAllocationByteCount():API19 加入,表明在內存中爲 Bitmap 分配的內存大小,代替了 getByteCount() 方法。 在不復用 Bitmap 時,getByteCount() 和 getAllocationByteCount 返回的結果是同樣的。在經過複用 Bitmap 來解碼圖片時,那麼 getByteCount() 表示新解碼圖片佔用內存的大 小,getAllocationByteCount() 表示被複用 Bitmap 真實佔用的內存大小(即 mBuffer 的長度)。

爲了保證在加載Bitmap的時候不產生內存溢出,能夠使用BitmapFactory進行圖片壓縮,主要有如下幾個參數:

BitmapFactory.Options.inPreferredConfig:將ARGB_8888改成RGB_565,改變編碼方式,節約內存。 BitmapFactory.Options.inSampleSize:縮放比例,能夠參考Luban那個庫,根據圖片寬高計算出合適的縮放比例。 BitmapFactory.Options.inPurgeable:讓系統能夠內存不足時回收內存。

5二、對於應用更新這塊是如何作的?(灰度,強制更新,分區域更新)

一、經過接口獲取線上版本號,versionCode 二、比較線上的versionCode 和本地的versionCode,彈出更新窗口 三、下載APK文件(文件下載) 四、安裝APK

灰度: (1)找單一渠道投放特別版本。 (2)作升級平臺的改造,容許針對部分用戶推送升級通知甚至版本強制升級。 (3)開放單獨的下載入口。 (4)是兩個版本的代碼都打到app包裏,而後在app端植入測試框架,用來控制顯示哪一個版本。測試框架負責與服務器端api通訊,由服務器端控制app上A/B版本的分佈,能夠實現指定的一組用戶看到A版本,其它用戶看到B版本。服務端會有相應的報表來顯示A/B版本的數量和效果對比。最後能夠由服務端的後臺來控制,所有用戶在線切換到A或者B版本~

不管哪一種方法都須要作好版本管理工做,分配特別的版本號以示區別。 固然,既然是作灰度,數據監控(常規數據、新特性數據、主要業務數據)仍是要作到位,該打的數據樁要打。 還有,灰度版最好有收回的能力,通常就是強制升級下一個正式版。

強制更新:通常的處理就是進入應用就彈窗通知用戶有版本更新,彈窗能夠沒有取消按鈕並不能取消。這樣用戶就只能選擇更新或者關閉應用了,固然也能夠添加取消按鈕,可是若是用戶選擇取消則直接退出應用。

增量更新:bsdiff:二進制差分工具bsdiff是相應的補丁合成工具,根據兩個不一樣版本的二進制文件,生成補丁文件.patch文件。經過bspatch使舊的apk文件與不定文件合成新的apk。 注意經過apk文件的md5值進行區分版本。

5三、請解釋安卓爲啥要加簽名機制。

一、發送者的身份認證 因爲開發商可能經過使用相同的 Package Name 來混淆替換已經安裝的程序,以此保證簽名不一樣的包不被替換。

二、保證信息傳輸的完整性 簽名對於包中的每一個文件進行處理,以此確保包中內容不被替換。

三、防止交易中的抵賴發生, Market 對軟件的要求。

5四、爲何bindService能夠跟Activity生命週期聯動?

一、bindService 方法執行時,LoadedApk 會記錄 ServiceConnection 信息。

二、Activity 執行 finish 方法時,會經過 LoadedApk 檢查 Activity 是否存在未註銷/解綁的 BroadcastReceiver 和 ServiceConnection,若是有,那麼會通知 AMS 註銷/解綁對應的 BroadcastReceiver 和 Service,並打印異常信息,告訴用戶應該主動執行註銷/解綁的操做。

5五、如何經過Gradle配置多渠道包?

用於生成不一樣渠道的包

android {  
    productFlavors {
        xiaomi {}
        baidu {}
        wandoujia {}
        _360 {}        // 或「"360"{}」,數字需下劃線開頭或加上雙引號
    }
}
複製代碼

執行./gradlew assembleRelease ,將會打出全部渠道的release包;

執行./gradlew assembleWandoujia,將會打出豌豆莢渠道的release和debug版的包;

執行./gradlew assembleWandoujiaRelease將生成豌豆莢的release包。

所以,能夠結合buildType和productFlavor生成不一樣的Build Variants,即類型與渠道不一樣的組合。

5六、activty和Fragmengt之間怎麼通訊,Fragmengt和Fragmengt怎麼通訊?

(一)Handler

(二)廣播

(三)事件總線:EventBus、RxBus、Otto

(四)接口回調

(五)Bundle和setArguments(bundle)

5七、自定義view效率高於xml定義嗎?說明理由。

自定義view效率高於xml定義:

一、少了解析xml。

2.、自定義View 減小了ViewGroup與View之間的測量,包括父量子,子量自身,子在父中位置擺放,當子view變化時,父的某些屬性都會跟着變化。

5八、廣播註冊通常有幾種,各有什麼優缺點?

第一種是常駐型(靜態註冊):當應用程序關閉後若是有信息廣播來,程序也會被系統調用,本身運行。

第二種不常駐(動態註冊):廣播會跟隨程序的生命週期。

動態註冊

優勢: 在android的廣播機制中,動態註冊優先級高於靜態註冊優先級,所以在必要狀況下,是須要動態註冊廣播接收者的。

缺點: 當用來註冊的 Activity 關掉後,廣播也就失效了。

靜態註冊

優勢: 無需擔心廣播接收器是否被關閉,只要設備是開啓狀態,廣播接收器就是打開着的。

5九、服務啓動通常有幾種,服務和activty之間怎麼通訊,服務和服務之間怎麼通訊

方式:

一、startService:

onCreate()--->onStartCommand() ---> onDestory()

若是服務已經開啓,不會重複的執行onCreate(), 而是會調用onStartCommand()。一旦服務開啓跟調用者(開啓者)就沒有任何關係了。 開啓者退出了,開啓者掛了,服務還在後臺長期的運行。 開啓者不能調用服務裏面的方法。

二、bindService:

onCreate() --->onBind()--->onunbind()--->onDestory()

bind的方式開啓服務,綁定服務,調用者掛了,服務也會跟着掛掉。 綁定者能夠調用服務裏面的方法。

通訊:

一、經過Binder對象。

二、經過broadcast(廣播)。

60、ddms 和 traceView 的區別?

ddms 原意是:davik debug monitor service。簡單的說 ddms 是一個程序執行查看器,在裏面能夠看見線程和堆棧等信息,traceView 是程序性能分析器。traceview 是 ddms 中的一部份內容。

Traceview 是 Android 平臺特有的數據採集和分析工具,它主要用於分析 Android 中應用程序的 hotspot(瓶頸)。Traceview 自己只是一個數據分析工具,而數據的採集則須要使用 Android SDK 中的 Debug 類或者利用DDMS 工具。兩者的用法以下:開發者在一些關鍵代碼段開始前調用 Android SDK 中 Debug 類的 startMethodTracing 函數,並在關鍵代碼段結束前調用 stopMethodTracing 函數。這兩個函數運行過程當中將採集運行時間內該應用全部線程(注意,只能是 Java線程) 的函數執行狀況, 並將採集數據保存到/mnt/sdcard/下的一個文件中。 開發者而後須要利用 SDK 中的 Traceview工具來分析這些數據。

6一、ListView卡頓緣由

Adapter的getView方法裏面convertView沒有使用setTag和getTag方式;

在getView方法裏面ViewHolder初始化後的賦值或者是多個控件的顯示狀態和背景的顯示沒有優化好,抑或是裏面含有複雜的計算和耗時操做;

在getView方法裏面 inflate的row 嵌套太深(佈局過於複雜)或者是佈局裏面有大圖片或者背景所致;

Adapter多餘或者不合理的notifySetDataChanged;

listview 被多層嵌套,屢次的onMessure致使卡頓,若是多層嵌套沒法避免,建議把listview的高和寬設置爲match_parent. 若是是代碼繼承的listview,那麼也請你別忘記爲你的繼承類添加上LayoutPrams,注意高和寬都mactch_parent的;

6二、AndroidManifest的做用與理解

AndroidManifest.xml文件,也叫清單文件,來獲知應用中是否包含該組件,若是有會直接啓動該組件。能夠理解是一個應用的配置文件。

做用:

  • 爲應用的 Java 軟件包命名。軟件包名稱充當應用的惟一標識符。
  • 描述應用的各個組件,包括構成應用的 Activity、服務、廣播接收器和內容提供程序。它還爲實現每一個組件的類命名併發布其功能,例如它們能夠處理的 Intent - 消息。這些聲明向 Android 系統告知有關組件以及能夠啓動這些組件的條件的信息。
  • 肯定託管應用組件的進程。
  • 聲明應用必須具有哪些權限才能訪問 API 中受保護的部分並與其餘應用交互。還聲明其餘應用與該應用組件交互所需具有的權限
  • 列出 Instrumentation類,這些類可在應用運行時提供分析和其餘信息。這些聲明只會在應用處於開發階段時出如今清單中,在應用發佈以前將移除。
  • 聲明應用所需的最低 Android API 級別
  • 列出應用必須連接到的庫

6三、LaunchMode應用場景

standard,建立一個新的Activity。

singleTop,棧頂不是該類型的Activity,建立一個新的Activity。不然,onNewIntent。

singleTask,回退棧中沒有該類型的Activity,建立Activity,不然,onNewIntent+ClearTop。

注意:

設置了"singleTask"啓動模式的Activity,它在啓動的時候,會先在系統中查找屬性值affinity等於它的屬性值taskAffinity的Task存在;若是存在這樣的Task,它就會在這個Task中啓動,不然就會在新的任務棧中啓動。所以, 若是咱們想要設置了"singleTask"啓動模式的Activity在新的任務中啓動,就要爲它設置一個獨立的taskAffinity屬性值。

若是設置了"singleTask"啓動模式的Activity不是在新的任務中啓動時,它會在已有的任務中查看是否已經存在相應的Activity實例, 若是存在,就會把位於這個Activity實例上面的Activity所有結束掉,即最終這個Activity 實例會位於任務的Stack頂端中。

在一個任務棧中只有一個」singleTask」啓動模式的Activity存在。他的上面能夠有其餘的Activity。這點與singleInstance是有區別的。

singleInstance,回退棧中,只有這一個Activity,沒有其餘Activity。

singleTop適合接收通知啓動的內容顯示頁面。

例如,某個新聞客戶端的新聞內容頁面,若是收到10個新聞推送,每次都打開一個新聞內容頁面是很煩人的。

singleTask適合做爲程序入口點。

例如瀏覽器的主界面。無論從多少個應用啓動瀏覽器,只會啓動主界面一次,其他狀況都會走onNewIntent,而且會清空主界面上面的其餘頁面。

singleInstance應用場景:

鬧鈴的響鈴界面。 你之前設置了一個鬧鈴:上午6點。在上午5點58分,你啓動了鬧鈴設置界面,並按 Home 鍵回桌面;在上午5點59分時,你在微信和朋友聊天;在6點時,鬧鈴響了,而且彈出了一個對話框形式的 Activity(名爲 AlarmAlertActivity) 提示你到6點了(這個 Activity 就是以 SingleInstance 加載模式打開的),你按返回鍵,回到的是微信的聊天界面,這是由於 AlarmAlertActivity 所在的 Task 的棧只有他一個元素, 所以退出以後這個 Task 的棧空了。若是是以 SingleTask 打開 AlarmAlertActivity,那麼當鬧鈴響了的時候,按返回鍵應該進入鬧鈴設置界面。

6四、說說Activity、Intent、Service 是什麼關係

他們都是 Android 開發中使用頻率最高的類。其中 Activity 和 Service 都是 Android 四大組件之一。他倆都是 Context 類的子類 ContextWrapper 的子類,所以他倆能夠算是兄弟關係吧。不過兄弟倆各有各自的本領,Activity 負責用戶界面的顯示和交互,Service 負責後臺任務的處理。Activity 和 Service 之間能夠經過 Intent 傳遞數據,所以 能夠把 Intent 看做是通訊使者。

6五、ApplicationContext和ActivityContext的區別

這是兩種不一樣的context,也是最多見的兩種.第一種中context的生命週期與Application的生命週期相關的,context隨着Application的銷燬而銷燬,伴隨application的一輩子,與activity的生命週期無關.第二種中的context跟Activity的生命週期是相關的,可是對一個Application來講,Activity能夠銷燬幾回,那麼屬於Activity的context就會銷燬屢次.至於用哪一種context,得看應用場景。還有就是,在使用context的時候,當心內存泄露,防止內存泄露,注意一下幾個方面:

  • 不要讓生命週期長的對象引用activity context,即保證引用activity的對象要與activity自己生命週期是同樣的。
  • 對於生命週期長的對象,能夠使用application context。
  • 避免非靜態的內部類,儘可能使用靜態類,避免生命週期問題,注意內部類對外部對象引用致使的生命週期變化。

6六、Handler、Thread和HandlerThread的差異

一、Handler:在android中負責發送和處理消息,經過它能夠實現其餘支線線程與主線程之間的消息通信。

二、Thread:Java進程中執行運算的最小單位,亦即執行處理機調度的基本單位。某一進程中一路單獨運行的程序。

三、HandlerThread:一個繼承自Thread的類HandlerThread,Android中沒有對Java中的Thread進行任何封裝,而是提供了一個繼承自Thread的類HandlerThread類,這個類對Java的Thread作了不少便利的封裝。HandlerThread繼承於Thread,因此它本質就是個Thread。與普通Thread的差異就在於,它在內部直接實現了Looper的實現,這是Handler消息機制必不可少的。有了本身的looper,可讓咱們在本身的線程中分發和處理消息。若是不用HandlerThread的話,須要手動去調用Looper.prepare()和Looper.loop()這些方法。

6七、ThreadLocal的原理

ThreadLocal是一個關於建立線程局部變量的類。使用場景以下所示:

  • 實現單個線程單例以及單個線程上下文信息存儲,好比交易id等。

  • 實現線程安全,非線程安全的對象使用ThreadLocal以後就會變得線程安全,由於每一個線程都會有一個對應的實例。 承載一些線程相關的數據,避免在方法中來回傳遞參數。

當須要使用多線程時,有個變量恰巧不須要共享,此時就沒必要使用synchronized這麼麻煩的關鍵字來鎖住,每一個線程都至關於在堆內存中開闢一個空間,線程中帶有對共享變量的緩衝區,經過緩衝區將堆內存中的共享變量進行讀取和操做,ThreadLocal至關於線程內的內存,一個局部變量。每次能夠對線程自身的數據讀取和操做,並不須要經過緩衝區與 主內存中的變量進行交互。並不會像synchronized那樣修改主內存的數據,再將主內存的數據複製到線程內的工做內存。ThreadLocal可讓線程獨佔資源,存儲於線程內部,避免線程堵塞形成CPU吞吐降低。

在每一個Thread中包含一個ThreadLocalMap,ThreadLocalMap的key是ThreadLocal的對象,value是獨享數據。

6八、計算一個view的嵌套層級

private int getParents(ViewParents view){
    if(view.getParents() == null) 
        return 0;
    } else {
    return (1 + getParents(view.getParents));
   }
}
複製代碼

6九、MVP,MVVM,MVC解釋和實踐

MVC:
  • 視圖層(View) 對應於xml佈局文件和java代碼動態view部分
  • 控制層(Controller) MVC中Android的控制層是由Activity來承擔的,Activity原本主要是做爲初始化頁面,展現數據的操做,可是由於XML視圖功能太弱,因此Activity既要負責視圖的顯示又要加入控制邏輯,承擔的功能過多。
  • 模型層(Model) 針對業務模型,創建數據結構和相關的類,它主要負責網絡請求,數據庫處理,I/O的操做。
總結

具備必定的分層,model完全解耦,controller和view並無解耦 層與層之間的交互儘可能使用回調或者去使用消息機制去完成,儘可能避免直接持有 controller和view在android中沒法作到完全分離,但在代碼邏輯層面必定要分清 業務邏輯被放置在model層,可以更好的複用和修改增長業務。

MVP

經過引入接口BaseView,讓相應的視圖組件如Activity,Fragment去實現BaseView,實現了視圖層的獨立,經過中間層Preseter實現了Model和View的徹底解耦。MVP完全解決了MVC中View和Controller傻傻分不清楚的問題,可是隨着業務邏輯的增長,一個頁面可能會很是複雜,UI的改變是很是多,會有很是多的case,這樣就會形成View的接口會很龐大。

MVVM

MVP中咱們說過隨着業務邏輯的增長,UI的改變多的狀況下,會有很是多的跟UI相關的case,這樣就會形成View的接口會很龐大。而MVVM就解決了這個問題,經過雙向綁定的機制,實現數據和UI內容,只要想改其中一方,另外一方都可以及時更新的一種設計理念,這樣就省去了不少在View層中寫不少case的狀況,只須要改變數據就行。

MVVM與DataBinding的關係?

MVVM是一種思想,DataBinding是谷歌推出的方便實現MVVM的工具。

看起來MVVM很好的解決了MVC和MVP的不足,可是因爲數據和視圖的雙向綁定,致使出現問題時不太好定位來源,有可能數據問題致使,也有可能業務邏輯中對視圖屬性的修改致使。若是項目中打算用MVVM的話能夠考慮使用官方的架構組件ViewModel、LiveData、DataBinding去實現MVVM。

三者如何選擇?
  • 若是項目簡單,沒什麼複雜性,將來改動也不大的話,那就不要用設計模式或者架構方法,只須要將每一個模塊封裝好,方便調用便可,不要爲了使用設計模式或架構方法而使用。
  • 對於偏向展現型的app,絕大多數業務邏輯都在後端,app主要功能就是展現數據,交互等,建議使用mvvm。
  • 對於工具類或者須要寫不少業務邏輯app,使用mvp或者mvvm均可。

70、SharedPrefrences的apply和commit有什麼區別?

這兩個方法的區別在於:

  1. apply沒有返回值而commit返回boolean代表修改是否提交成功。

  2. apply是將修改數據原子提交到內存, 然後異步真正提交到硬件磁盤, 而commit是同步的提交到硬件磁盤,所以,在多個併發的提交commit的時候,他們會等待正在處理的commit保存到磁盤後在操做,從而下降了效率。而apply只是原子的提交到內容,後面有調用apply的函數的將會直接覆蓋前面的內存數據,這樣從必定程度上提升了不少效率。

  3. apply方法不會提示任何失敗的提示。 因爲在一個進程中,sharedPreference是單實例,通常不會出現併發衝突,若是對提交的結果不關心的話,建議使用apply,固然須要確保提交成功且有後續操做的話,仍是須要用commit的。

7一、Base6四、MD5是加密方法麼?

Base64是什麼?

Base64是用文本表示二進制的編碼方式,它使用4個字節的文原本表示3個字節的原始二進制數據。 它將二進制數據轉換成一個由64個可打印的字符組成的序列:A-Za-z0-9+/

MD5是什麼?

MD5是哈希算法的一種,能夠將任意數據產生出一個128位(16字節)的散列值,用於確保信息傳輸完整一致。咱們常在註冊登陸模塊使用MD5,用戶密碼能夠使用MD5加密的方式進行存儲。如:md5(hello world,32) = 5eb63bbbe01eeed093cb22bb8f5acdc3

加密,指的是對數據進行轉換之後,數據變成了另外一種格式,而且除了拿到解密方法的人,沒人能把數據轉換回來。 MD5是一種信息摘要算法,它是不可逆的,不能夠解密。因此它只能算的上是一種單向加密算法。 Base64也不是加密算法,它是一種數據編碼方式,雖然是可逆的,可是它的編碼方式是公開的,無所謂加密。

7二、HttpClient和HttpConnection的區別?

Http Client適用於web瀏覽器,擁有大量靈活的API,實現起來比較穩定,且其功能比較豐富,提供了不少工具,封裝了http的請求頭,參數,內容體,響應,還有一些高級功能,代理、COOKIE、鑑權、壓縮、鏈接池的處理。   可是,正所以,在不破壞兼容性的前提下,其龐大的API也令人難以改進,所以Android團隊對於修改優化Apache Http Client並不積極。(並在Android 6.0中拋棄了Http Client,替換成OkHttp)

HttpURLConnection對於大部分功能都進行了包裝,Http Client的高級功能代碼會較複雜,另外,HttpURLConnection在Android 2.3中增長了一些Https方面的改進(包括Http Client,二者都支持https)。且在Android 4.0中增長了response cache。當緩存被安裝後(調用HttpResponseCache的install()方法),全部的HTTP請求都會知足如下三種狀況:

  • 全部的緩存響應都由本地存儲來提供。由於沒有必要去發起任務的網絡鏈接請求,全部的響應均可以馬上獲取到。
  • 視狀況而定的緩存響應必需要有服務器來進行更新檢查。好比說客戶端發起了一條相似於 「若是/foo.png這張圖片發生了改變,就將它發送給我」 這樣的請求,服務器須要將更新後的數據進行返回,或者返回一個304 Not Modified狀態。若是請求的內容沒有發生,客戶端就不會下載任何數據。
  • 沒有緩存的響應都是由服務器直接提供的。這部分響應會在稍後存儲到響應緩存中。

在Android 2.2版本以前,HttpClient擁有較少的bug,所以使用它是最好的選擇。 而在Android 2.3版本及之後,HttpURLConnection則是最佳的選擇。它的API簡單,體積較小,於是很是適用於Android項目。壓縮和緩存機制能夠有效地減小網絡訪問的流量,在提高速度和省電方面也起到了較大的做用。對於新的應用程序應該更加偏向於使用HttpURLConnection,由於在之後的工做當中Android官方也會將更多的時間放在優化HttpURLConnection上面。

7三、ActivityA跳轉ActivityB而後B按back返回A,各自的生命週期順序,A與B均不透明。

ActivityA跳轉到ActivityB:
Activity A:onPause
Activity B:onCreate
Activity B:onStart
Activity B:onResume
Activity A:onStop
複製代碼
ActivityB返回ActivityA:
Activity B:onPause
Activity A:onRestart
Activity A:onStart
Activity A:onResume
Activity B:onStop
Activity B:onDestroy
複製代碼

7四、如何經過廣播攔截和abort一條短信?

能夠監聽這條信號,在傳遞給真正的接收程序時,咱們將自定義的廣播接收程序的優先級大於它,而且取消廣播的傳播,這樣就能夠實現攔截短信的功能了。

7五、BroadcastReceiver,LocalBroadcastReceiver 區別?

一、應用場景

一、BroadcastReceiver用於應用之間的傳遞消息;

二、而LocalBroadcastManager用於應用內部傳遞消息,比broadcastReceiver更加高效。

二、安全

一、BroadcastReceiver使用的Content API,因此本質上它是跨應用的,因此在使用它時必需要考慮到不要被別的應用濫用;

二、LocalBroadcastManager不須要考慮安全問題,由於它只在應用內部有效。

三、原理方面

(1) 與BroadcastReceiver是以 Binder 通信方式爲底層實現的機制不一樣,LocalBroadcastManager 的核心實現實際仍是 Handler,只是利用到了 IntentFilter 的 match 功能,至於 BroadcastReceiver 換成其餘接口也無所謂,順便利用了現成的類和概念而已。

(2) LocalBroadcastManager由於是 Handler 實現的應用內的通訊,天然安全性更好,效率更高。

7六、如何選擇第三方,從那些方面考慮?

大方向:從軟件環境作判斷

性能是開源軟件第一解決的問題。

一個好的生態,是一個優秀的開源庫必備的,取決標準就是觀察它是否一直在持續更新迭代,是否能及時處理github上用戶提出來的問題。你們在社區針對這個開源庫是否有比較活躍的探討。

背景,該開源庫由誰推出,由哪一個公司推出來的。

用戶數和有哪些知名的企業落地使用

小方向:從軟件開發者的角度作判斷

是否解決了咱們現有問題或長期來看帶來的維護成本。

公司有多少人會。

學習成本。

7七、簡單說下接入支付的流程,是否本身接入過支付功能?

Alipay支付功能:

1.首先登陸支付寶開放平臺建立應用,並給應用添加App支付功能, 因爲App支付功能須要簽約,所以須要上傳公司信息和證件等資料進行簽約。

2.簽約成功後,須要配置祕鑰。使用支付寶提供的工具生成RSA公鑰和私鑰,公鑰須要設置到管理後臺。

3.android studio集成

(1)copy jar包;
(2)發起支付請求,處理支付請求。
複製代碼

7八、單例實現線程的同步的要求:

1.單例類確保本身只有一個實例(構造函數私有:不被外部實例化,也不被繼承)。

2.單例類必須本身建立本身的實例。

3.單例類必須爲其餘對象提供惟一的實例。

7九、如何保證Service不被殺死?

Android 進程不死從3個層面入手:

A.提供進程優先級,下降進程被殺死的機率

方法一:監控手機鎖屏解鎖事件,在屏幕鎖屏時啓動1個像素的 Activity,在用戶解鎖時將 Activity 銷燬掉。

方法二:啓動前臺service。

方法三:提高service優先級:

在AndroidManifest.xml文件中對於intent-filter能夠經過android:priority = "1000"這個屬性設置最高優先級,1000是最高值,若是數字越小則優先級越低,同時適用於廣播。

B. 在進程被殺死後,進行拉活

方法一:註冊高頻率廣播接收器,喚起進程。如網絡變化,解鎖屏幕,開機等

方法二:雙進程相互喚起。

方法三:依靠系統喚起。

方法四:onDestroy方法裏重啓service:service + broadcast 方式,就是當service走ondestory的時候,發送一個自定義的廣播,當收到廣播的時候,從新啓動service;

C. 依靠第三方

根據終端不一樣,在小米手機(包括 MIUI)接入小米推送、華爲手機接入華爲推送;其餘手機能夠考慮接入騰訊信鴿或極光推送與小米推送作 A/B Test。

80、說說ContentProvider、ContentResolver、ContentObserver 之間的關係?

ContentProvider:管理數據,提供數據的增刪改查操做,數據源能夠是數據庫、文件、XML、網絡等,ContentProvider爲這些數據的訪問提供了統一的接口,能夠用來作進程間數據共享。

ContentResolver:ContentResolver能夠爲不一樣URI操做不一樣的ContentProvider中的數據,外部進程能夠經過ContentResolver與ContentProvider進行交互。

ContentObserver:觀察ContentProvider中的數據變化,並將變化通知給外界。

8一、如何導入外部數據庫?

把原數據庫包括在項目源碼的 res/raw。

android系統下數據庫應該存放在 /data/data/com.(package name)/ 目錄下,因此咱們須要作的是把已有的數據庫傳入那個目錄下。操做方法是用FileInputStream讀取原數據庫,再用FileOutputStream把讀取到的東西寫入到那個目錄。

8二、LinearLayout、FrameLayout、RelativeLayout性能對比,爲何?

RelativeLayout會讓子View調用2次onMeasure,LinearLayout 在有weight時,也會調用子 View 2次onMeasure

RelativeLayout的子View若是高度和RelativeLayout不一樣,則會引起效率問題,當子View很複雜時,這個問題會更加嚴重。若是能夠,儘可能使用padding代替margin。

在不影響層級深度的狀況下,使用LinearLayout和FrameLayout而不是RelativeLayout。

爲何Google給開發者默認新建了個RelativeLayout,而本身卻在DecorView中用了個LinearLayout?

由於DecorView的層級深度是已知並且固定的,上面一個標題欄,下面一個內容欄。採用RelativeLayout並不會下降層級深度,因此此時在根節點上用LinearLayout是效率最高的。而之因此給開發者默認新建了個RelativeLayout是但願開發者能採用儘可能少的View層級來表達佈局以實現性能最優,由於複雜的View嵌套對性能的影響會更大一些。

8三、scheme跳轉協議

Android中的scheme是一種頁面內跳轉協議,經過定義本身的scheme協議,能夠跳轉到app中的各個頁面

服務器能夠定製化告訴app跳轉哪一個頁面

App能夠經過跳轉到另外一個App頁面

能夠經過H5頁面跳轉頁面

8四、HandlerThread

一、HandlerThread原理

當系統有多個耗時任務須要執行時,每一個任務都會開啓個新線程去執行耗時任務,這樣會致使系統屢次建立和銷燬線程,從而影響性能。爲了解決這一問題,Google提出了HandlerThread,HandlerThread本質上是一個線程類,它繼承了Thread。HandlerThread有本身的內部Looper對象,能夠進行loopr循環。經過獲取HandlerThread的looper對象傳遞給Handler對象,能夠在handleMessage()方法中執行異步任務。建立HandlerThread後必須先調用HandlerThread.start()方法,Thread會先調用run方法,建立Looper對象。當有耗時任務進入隊列時,則不須要開啓新線程,在原有的線程中執行耗時任務便可,不然線程阻塞。它在Android中的一個具體的使用場景是IntentService。因爲HanlderThread的run()方法是一個無限循環,所以當明確不須要再使用HandlerThread時,能夠經過它的quit或者quitSafely方法來終止線程的執行。

二、HanlderThread的優缺點

  • HandlerThread優勢是異步不會堵塞,減小對性能的消耗。

  • HandlerThread缺點是不能同時繼續進行多任務處理,要等待進行處理,處理效率較低。

  • HandlerThread與線程池不一樣,HandlerThread是一個串隊列,背後只有一個線程。

8五、IntentService

IntentService是一種特殊的Service,它繼承了Service而且它是一個抽象類,所以必須建立它的子類才能使用IntentService。

原理

在實現上,IntentService封裝了HandlerThread和Handler。當IntentService被第一次啓動時,它的onCreate()方法會被調用,onCreat()方法會建立一個HandlerThread,而後使用它的Looper來構造一個Handler對象mServiceHandler,這樣經過mServiceHandler發送的消息最終都會在HandlerThread中執行。

生成一個默認的且與主線程互相獨立的工做者線程來執行全部傳送至onStartCommand()方法的Intetnt。

生成一個工做隊列來傳送Intent對象給onHandleIntent()方法,同一時刻只傳送一個Intent對象,這樣一來,你就沒必要擔憂多線程的問題。在全部的請求(Intent)都被執行完之後會自動中止服務,因此,你不須要本身去調用stopSelf()方法來中止。

該服務提供了一個onBind()方法的默認實現,它返回null。

提供了一個onStartCommand()方法的默認實現,它將Intent先傳送至工做隊列,而後從工做隊列中每次取出一個傳送至onHandleIntent()方法,在該方法中對Intent作相應的處理。

爲何在mServiceHandler的handleMessage()回調方法中執行完onHandlerIntent()方法後要使用帶參數的stopSelf()方法?

由於stopSel()方法會當即中止服務,而stopSelf(int startId)會等待全部的消息都處理完畢後才終止服務,通常來講,stopSelf(int startId)在嘗試中止服務以前會判斷最近啓動服務的次數是否和startId相等,若是相等就馬上中止服務,不相等則不中止服務。

8六、如何將一個Activity設置成窗口的樣式。

中配置:

android:theme="@android:style/Theme.Dialog"
複製代碼

另外

android:theme="@android:style/Theme.Translucnt"
複製代碼

是設置透明。

8七、Android中跨進程通信的幾種方式

1:訪問其餘應用程序的Activity 如調用系統通話應用

Intent callIntent = new Intent(Intent.ACTION_CALL,Uri.parse("tel:12345678");
startActivity(callIntent);
複製代碼

2:Content Provider 如訪問系統相冊

3:廣播(Broadcast) 如顯示系統時間

4:AIDL服務

8八、顯示Intent與隱式Intent的區別

對明確指出了目標組件名稱的Intent,咱們稱之爲「顯式Intent」。

對於沒有明確指出目標組件名稱的Intent,則稱之爲「隱式 Intent」。

對於隱式意圖,在定義Activity時,指定一個intent-filter,當一個隱式意圖對象被一個意圖過濾器進行匹配時,將有三個方面會被參考到:

動做(Action)

類別(Category ['kætɪg(ə)rɪ] )

數據(Data )

<activity android:name=".MainActivity"  android:label="@string/app_name">
            <intent-filter>
                <action android:name="com.wpc.test" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="image/gif"/>
            </intent-filter>
</activity>
複製代碼

8九、Android Holo主題與MD主題的理念,以及你的見解

Holo Theme

Holo Theme 是 Android Design 的最基礎的呈現方式。由於是最爲基礎的 Android Design 呈現形式,每一臺 Android 4.X 的手機系統內部都有集成 Holo Theme 須要的控件,即開發者不須要本身設計控件,而是直接從系統裏調用相應的控件。在 UI 方面沒有任何的亮點,和 Android4.X 的設置/電話的視覺效果極度統一。由此帶來的好處顯而易見,這個應用做爲 Android 應用的辨識度極高,且徹底不可能與系統風格產生衝突。

Material Design

Material design實際上是單純的一種設計語言,它包含了系統界面風格、交互、UI,更加專一擬真,更加大膽豐富的用色,更加豐富的交互形式,更加靈活的佈局形式

1.鮮明、形象的界面風格,

2.色彩搭配使得應用看起來很是的大膽、充滿色彩感,凸顯內容

3.Material design對於界面的排版很是的重視

4.Material design的交互設計上採用的是響應式交互,這樣的交互設計能把一個應用從簡單展示用戶所請求的信息,提高至能與用戶產生更強烈、更具體化交互的工具。

90、如何讓程序自動啓動?

定義一個Braodcastreceiver,action爲BOOT——COMPLETE,接受到廣播後啓動程序。

9一、Fragment 在 ViewPager 裏面的生命週期,滑動 ViewPager 的頁面時 Fragment 的生命週期的變化。

9二、如何查看模擬器中的SP與SQList文件。如何可視化查看佈局嵌套層數與加載時間。

9三、各大平臺打包上線的流程與審覈時間,常見問題(主流的應用市場說出3-4個)

9四、屏幕適配的處理技巧都有哪些?

1、爲何要適配

爲了保證用戶得到一致的用戶體驗效果,使得某一元素在Android不一樣尺寸、不一樣分辨率的、不一樣系統的手機上具有相同的顯示效果,可以保持界面上的效果一致,咱們須要對各類手機屏幕進行適配!

  • Android系統碎片化:基於Google原生系統,小米定製的MIUI、魅族定製的flyme、華爲定製的EMUI等等;
  • Android機型屏幕尺寸碎片化:5寸、5.5寸、6寸等等;
  • Android屏幕分辨率碎片化:320x480、480x800、720x1280、1080x1920等。
2、基本概念
  • 像素(px):像素就是手機屏幕的最小構成單元,px = 1像素點 通常狀況下UI設計師的設計圖會以px做爲統一的計量單位。
  • 分辨率:手機在橫向、縱向上的像素點數總和 通常描述成 寬*高 ,即橫向像素點個數 * 縱向像素點個數(如1080 x 1920),單位:px。
  • 屏幕尺寸:手機對角線的物理尺寸。單位 英寸(inch),一英寸大約2.54cm 常見的尺寸有4.7寸、5寸、5.5寸、6寸。
  • 屏幕像素密度(dpi):每英寸的像素點數,例如每英寸內有160個像素點,則其像素密度爲160dpi,單位:dpi(dots per inch)。
  • 標準屏幕像素密度(mdpi): 每英寸長度上還有160個像素點(160dpi),即稱爲標準屏幕像素密度(mdpi)。
  • 密度無關像素(dp):與終端上的實際物理像素點無關,能夠保證在不一樣屏幕像素密度的設備上顯示相同的效果,是安卓特有的長度單位,dp與px的轉換:1dp = (dpi / 160 ) * 1px。
  • 獨立比例像素(sp):字體大小專用單位 Android開發時用此單位設置文字大小,推薦使用12sp、14sp、18sp、22sp做爲字體大小。
3、適配方案

適配的最多的3個分辨率:1280720,19201080,800*480。

解決方案:

對於Android的屏幕適配,我認爲能夠從如下4個方面來作:

一、佈局組件適配

  • 請務必使用密度無關像素 dp 或獨立比例像素 sp 單位指定尺寸。
  • 使用相對佈局或線性佈局,不要使用絕對佈局
  • 使用wrap_content、match_parent、權重
  • 使用minWidth、minHeight、lines等屬性

dimens使用:

不一樣的屏幕尺寸能夠定義不一樣的數值,或者是不一樣的語言顯示咱們也能夠定義不一樣的數值,由於翻譯後的長度通常都不會跟中文的一致。此外,也能夠使用百分比佈局或者AndroidStudio2.2的新特性約束佈局。

二、佈局適配

使用限定符(屏幕密度限定符、尺寸限定符、最小寬度限定符、佈局別名、屏幕方向限定符)根據屏幕的配置來加載相應的UI佈局。

三、圖片資源適配

使用自動拉伸圖.9png圖片格式使圖片資源自適應屏幕尺寸。

普通圖片和圖標:

建議按照官方的密度類型進行切圖便可,但通常咱們只需xxhdpi或xxxhdpi的切圖便可知足咱們的需求;

四、代碼適配:

在代碼中使用Google提供的API對設備的屏幕寬度進行測量,而後按照需求進行設置。

五、接口配合:

本地加載圖片前判斷手機分辨率或像素密度,向服務器請求對應級別圖片。

9五、斷點續傳實現?

在本地下載過程當中要使用數據庫實時存儲到底存儲到文件的哪一個位置了,這樣點擊開始繼續傳遞時,才能經過HTTP的GET請求中的setRequestProperty("Range","bytes=startIndex-endIndex");方法能夠告訴服務器,數據從哪裏開始,到哪裏結束。同時在本地的文件寫入時,RandomAccessFile的seek()方法也支持在文件中的任意位置進行寫入操做。最後經過廣播或事件總線機制將子線程的進度告訴Activity的進度條。關於斷線續傳的HTTP狀態碼是206,即HttpStatus.SC_PARTIAL_CONTENT。

9六、項目中遇到哪些難題,最終你是如何解決的

9七、Activity正常和異常狀況下的生命週期

9八、關於< include >< merge >< stub >三者的使用場景

9九、Android對HashMap作了優化後推出的新的容器類是什麼?

讚揚

若是這個庫對您有很大幫助,您願意支持這個項目的進一步開發和這個項目的持續維護。你能夠掃描下面的二維碼,讓我喝一杯咖啡或啤酒。很是感謝您的捐贈。謝謝!


Contanct Me

● 微信 && 微信羣:

歡迎關注個人微信:bcce5360。因爲微信羣人數太多沒法生成羣邀二維碼,因此麻煩你們想進微信羣的朋友們,加我微信拉你進羣(PS:微信羣的學習氛圍與各項福利將會超乎你的想象)

● QQ羣:

2千人QQ羣,Awesome-Android學習交流羣,QQ羣號:959936182, 歡迎你們加入~

About me

很感謝您閱讀這篇文章,但願您能將它分享給您的朋友或技術羣,這對我意義重大。

但願咱們能成爲朋友,在 Github掘金上一塊兒分享知識。

相關文章
相關標籤/搜索