技術面試 android部分

小楠總發表於2017-12-21

v:* {behavior:url(#default#VML);} o:* {behavior:url(#default#VML);} w:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);}

Normal

0

false

7.8 磅

0

2

false

false

false

EN-US

ZH-CN

X-NONE

/* Style Definitions */ table.MsoNormalTable {mso-style-name:普通表格; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.5pt; mso-bidi-font-size:11.0pt; font-family:等線; mso-ascii-font-family:等線; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:等線; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:等線; mso-hansi-theme-font:minor-latin; mso-font-kerning:1.0pt;} table.MsoTableGrid {mso-style-name:網格型; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-priority:39; mso-style-unhide:no; border:solid windowtext 1.0pt; mso-border-alt:solid windowtext .5pt; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-border-insideh:.5pt solid windowtext; mso-border-insidev:.5pt solid windowtext; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.5pt; mso-bidi-font-size:11.0pt; font-family:等線; mso-ascii-font-family:等線; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:等線; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:等線; mso-hansi-theme-font:minor-latin; mso-font-kerning:1.0pt;}

Android技術面(注意時間的把握與控制) **

1**、自我介紹一下吧(一兩分鐘內,簡短介紹學習、專案經歷) **

我是來自廣東工業大學資訊工程學院的吳煥楠,煥然一新的煥,木字邊加東南西北的楠,我來應聘的崗位是android開發工程師。大二開始自學android開發,看的是淘寶網買的一套黑馬程式設計師的視訊教程,後來又在菜鳥窩官網學習了一套叫做《菜鳥商城》的實戰視訊教程,後期主要是靠實習和看書,看部落格來提升自己的技術水平。

2**、在什麼地方實習過?實習多久?平時主要做什麼?離職了嗎?為什麼離職? **

是這樣的,我是在今年3月份開始在悅乎網路科技有限公司實習的,一直到九月份才離職,一共工作了6個月。這家公司是一家創業型公司,規模比較小,但是基本所有功能模組都是自己獨立完成的,這樣可以有更多鍛鍊自己的機會。但是畢竟是實習,薪水只能滿足於生活費用,現在覺得自己的水平已經有一定提升,因此想得到貴公司的認可。

平時主要的任務就是負責開發《師兄幫幫》APP的各種功能模組的調研,開發以及日常的升級與維護。

3**、能不能簡單介紹一下你做過的APP?開發週期?你做的專案,說一下優缺點,有什麼想改進的地方? **

《師兄幫幫》是一款垂直社交應用平臺,這款產品主打是大學生,裡面有20萬份資料供使用者閱讀檢視和下載。使用者可以在這個平臺上釋出問題或者需要,也可以進行搶單,解決問題以後就有相應的報酬。

**開發週期:**一個星期一個小版本,一個月一個大版本

優點是:技術方面:在架構設計方面比較混亂,沒有用到一些比較新的架構。細節上面:還沒有適配android6.0的動態許可權。

非技術方面:介面比較清晰易懂,但就是功能過於單一。限制太多,很多功能需要花錢,而且使用者之間的互動比較少。至於app的盈利模式,公司規定不能向外透露。

4**、你在開發這個APP的時候你遇到過的技術難點有什麼?你是怎麼解決的?(重點問題,一定要準備) **

*******注意點: **

1**、說到實現一個功能的時候,先說自己想辦法,調研。實在找不到解決方案的時候,就說網上已經有成熟的解決方案。最好能說說找到了什麼方案,最好能說一些外國的SDK或者庫,給人一種比較牛逼的感覺。 **

2**、最好在說的時候突出一下團隊合作,突出自己有提前調研過,計劃好才開始寫程式碼,實在是按時完成不了的就說自己是另外找時間加班完成的。 **

** **

0、記憶體洩漏問題

解決:

先介紹記憶體洩漏:用例子說明,我的手代表app所能使用的記憶體,手裡面能夠放很多東西。比如我手裡有鑰匙,洋娃娃。而洋娃娃需要揚聲器才能工作,那麼洋娃娃和揚聲器之間就有了引用的關係。一旦我扔掉了洋娃娃,就會有垃圾回收器來回收。但是意外的是,我的鑰匙和洋娃娃黏在了一起,阻止了我扔掉洋娃娃。導致洋娃娃不會被回收掉。記憶體洩漏就是外部的引用指向了本來應該被回收的物件,造成物件不能被釋放,導致了記憶體洩漏。

專案中,為了app的特效,打算做水波紋效果,但是這是5.0以上原有的,以下版本需要自己手動實現ViewGroup,後來發現了github上面的水波紋效果控制元件。但是導致app變卡,初步斷定是記憶體洩漏導致的。使用LeakCanary來進行檢測記憶體洩漏(結合Demo),最終分析出是BitMap物件沒有recycle導致。Demo分析,靜態變數比較特殊,是GC root的一種,回收器只會回收非GC root的物件。解決辦法:手動設定為null,或者使用弱引用。

LeakCanary檢測記憶體洩漏的原理是利用虛引用(虛引用不會影響回收,即虛引用不會物件的生命週期,回收取決於物件是否還存在強引用)對被測物件打一個標記,當物件回撥銷燬(onDestory)之後,一旦判斷到這個弱引用還存在的話,就說明物件不能被正確回收,造成了記憶體洩漏。然後利用API把堆記憶體的資訊dump出來,並且彈出通知提醒使用者,最終把資訊顯示到介面上面。

1、
APP內部查閱資料的問題:資料有word、excel、ppt、PDF、圖片等格式。由於PDF和大圖的檢視網上有很多成熟的解決方案。但是谷歌官方並沒有在android原生平臺檢視office文件的功能,相對來說IOS的瀏覽器核心Safari是支援直接開啟office文件的。

解決:本來打算自己實現,但是發現工作量很大,因此只能找第三方解決方案。當時考慮過使用Apache的POI,但是發現這個庫主要是java方向的,對於android的相容性做得不是很好,引入的時候出現過很多問題。也考慮過使用韓國的一款office SDK,叫做北極星Office,但是後來考慮到這個SDK收費太貴所以沒有使用。最後是決定採用使用Web Office服務,有服務動態生成office文件的url,用android的WebView來載入和瀏覽。

2、
第二個要說的就是沉浸式狀態列的實現。這個問題比較尷尬,因為我們的標題欄是白色的,因此如果直接設定狀態列的顏色為白色的話,那麼原有的狀態列上面的文字是白色的話就看不見了。

解決:目前來說只有小米、魅族以及android6.0以上才提供了設定狀態列字型顏色的API。考慮到相容性問題,只能參考市面上的一些app,把狀態列設定為半透明的黑色。使用了github上面的一個開源庫system bar tint,並且在app主題中開啟了透明狀態列。

3、
簡訊驗證碼的自動填寫。

解決:使用Content Observer去觀察簡訊資料庫的收件箱,當有新的簡訊進來的時候,就通過正規表示式去獲取簡訊中的驗證碼,並且通過handler把結果傳遞到UI中。四個連續數字(\d{4})

4、
動態庫檔案(so檔案)衝突:由於當時想引入Fresco圖片快取框架,但是後來發現由於Fresco框架對不同架構的平臺的支援得非常好,提供了所有平臺的so包,但是這樣會導致app不能正確載入其他庫(如簡訊驗證SDK)的so庫,從而引發crash。

解決:當時是看到Stack Overflow上的一篇部落格介紹,通過配置APP的gradle指令碼檔案,使得app只輸出armabi架構的so包,成功解決問題。

5、
實現防止多終端登入同一個賬號的時候,伺服器需要知道使用者是否正在登入app。

解決:通過後臺開一個Service,每隔一段時間去訪問服務端的一個心跳介面,從而告訴服務端app的某個賬號正在使用。當時也考慮過其他的解決方案,但是這個唯有客戶端去輪詢才能實現。

6、
使用第三方SDK時,例如融雲即使聊天、Ping++的時候,遇到問題一般都是通過提交工單的方式去尋求解決。

5**、你說你看過好多書,能不能簡單介紹一下你看過什麼書?平時看什麼部落格?自己寫過部落格嗎? **

《android原始碼設計模式解析與實戰》,這是一本介紹了設計原則、設計模式以及android原始碼的一本書。

《android群英傳》,《android開發藝術探索》,《android開發從小工到專家》,這些都是android方面的技術進階書籍,從各個方面介紹android開發中的一些常見的難點。

《android神兵利器》,主要介紹了git、android studio等工具的使用,還沒看完。

平時看的部落格主要來源於CSDN,微信公眾號等,自己有在簡書上面寫技術部落格以及筆記。

6**、你會不會使用反射技術?你是怎麼理解這個技術的?在什麼地方用過? **

我對反射技術的理解就是,反射就是把Java類中的各種成分通過java的反射API對映成相應的Java類,得到這些類以後就可以對其進行使用。比如方法,構造方法,成員變數,型別,包等。

直接用到反射技術的不多,一般都是間接用到比較多。比如:

1、android中的通過讀取佈局檔案的資訊,然後利用反射來構造各種控制元件的物件。

2、使用開源ORM資料庫框架的時候,是通過反射的方式來進行java Bean和表的對映的。

3、Gson在解析JSON並且生成Bean物件的時候利用了反射技術。

7**、什麼是設計模式?你知道哪些設計模式?簡單介紹一下吧 **

設計模式(Design pattern)是一套被反覆使用、多數人知曉的、經過分類編目的、程式碼設計經驗的總結。

單例模式,主要用在一些資源消耗比較多的類身上,比較典型的實現由DCL方式、列舉、靜態內部類來實現。例子有

  1. SystemService
  2. 運算元據庫的類,DataBaseOpenHelper
  3. 操作SharePreference的類
  4. 各種管理類,比如網路,圖片載入器等等

單例模式的DCL失效問題:虛擬機器允許指令的亂序執行,當單例例項化的時候,實際上會執行了三個步驟:

給單例例項分配記憶體空間

呼叫單例例項的建構函式,初始化一些欄位

將單例例項物件指向分配的記憶體空間(sInstance不為null)

2、3兩步的執行順序是不確定的,因此如果在多執行緒的狀態下,執行緒A執行了3以後,執行緒B馬上來取走例項,就是報錯(因為第二部的初始化還沒有完成)

Builder模式,主要是用作一些複雜類的構建,並且一般支援連點操作。例子:

  1. AlertDialog的構建
  2. ImageLoader等圖片載入框架類的構建

Adapter模式:這種模式主要是解決介面不相容的問題。例子:

我們常用的ListView、RecycleView等,就使用了adapter模式設計,這樣做分離了ListView顯示檢視,Adapter提供資料以及操作的功能,負責單一職責原則。

觀察者模式:這種模式是主要有被觀察者、觀察者組成,當被觀察者的觀察行為發上變化的時候,觀察者可以馬上做出相應處理。例子:

Content Observer

RXJava

ListView、RecycleView在設定Adapter的時候也註冊了資料觀察者,當使用者呼叫notifyDateSetChange等方法的時候,這些觀察者就會通知這些控制元件去重新重新整理檢視。

工廠模式:主要是定義了一個物件建立的介面,具體產生什麼類由使用者去實現。例子:

  1. Activity中的onCreate方法,就是構造檢視View的工廠方法
  2. Collection中的iterator方法
  3. Bitmap的建立也可以通過工廠方法

裝飾者模式:動態地給一個物件新增一些額外的功能。例子:應用:IO流,ContextWrapper等。

8**、Java與JS的互動**

1、Java呼叫JS:直接利用WebView載入URL即可:webview.loadUrl("javascript:method("+引數+")");

2、WebView設定使能JS,建立JS Interface,設定到WebView當中。JS通過中window.appInterface.buy(id);呼叫Java方法。

9**、簡述一下android的訊息傳遞機制吧。 **

Android中的訊息機制主要是指Handler的執行機制。Handler是進行執行緒切換的關鍵,在主執行緒和子執行緒之間切換隻是一種比較特殊的使用情景而已。其中訊息傳遞機制需要了解的東西有Message、Handler、Looper、Looper裡面的MessageQueue物件。我們可以把整個訊息機制看作是一條流水線。其中:

  1. MessageQueue是傳送帶,負責Message佇列的傳送與管理
  2. Looper是流水線的發動機,不斷地把訊息從訊息佇列裡面取出來,交給Handler來處理
  3. Message是每一件產品
  4. Handler就是工人。但是這麼比喻不太恰當,因為傳送以及最終處理Message的都是Handler

app在啟動的時候,也就是執行ActivityThread的main方法的時候,會為主執行緒建立Looper,並且啟動整個app的訊息迴圈,同時保證app不會立馬退出。

另外,子執行緒之間也可以利用Handler進行通訊,甚至是子執行緒可以通過Handler發訊息給主執行緒。前提條件是子執行緒沒有關聯Looper,因此必須手動建立Looper並且啟動訊息迴圈。

10**、簡述一下android的事件傳遞機制吧。遇到過(滑動)事件衝突嗎?你是怎麼解決的? **

事件總是從上往下進行分發,即先到達Activity,再到達ViewGroup,再到達子View,如果沒有任何成員消耗事件的話,事件會順著路徑往回傳遞。

  1. dispatchTouchEvent是事件的分發方法,如果事件能夠到達該檢視的話,就首先一定會呼叫,一般我們不會去修改這個方法。
  2. onInterceptTouchEvent是事件分發的核心方法,表示ViewGroup是否攔截事件,如果返回true表示攔截,在這之後ViewGroup的onTouchEvent會被呼叫,事件就不會往下傳遞。
  3. onTouchEvent是最低階的,在事件分發中最後被呼叫。
  4. 子View可以通過requestDisallowInterceptTouchEvent方法去請求父元素不要攔截。

遇到過事件衝突:就是ViewPager其中一個Pager上面的Banner,當Banner還沒滑到最後一頁的時候,應該請求ViewPager不要攔截自己的滑動事件;當Banner滑動到最後一頁的時候,要請求ViewPager去攔截自己的滑動事件,從而使得ViewPager能夠跟Banner配合工作。

結合自己的Demo說說,舉例子:爺父子之間傳遞蘋果

11**、簡要說說View的工作機制。有自定義過View嗎?簡要說說。 **

View的工作機制(View的繪製流程)主要包括測量(Measure)和繪製(Draw),而對於ViewGroup來說還包括佈局(Layout)。

1、測量主要是根據使用者指定的測量大小以及模式通過setMeasuredDimension方法去設定View的大小。精確模式下需要返回使用者指定的大小。最大值模式以及不明確指定的模式下,需要提供預設大小,在最大值模式下需要返回兩者的最小值。

2、繪製主要是通過一些畫圖API比如畫布畫筆,在View區域上面動態畫一些東西。

3、佈局主要是自定義ViewGroup的時候實現的,主要是控制各個子View在ViewGroup的位置以及他們之間的位置關係。

把《師兄幫幫》那個錄音按鈕給面試官看

12**、有沒有(參與)寫過(開源)框架? **

雖然我沒有在GitHub上面參與或者發表過開源專案,感覺自己想傳上去,但是發現已經有實現了,但是我經常關注GitHub上面看一些不錯的開源專案和控制元件,比如說BGARefreshLayout、BaseRecyclerViewAdapterHelper、程式碼家以及各種自定義控制元件等。平常也有關注一些android開發相關的微信公眾號,比如徐宜生、郭霖、android開發技術前線等,以及簡書、CSDN等一些大牛的部落格,平時自己也有在簡書上面用MD來寫一些技術文章。

13**、有沒有關注一些新技術? **

RXJava:

一個非同步請求庫,核心就是非同步。利用的是一種擴充套件的觀察模式,被觀察者發生某種變化的時候,可以通過事件(onNext、onError、onComplete)等方式通過觀察者。RXJava同時支援執行緒的排程和切換,使用者可以指定訂閱發生的執行緒以及觀察者觸發的執行緒。

Retrofit 2.0:

通過註解的方式來指定URL、請求方法,實質上底層是通過OKHttp來實現的。

Dagger 2:一個依賴注入框架

HotFit:淘寶的Dexposed(相容性不好,利用AOP面向切面程式設計實現)、阿里巴巴的AndFix(Dexposed從Method入手,但是AndFix從Field入手,不需要重啟),QQ空間的ClassLoader(虛擬機器載入類之前,通過反射去修復有問題的Dex檔案),微信的Tinker(沒有了解過,因為之前的手機用不了)、Nuwa(需要重啟)

外掛式開發:核心是動態載入技術。當app越來越大的時候,通過外掛化來減輕應用的記憶體以及CPU,還可以實現熱插拔,實現動態修復和更新。

大概瞭解,需要用到的技術:反射、動態代理、類載入器原理等。外掛開發是開發者通過將外掛程式碼封裝成Jar或者Apk檔案放在網路或者本地。在宿主app中載入並且呼叫外掛中的方法。

14**、看過什麼框架?原始碼?原理?有沒有自己寫過框架? **

**網路請求框架的基本流程: **

1、首先build request引數

2、因為不能在主執行緒請求HTTP,所以你得有個Executor或者執行緒

3、enqueue後,通過執行緒去執行請求,把Request物件通過位元組流輸出

4、得到伺服器資料後,獲取返回的輸入位元組流,通過反序列化轉換成需

要的實體物件,最後通過callback回撥給客戶端,同時還要實現執行緒切換

**Retrofit****的一些優點: **

1、型別安全:通過指定泛型來實現

2、可擴充套件性強,可以適應不同的業務需求

3、簡潔高效:通過註解的方式來實現網路請求,大大減少了程式碼量

4、高度解耦,內部通過Adapter模式適配不同的框架,比如RXJava等

**Retrofit****原始碼流程概述: **

1、先通過Builder模式去構造Retrofit物件,其中Retrofit只是外觀模式包裝的一個物件,所有基本功能都通過Retrofit來對外提供。構造Retrofit的內部構造了OkHttpClient物件,並且構建了CallbackExecutor物件,用來處理請求。同時也為Retrofit指定了Converter。

2、為我們的請求介面建立動態代理物件,當這個物件的方法被呼叫的時候,會被攔截,並且通過ServiceMethod類去通過反射的方式去獲取這個物件上面的註解,通過這些註解獲取網路請求方法、請求體等,最後構造出OKHttpCall物件、RequestConverter以及ResponseConverter,這兩個Converter分別是代表把請求物件、返回物件進行轉換,例如轉換成JSON、XML等。(注意:由於通過反射獲取物件的註解是耗時並且消耗效能的,ServiceMethod內部有做快取,解析過就直接複用)

3、當我們呼叫Call物件進行enqueue或者execute的時候,內部是把OKHttpCall轉換成CallAdapter,分別適配:RxJava, Java8, Guava還有一個Retrofit預設的回撥。

4、把請求分發給CallbackExecutor物件執行,CallbackExecutor內部其實是呼叫OkHttp的一些相關方法進行請求。請求執行的時候通過RequestConverter進行轉換。

5、請求返回的時候,判斷返回碼的型別,通過ResponseConverter物件把返回的位元組流轉換成實體物件,最後通過Handler機制post一個Runnable把Callback回撥給主執行緒,重新整理介面等操作。如果是使用RXJava的話,還可以很方便地先去指定子執行緒進行資料轉換再返回主執行緒進行介面重新整理。

**Retrofit****的一些功能擴充套件: **

1、通過自定義RequestConverter以及ResponseConverter進行資料網路傳輸的加密、解密。

2、可以通過自定義執行緒池來維護請求佇列,適應具體的業務需求。比如先進先出、後進先出等。

3、通過Adapter模式(CallbackAdapter)可以利用不同的框架實現不同的回撥程式碼,比如RXJava、Java8、Guava等。

4、通過不同Converter實現Request以及Resource適應不同的協議,比如JSON、XML等。

主流的網路請求框架

1**、**HttpURLConnection:在android4.4中已經替換成OKHttp了。

2**、**HttpClient:API數量比較多,使得我們很難在不破壞相容性的

情況下對它進行升級和擴充套件維護成本較高,android5.0廢棄,6.0刪除。

3**、**Volley:已經停止更新。Android2.2以下版本使用HttpClient、

android2.2以上版本使用HttpURLConnection實現。但是相對來說擴

展性比Okhttp較低。

4**、**OkHttp:支援自定義請求頭、支援一般的請求方法、檔案上傳

下載、圖片載入、IP自動重連、Gzip、SPDY、連線池、HTTP快取等。

Retrofit:和Volley框架的請求方式很相似,底層網路請求採用okhttp

(效率高,android4.4底層採用okhttp),採用註解方式來指定請求方

式和url地址,減少了程式碼量。

主流的圖片載入框架

1.、Picasso:和Square的網路庫一起能發揮最大作用,因為Picasso可以選擇將網路請求的快取部分交給了okhttp實現。 2.、Glide:模仿了Picasso的API,而且在他的基礎上加了很多的擴充套件(比如gif等支援),支援圖片流,因此在做愛拍之類的視訊應用用得比較多一些。 3.、Fresco:Fresco中設計有一個叫做image pipeline的模組。它負責從網路,從本地檔案系統,本地資源載入圖片。 為了最大限度節省空間和CPU時間,它含有3級快取設計(2級記憶體,1級檔案)。Fresco中設計有一個叫做Drawees模組, 方便地顯示loading圖,當圖片不再顯示在螢幕上時,及時地釋放記憶體和空間佔用。

Fresco是把圖片快取放在了Ashmem(系統匿名記憶體共享區)

  1. Heap-堆記憶體:Android中每個App的 Java堆記憶體大小都是被嚴格的限制的。每個物件都是使用Java的new在堆記憶體例項化,這是記憶體中相對安全的一塊區域。記憶體有垃圾回收機制,所以當App不在使用記憶體的時候,系統就會自動把這塊記憶體回收。不幸的是,記憶體進行垃圾回收的過程正是問題所在。當記憶體進行垃圾回收時,記憶體不僅僅進行了垃圾回收,還把Android 應用完全終止了。這也是使用者在使用 App 時最常見的卡頓或短暫假死的原因之一。
  2. Ashmem:Android 在操作 Ashmem 堆時,會把該堆中存有資料的記憶體區域從 Ashmem 堆中抽取出來,而不是把它釋放掉,這是一種弱記憶體釋放模式;被抽取出來的這部分記憶體只有當系統真正需要更多的記憶體時(系統記憶體不夠用)才會被釋放。當Android 把被抽取出來的這部分記憶體放回 Ashmem堆,只要被抽取的記憶體空間沒有被釋放,之前的資料就會恢復到相應的位置。

不管發生什麼,垃圾回收器都不會自動回收這些 Bitmap。當 Android 繪製系統在渲染這些圖片,Android 的系統庫就會把這些Bitmap 從 Ashmem 堆中抽取出來,而當渲染結束後,這些Bitmap 又會被放回到原來的位置。如果一個被抽取的圖片需要再繪製一次,系統僅僅需要把它再解碼一次,這個操作非常迅速。

圖片的三級快取

當app需要使用圖片的時候,先到記憶體快取去取,因為記憶體快取速度最快。如果記憶體快取沒有,再去本地快取取,如果都沒有,就到網路獲取。獲取以後分別寫入記憶體快取以及本地快取。

自己寫過圖片載入框架:

概述:利用組合設計模式,圖片載入功能在ImageLoader集中對外公開,ImageLoader是統籌了圖片下載器,圖片快取等功能。

ImageLoader

ImageDownloaderer

ImageCache

ImageLoader

ImageLoader

遇到的問題:

1、
使用LruCache代替弱(軟)引用儲存,因為API9以後GC會更傾向於回收持有弱引用的物件。LruCache是android提供的一個快取工具類,其演算法是最近最少使用演算法。它把最近使用的物件用“強引用”儲存在LinkedHashMap中,並且把最近最少使用的物件在快取值達到預設定值之前就從記憶體中移除。其在API12被引進,低版本可以用support包中的類。

2、
圖片的錯位問題。通過給ImageView打一個url標記,每次設定顯示圖片的時候先判斷Bitmap是否對應某一個ImageView。

3、
url作為鍵值對中的鍵問題,使用MD5演算法把url轉為MD5字串。

15**、網路優化、網路安全問題。**

為什麼要做快取,或者說有什麼好處?

1、減少伺服器負荷,降低延遲提升使用者體驗。

2、複雜的快取策略會根據使用者當前的網路情況採取不同的快取策略,比如在2g網路很差的情況下,提高快取使用的時間;

3、不用的應用、業務需求、介面所需要的快取策略也會不一樣,有的要保證資料的實時性,所以不能有快取,有的你可以快取5分鐘,等等。你要根據具體情況所需資料的時效性情況給出不同的方案。當然你也可以全部都一樣的快取策略,看你自己。

網路優化建議點:

1、連線複用節省連線建立時間,如開啟keep-alive

2、不用域名,用IP直連省去DNS解析過程,根據域名得到IP地址

3、能夠快取的儘量快取起來,減少網路請求,減輕伺服器負擔

網路請求的安全性問題: 這塊瞭解的不多。我給你說說我的思路吧,利用對稱加密。伺服器給我們的資料可以通過金鑰和其他引數做個MD5加密,得到一個key;在客戶端按照相同的辦法生成key然後與服務端給的做個對比。

對稱加密: 檔案加密和解密使用相同的金鑰,即加密金鑰也可以用作解密金鑰。DES、IDEA

非對稱加密: 非對稱加密演算法需要兩個金鑰:公開金鑰(publickey)和私有金鑰(privatekey)。公開金鑰與私有金鑰是一對,如果用公開金鑰對資料進行加密,只有用對應的私有金鑰才能解密;如果用私有金鑰對資料進行加密,那麼只有用對應的公開金鑰才能解密。RSA,RCC

16**、程式、執行緒通訊、Linux相關 **

如何開啟多程式?

1、通過在清單檔案對四大元件指定android:process屬性。除此之外android是沒有辦法指定執行緒或者實體類執行所在的程式。

2、非常規方法:通過JNI在native層去fork一個新的程式。

多程式所帶來的問題: 1、靜態成員和單例模式完全失效。

2、執行緒同步機制會完全失效。

3、SharePreferences的可靠性會下降。 4、Application會多次被建立,例如在推送或者即時通訊SDK中,需要單獨開一個程式來接收訊息,那麼我們在Application中初始化SDK的時候,需要判斷當前程式是否為當前APP的主程式,是就初始化,否則不做任何操作。

程式間通訊方式對比:

方式

優點

缺點

適用場景

Bundle

簡單易用

只支援Bundle支援的資料型別

四大元件之間的跨程式通訊

檔案共享

簡單易用

不適合高併發場景,並且無法做到即時通訊

無併發的情形,實時性不高的場景

AIDL

功能強大,支援一對多併發實時通訊

適用稍微複雜,需要處理執行緒同步問題

一對多通訊,實時性高

Messenger

功能一般,支援一對多序列實時通訊

不能很好處理高併發,只能傳輸Bundle支援的型別

低併發的一對多實時通訊,無需返回結果

ContentProvider

資料來源訪問方面功能強大,支援一對多併發資料共享,可以通過call方法進行擴充套件

可以理解為受約束的AIDL,主要是資料來源提供CRUD操縱

一對多的程式間資料共享

Socket

功能強大,通過網路傳輸位元組流,支援一對多併發實時通訊

實現麻煩,不支援直接的RPC

網路資料交換

**Linux****中的程式間通訊方式: **

1、命名管道  2、共享記憶體  3、訊號量

**Android****中程式的級別: **

前臺程式(正在與使用者互動)、可見程式(有可見的介面)、服務程式、後臺程式、空程式

常用的Linux命令:mkdir 建立資料夾、rmdir 刪除資料夾、rm 刪除檔案、mv 移動檔案、cp 拷貝檔案、cat 檢視檔案

tail 檢視檔案尾部、more 分頁檢視檔案、cd 切換當前目錄、ls 列出檔案清單、reboot 重啟、date 顯示日期

cal 顯示日曆、ps 檢視系統程式相當於windows 的工作管理員、ifconfig 配置網路

** **

**Linux****程式和DVM的程式是否為同一個概念? **

每一個Android 應用程式都擁有一個獨立的虛擬機器例項,應用程式都在它自己的程式中執行。而每一個dvm都是在Linux中的一個程式,所以說可以近似認為是同一個概念。

獨立的程式可以防止在虛擬機器崩潰的時候所有程式都被關閉。

**Android****中的安全機制 **

1、Android 是基於Linux 核心的,因此Linux 對檔案許可權的控制同樣適用於Android。在Android 中每個應用都有自己的/data/data/包名資料夾,該資料夾只能該應用訪問,而其他應用則無權訪問。

2、Android 的許可權機制保護了使用者的合法權益。如我們的程式碼想撥打電話、傳送簡訊、訪問通訊錄、定位、訪問sdcard等所有可能侵犯用於權益的行為都是必須要在AndroidManifest.xml 中進行宣告的,這樣就給了使用者一個知情權。並且在android6.0中引入了動態許可權管理

3、Android 的程式碼混淆以及apk的簽名保護了開發者的權益。

**AIDL****主要思路(步驟)就是: **

1、服務端建立一個Service來監聽客戶端的連線請求。建立AIDL檔案,將介面暴露給客戶端,並在Service中實現這個介面。

2、客戶端繫結Service,並定成功之後將服務端返回的Binder物件轉換成AIDL中的介面型別,然後就可以呼叫介面的方法,並且獲取返回值。

17**、Android新特性相關**

  1. 5.0:Material Design、多種裝置的支援、支援64位ART虛擬機器、Project Volta電池續航改進計劃等
  2. 6.0:動態許可權管理、過度動畫、支付、指紋等
  3. 7.0:分屏、通知訊息快捷回覆、夜間模式、流量保護模式等

18、在技術上的發展有什麼規劃?(離職原因)(實現自己的價值,學習牛逼的技術,公司的發展前景) **

之前的公司就是直接實現業務邏輯的,功能的話只要給時間一定可以實現的。然後在上一家公司就是接觸到了一些思想層次上的,比如設計模式啊MVC之類的,然後買了一些書來看,現在在往這方面發展。以後的就要等我再學到一定層次再考慮了。

19、螢幕適配 **

1、**對應不同螢幕建立不同的dimen的資料夾,放置不同的大小 ,根據螢幕解析度建立不同layout資料夾,使用權重來適配

2、**使用九切圖和SVG圖片、xml來代替直接使用png

3長度單位用dp代替px   ** 4**、使用wrap_content, match_parent, weight 5、**使用相對佈局,在開發中禁用絕對佈局

**上和左控制拉伸,下和右負責內容區域 5、使用線性佈局,放不下的時候用ScrollView包裹 **

20**、android分包、外掛化、熱修復等相關知識: **

Dex分包 **

**引入原因:**在apk程式碼量越來越多的時候,往往會出現方法數量過多(超過了65536),而一個dex檔案最多隻支援65536個方法;apk過大不能在一些舊版本的android手機上面安裝,因為android2.3以前的版本分配 用來執行dex優化的 記憶體只有5M。

android的載入器體系與java類載入器體系對比: **

1、PathClassLoader:載入安卓應用,只能載入

已安裝到系統中(即/data/app目錄下)的

apk檔案。

2、 DexClass:可以載入apk,jar,及dex檔案。

載入一個類的時候,ClassLoader先遍歷一個裝在dex檔案(每個dex檔案實際上是一個DexFile物件)的陣列(Element陣列,Element是一個內部類),然後依次去載入所需要的class檔案,直到找到為止。

Dex注入的解決方案:假如我們將第二個dex檔案放入Element陣列中,在載入第二個dex包中的類時,應該可以直接找到。 **

Dex分包的注意要點: **

  1. 由於第二個dex包是在Application的onCreate中動態注入的,如果dex包過大,會使app(Activity)的啟動速度變慢,因此,在dex分包過程中一定要注意,第二個dex包不宜過大。

  2. 由於上述第一點的限制,假如我們的app越來越臃腫和龐大,往往會採取dex分包方案和外掛化方案配合使用,將一些非核心獨立功能做成外掛載入,核心功能再分包載入。

** **

**外掛化 **

思路:通過在宿主app裡面註冊新增一些activity作為外掛app的容器,載入外掛app,通過動態代理的方法去處理被

載入(被代理)的activity、fragment的生命週期。由此引出Activity與Fragment之間的傳值問題**

第三方服務:apkplug,還沒有仔細研究就辭職了,由此引出久邦數碼舉辦的app創新設計大賽。

外掛化第三方框架:360的DroidPlugin、攜程的DynamicAPK、今年初開源的Small

21**、android外掛化是否有其他更好的代替方法? **

**外掛化引入: **

1、APK方法數量過多2、低版本手機安裝出錯

3、移動應用中的2/8定律,80%的使用者訪問20%的頁面,那麼剩下80%的頁面是沒必要使用者去下載的,只有在用到的時候去下載。通過這樣可以大大減輕app對CPU、記憶體的負擔,同時也實現動態載入的目的。

**代替方案: **

1、移動應用從C/S架構向B/S架構的轉變。最近比較火的一個框架React Native。基於頁面級別的動態載入。2、買付費的Proguard

3、最笨的方法是刪除無用的程式碼以及模組

**熱修復 **

app上線之後需要緊急去修改一些有問題的程式碼,常規的方法是重新測試、打包、混淆加密加固、上線。這樣太麻煩。

**第三方方案: **

**阿里巴巴的AndFix:**通過載入器讀取一個dex檔案中的類,並找到被註解標記到的要修復的方法,再通過jni在C層替換掉原本出BUG的方法的指標,從而達到熱修復的目的。

QQ空間的熱修復方案:**MultiDex的思路,在應用啟動的時候,往Classloader的PathList裡面插入一個Dex,通過覆蓋掉出BUG的類來做到熱修復。QQ空間只出了理論方案,而這套方案的開原始碼實現,則是由 賈吉鑫 寫了一個 nuwa 託管在 Github 上。

** **

22**、怎麼定位 **

**anr****問題程式碼位置? **

** **

ANR:**Application Not Response

導致ANR的原因有:主執行緒(Activity、Service)是5 秒,BroadCastReceiver 是10 秒。(自己專案:在主執行緒去讀取SD卡)

**解決方案:**將所有耗時操作,比如訪問網路,Socket 通訊,查詢大量SQL 語句,複雜邏輯計算等都放在子執行緒中去,然後通過handler.sendMessage、runonUITread去重新整理UI;顯示Loading!!!;onReceive啟動Service

**定位:**發生ANR以後,系統會在/data/anr目錄下面生成一個traces.txt檔案

第一步,先pull出/data/anr/traces.txt檔案。 第二步,檢視app被殺死時的執行緒id。 第三步,檢視traces.txt裡關於該執行緒id的資訊。

典型場景,呼叫關係比較複雜的時候,比如說主執行緒的方法裡面開了一個子執行緒,子執行緒獲得了同步鎖,主執行緒的方法被阻塞掉。此時應該先分析主執行緒,檢視什麼鎖被什麼執行緒hold住了,然後再對應去看那個執行緒。

23**、避免OOM的一些常見方法:**

1、App資源中儘量少用大圖。使用Bitmap的時候要注意等比例縮小圖片,並且注意Bitmap的回收。 BitmapFactory.Options options = new BitmapFactory.Option(); options.inSampleSize = 2; //Options 只儲存圖片尺寸大小,不儲存圖片到記憶體 BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inSampleSize = 2; Bitmap bmp = null; bmp = BitmapFactory.decodeResource(getResources(), mImageIds[position],opts); //回收 bmp.recycle(); 2、結合元件的生命週期,釋放資源 3、IO流,資料庫查詢的遊標等應該在使用完之後及時關閉。 4、ListView中應該使用ViewHolder模式快取ConverView 5、頁面切換的時候儘量去傳遞(複用)一些物件,通過Intent傳遞過去

24**、Android中如何捕獲未捕獲的異常 **

1、自定義Application,實現Thread.UncaughtExceptionHandler

2、實現uncaughtException(Thread t, Throwable e)方法,在方法中處理異常。如果不能處理的話,一般android.os.Process.killProcess(android.os.Process.myPid());來結束自己,避免把異常資訊報給使用者。

3、在Application初始化的時候設定Thread.setDefaultUncaughtExceptionHandler(this);

** **

25**、Android6.0新增的動態許可權 **

1、對於6.0以下的許可權及在安裝的時候,根據許可權宣告產生一個許可權列表,使用者只有在同意之後才能完成app的安裝,也就是說許可權在安裝的時候已經授予了。

2、對於6.0或以上的版本,谷歌把許可權分為了兩類,

一種是Normal Permission,例如訪問網路、網路狀態獲取、震動等;

另外一種是Dangerous Permission,例如傳送、讀取簡訊、打電話、讀取通訊錄、錄音等。並且引入了許可權組的概念,如果你申請某個危險的許可權,假設你的app早已被使用者授權了同一組的某個危險許可權,那麼系統會立即授權,而不需要使用者去點選授權

**許可權申請方式: **

1、在清單檔案裡面配置許可權,跟以前一樣。

2、檢查許可權ContextCompat.checkSelfPermission,方法返回值為PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED。

3、在Activity中使用ActivityCompat的requestPermissions,或者在Fragment裡面直接使用Fragment提供的requestPermissions方法去申請某一個危險許可權,然後在onRequestPermissionsResult回撥裡面進行業務邏輯。

**最簡單的解決方式:在gradle配置檔案中把targetSDK改為小於23。 **

26**、佈局優化 **

1、使用includea標籤去複用相同的佈局

2、使用merge標籤去除同類的檢視

3、使用ViewStub來延遲載入一些不常用的佈局

27**、記憶體優化 **

1、珍惜Service資源,儘量使用IntentService IntentService在內部其實是通過執行緒以及Handler實現的,當有新的Intent到來的時候,會建立執行緒並且處理這個Intent,處理完畢以後就自動銷燬自身。因此使用IntentService能夠節省系統資源。

2、實現一些在記憶體緊張的時候會回撥的一些方法,比如Activity中的onLowMemory、onTrimMemory。比如停止動畫特效等。

3、通過Manifest中對Application配置更大的記憶體,但是一般不推薦。 android:largeHeap="true" 4、避免Bitmap的浪費,應該儘量去適配螢幕裝置。儘量使用成熟的圖片載入框架,Picasso,Fresco,Glide等。 5、使用優化的容器,SparseArray等 6、其他建議:儘量少用列舉變數,儘量少用抽象,儘量少增加類,避免使用依賴注入框架,謹慎使用library,使用程式碼混淆,時當場合考慮使用多程式等。 7、避免記憶體洩漏(本來應該被回收的物件沒有被回收)。一旦APP的記憶體短時間內快速增長或者GC非常頻繁的時候,就應該考慮是否是記憶體洩漏導致的。

28**、效能優化 **

1、防止過度繪製,通過開啟手機的“顯示過度繪製區域”即可檢視過度繪製的情況。 2、最小化渲染時間,使用檢視樹檢視節點,對節點進行效能分析。 3通過TraceView進行資料的採集以及分析。在有大概定位的時候,使用Android官方提供的Debug類進行採集。最後通過DDMS即可開啟這個.trace檔案,分析函式的呼叫情況(包括在指定情況下執行時間,呼叫次數) //開啟資料採集 Debug.startMethodTracing("test.trace"); //關閉 Debug.stopMethodTracing();

29**、SharedPreference **

SharedPreference.Editor的apply和commit方法異同: ** 1. apply沒有返回值而commit返回boolean表明修改是否提交成功 2. apply是將修改資料原子提交到記憶體, 而後非同步真正提交到硬體磁碟, 而commit是同步的提交到硬體磁碟,因此,在多個併發的提交commit的時候,他們會等待正在處理的commit儲存到磁碟後在操作,從而降低了效率。而apply只是原子的提交到記憶體,後面有呼叫apply的函式的將會直接覆蓋前面的記憶體資料,這樣從一定程度上提高了很多效率。 3. apply方法不會提示任何失敗的提示。

**注意點: **

0、每次呼叫commit()、apply()都會將整個settings全部寫到檔案中,即使你只改動了一個setting。因為它是基於全域性的,而不是增量的,所以你的客戶端程式碼中一定不要出現一個putXXX就緊跟著一個commit/apply,而是put完所有你要的改動,最後呼叫一次commit/apply。 1、由於在一個程式中,SharedPreference是單例項,一般不會出現併發衝突,如果對提交的結果不關心的話,建議使用apply。2、當然需要確保提交成功且有後續操作的話,還是需要用commit(利用返回值)的。

3、**原始碼中多執行緒同步問題:**SharedPreference通過一個標誌來控制多執行緒併發讀寫的,資料提交的時候,會把標誌加一,資料提交完畢的時候會減一,因此如果判斷到標誌大於0的話就證明還有資料沒有提交完成,那麼就把資料集(Map)重新拷貝一份再進行後續提交操作。

4、**多程式中:**SharePreferences的可靠性會下降。

SharedPreference的xml檔案什麼時候載入到記憶體中? **

app啟動Context初始化的時候,通過SharedPreferencesImpl的startLoadFromDisk中會起一個執行緒呼叫loadFromDiskLocked從磁碟上載入資料。

如果一個應用中有好幾個sharedPreferences時,每個sp對應的SharedPreferencesImpl都會各自起一個執行緒去把xml中的資料載入到map中,後面所有的getXXX方法實際上都是從記憶體中取資料,不會再有讀磁碟的動作了。

**注意:**SharedPreference的序列化和解析的操作都是在記憶體中完成,由於每一個DVM分配的堆記憶體一般最大隻有16M,因此不建議在SharedPreference中儲存太大的資料。

30**、Activity與Fragment傳值問題 **

1、findFragmentByTag或者getActivity獲得對方的引用(強轉)之後,再相互呼叫對方的public方法,耦合度高。

2、通過Bundle的方法進行傳值,fragment.setArguments()

3、通過EventBus或者RxBus,耦合度低。

31**、Activity相關 **

Activity生命週期 **

Activity 從建立到銷燬有多種狀態,從一種狀態到另一種狀態時會激發相應的回撥方法,這些回撥方法包括:

onCreate onStart onResume onPause onStop onDestroy

其實這些方法都是兩兩對應的,onCreate 建立與onDestroy 銷燬;onStart 可見與onStop 不可見;onResume 可編輯(即焦點)與onPause;在Activity 被onStop 後,但是沒有被onDestroy,在再次啟動此Activity 時就呼叫onRestart(而不再呼叫onCreate)方法;如果被onDestroy 了,則是呼叫onCreate 方法。

** **

Activity的啟動原理(大概把過程說出來) **

1.無論是通過Launcher來啟動Activity,還是通過Activity內部呼叫startActivity介面來啟動新的Activity,都通過Binder程式間通訊進入到ActivityManagerService程式中,並且呼叫ActivityManagerService.startActivity介面;

2.ActivityManagerService呼叫ActivityStack.startActivityMayWait來做準備要啟動的Activity的相關資訊;

3.ActivityStack通知ApplicationThread要進行Activity啟動排程了,這裡的ApplicationThread代表的是呼叫ActivityManagerService.startActivity介面的程式,對於通過點選應用程式圖示的情景來說,這個程式就是Launcher了,而對於通過在Activity內部呼叫startActivity的情景來說,這個程式就是這個Activity所在的程式了;

4.ApplicationThread不執行真正的啟動操作,它通過呼叫.activityPaused介面進入到ActivityManagerService程式中,看看是否需要建立新的程式來啟動Activity;

5.對於通過點選應用程式圖示來啟動Activity的情景來說,ActivityManagerService在這一步中,會呼叫startProcessLocked來建立一個新的程式,而對於通過在Activity內部呼叫startActivity來啟動新的Activity來說,這一步是不需要執行的,因為新的Activity就在原來的Activity所在的程式中進行啟動;

6.ActivityManagerServic呼叫ApplicationThread.scheduleLaunchActivity介面,通知相應的程式執行啟動Activity的操作;

7.ApplicationThread把這個啟動Activity的操作轉發給ActivityThread,ActivityThread通過ClassLoader匯入相應的Activity類,然後把它啟動起來。

**兩個Activity 之間跳轉時必然會執行的是哪幾個方法? **

一般情況下比如說有兩個activity,分別叫A,B,當在A 裡面啟用B 元件的時候, A 會呼叫onPause()方法,然後B 呼叫onCreate() ,onStart(), onResume()。

這個時候B 覆蓋了窗體, A 會呼叫onStop()方法. 如果B 是個透明的,或者是對話方塊的樣式, 就不會呼叫A 的onStop()方法。

**異常狀態下的Activity生命週期 **

資源相關的系統配置發生改變或者資源不足:例如螢幕旋轉,當前Activity會銷燬,並且在onStop之前回撥onSaveInstanceState儲存資料,在重新建立Activity的時候在onStart之後回撥onRestoreInstanceState。其中Bundle資料會傳到onCreate(不一定有資料)和onRestoreInstanceState(一定有資料)。 防止螢幕旋轉的時候重建,在清單檔案中新增配置: android:configChanges="orientation"。螢幕旋轉的時候會回撥onConfigurationChanged方法。

Activity的啟動模式** 1、standard:每次啟用Activity時(startActivity),都建立Activity例項,並放入任務棧; 2、singleTop:如果某個Activity自己啟用自己,即任務棧棧頂就是該Activity,則不需要建立,其餘情況都要建立Activity例項; 3、singleTask:如果要啟用的那個Activity在任務棧中存在該例項,則不需要建立,只需要把此Activity放入棧頂,即把該Activity以上的Activity例項都pop,並呼叫其onNewIntent;但是getIntent方法返回的還是舊的Intent。 4、singleInstance:啟用新的任務棧建立Activity例項,如果應用2也要啟用Activity,則不需要建立,兩應用共享該Activity例項。

32**、Service相關,Service與Activity之間的互動-利用程式間通訊的方式 **

Service執行所在的程式**:不配置的情況下預設在當前app程式中的主執行緒中執行,因此不能執行耗時操作。

Service的兩種啟動方式 **

Activity 通過bindService(Intent service, ServiceConnection conn, int flags)跟Service 進行繫結,當繫結成功的時候Service 會將代理物件通過回撥的形式傳給conn,這樣我們就拿到了Service 提供的服務代理物件。在Activity 中可以通過startService 和bindService 方法啟動Service。一般情況下如果想獲取Service 的服務物件那麼肯定需要通過bindService()方法,比如音樂播放器,第三方支付等。如果僅僅只是為了開啟一個後臺任務那麼可以使用startService()方法。

**非繫結模式:**當第一次呼叫startService 的時候執行的方法依次為onCreate()、onStartCommand(),(onStart())。當Service 關閉的時候呼叫onDestory 方法。

**繫結模式:**第一次bindService()的時候,執行的方法為onCreate()、onBind()解除繫結的時候會執行onUnbind()、onDestory()。

**注意 **

1、Service 例項只會有一個,也就是說如果當前要啟動的Service 已經存在了那麼就不會再次建立該Service 當然也不會呼叫onCreate()方法。

2、一個Service 可以被多個客戶進行繫結,只有所有的繫結物件都執行了onBind()方法後該Service 才會銷燬,不過如果在混合模式下,有一個客戶執行了onStart()方法,那麼這個時候如果所有的bind 客戶都執行了unBind()該Service 也不會銷燬。

**IntentService **

Service 本身存在兩個問題:

1、Service 不會專門啟動一條單獨的程式,Service 與它所在應用位於同一個程式中;

2、Service 也不是專門一條新執行緒,因此不應該在Service 中直接處理耗時的任務;

IntentService的優點: **

會建立獨立的worker 執行緒來處理所有的Intent 請求;

會建立獨立的worker 執行緒來處理onHandleIntent()方法實現的程式碼,無需處理多執行緒問題;

所有請求處理完成後,IntentService 會自動停止,無需呼叫stopSelf()方法停止Service;

為Service 的onBind()提供預設實現,返回null;

為Service 的onStartCommand 提供預設實現,將請求Intent 新增到佇列中;

IntentService的原理: **

IntentService在內部其實是通過執行緒以及Handler實現的,當有新的Intent到來的時候,會在onCreate中建立執行緒,Looper以及Handler。在onStart中通過Handler通知子執行緒去回撥onHandleIntent方法去處理這個Intent,處理完畢以後就通過stopSelf方法銷燬自身。因此使用IntentService能夠節省系統資源。

**如何讓Service成為前置程式? **

在onStartCommand中發一個Notification通知。

**Service **的onStartCommand 方法有幾種返回值?各代表什麼意思? **

有四種返回值,不同值代表的意思如下:

1、START_STICKY:如果service程式被kill掉,保留service 的狀態為開始狀態,但不保留遞送的intent物件。隨後系統會嘗試重新建立service,由於服務狀態為開始狀態,所以建立服務後一定會呼叫onStartCommand方法。如果在此期間沒有任何啟動命令被傳遞到service,那麼引數Intent 將為null。

2、START_NOT_STICKY:“非粘性的”。使用這個返回值時,如果在執行完onStartCommand後,服務被異常kill掉,系統不會自動重啟該服務。

3、START_REDELIVER_INTENT:重傳Intent。使用這個返回值時,如果在執行完onStartCommand後,服務被異常kill 掉,系統會自動重啟該服務,並將Intent 的值傳入。

4、START_STICKY_COMPATIBILITY:START_STICKY 的相容版本,但不保證服務被kill 後一定能重啟。

**Service **的onRebind(Intent)方法在什麼情況下會執行? **

如果在onUnbind()方法返回true 的情況下會執行,否則不執行。

33**、廣播 **

**內部通訊實現機制:**通過Android 系統的Binder 機制實現通訊。

**廣播的兩種分類: **

無序廣播:完全非同步,邏輯上可以被任何廣播接收者接收到。優點是效率較高。缺點是一個接收者不能將處理結

果傳遞給下一個接收者,並無法終止廣播intent 的傳播。(優先順序對無序廣播也會生效)

有序廣播:按照被接收者的優先順序順序,在被接收者中依次傳播。每個接收者有權終止廣播,但是如果設定了最終接收者除外。如果傳播過程中沒有廣播被終止,最終接收者會回撥兩次onReceive,第一次是按照正常順序觸發的,第二次是最終接受觸發。

**判斷廣播型別:**在onReceive方法中通過isOrderedBroadcast()方法

**註冊:**廣播接收者可以在清單檔案中設定,也可以在程式碼中設定,但是要注意登出,否則會引發記憶體洩漏。

**動態註冊的優先順序是通過註冊先後來確定的,先註冊的接收者優先順序高。 **

**廣播的生命週期 **

BroadCastReceiver 的生命週期

1、廣播接收者的生命週期非常短暫的,在接收到廣播的時候建立,onReceive()方法結束之後銷燬;

2、廣播接收者中不要做一些耗時的工作,否則會彈出Application No Response 錯誤對話方塊;(不能超過10秒)

3、最好也不要在廣播接收者中建立子執行緒做耗時的工作,因為廣播接收者被銷燬後程式就成為了空程式,很容易

被系統殺掉;最好新開一個Service**來實現;

**如何讓廣播在指定app中才能接收?即廣播自定義許可權 **

1、在清單檔案中通過permission標籤定義自定義許可權,然後uses-permission宣告這個許可權

2、在指定app中也同樣做以上操作,定義廣播接收者時候也要新增permission屬性。

34**、ContentProvider相關 **

**簡要介紹ContentProvider如何實現了應用程式之間的資料共享? **

1、APP如果需要把資料共享出去,先要自定義ContentProvider,實現CURD方法,在清單檔案中註冊。

2、第三方APP就可以通過ContentResolver進行資料的操作。

3、使用者可以通過註冊ContentObserver對資料提供者的資料變化進行監聽,例如監聽簡訊資料庫來實現簡訊驗證碼自動填寫。

35**、SurfaceView與View的區別 **

別:surfaceView是在一個新起的單獨執行緒中可以重新繪製畫面,而View必須在UI的主執行緒中更新畫面。那麼在UI的主執行緒中更新畫面 可能會引發問題,比如你更新畫面的時間過長,那麼你的主UI執行緒會被你正在畫的函式阻塞。那麼將無法響應按鍵,觸屏等訊息。當使用surfaceView 由於是在新的執行緒中更新畫面所以不會阻塞你的UI主執行緒。但這也帶來了另外一個問題,就是事件同步。比如你觸屏了一下,你需要surfaceView中 thread處理,一般就需要有一個event queue的設計來儲存touch event,這會稍稍複雜一點,因為涉及到執行緒同步。

**所以基於以上,根據遊戲特點,一般分成兩類。 **

1 被動更新畫面的。比如棋類,這種用view就好了。因為畫面的更新是依賴於onTouch 來更新,可以直接使用 invalidate。 因為這種情況下,這一次Touch和下一次的Touch需要的時間比較長些,不會產生影響。

2 主動更新。比如一個人在一直跑動。這就需要一個單獨的thread不停的重繪人的狀態,避免阻塞main UI thread。所以顯然view不合適,需要surfaceView來控制。

Scroller的原理

public classMyView extendsView {

private Context mContex

Scroller mScroller =****newScroller**(mContext);**

private void smoothScrollTo**(intdestX,intdestY)****{**

int scrollX = getScrollX**();**

//計算滑動距離,startScroll儲存引數

int delta = destX - scrollX**;**

mScroller**.startScroll(scrollX,0,destX,0);**

}

@Override

public void computeScroll**()****{**

if **(mScroller.computeScrollOffset())****{// **

//滑動並且重新整理

scrollTo**(mScroller.getCurrX(),mScroller.getCurrY());**

postInvalidate**();**

}

}

}** **

** **

**Scroller****執行流程裡面的三個核心方法以及滑動的原理: **

mScroller.startScroll()

mScroller.computeScrollOffset()

view.computeScroll()

1、在mScroller.startScroll()中為滑動做了一些初始化準備。

比如:起始座標,滑動的距離和方向以及持續時間(有預設值),動畫開始時間等

2、mScroller.computeScrollOffset()方法主要是根據當前已經消逝的時間來計算當前的座標點。

因為在mScroller.startScroll()中設定了動畫時間,那麼在computeScrollOffset()方法中依據已經消逝的時間就很容易得到當前時刻應該所處的位置並將其儲存在變數mCurrX和mCurrY中。除此之外該方法還可判斷動畫是否已經結束。

3、postInvalidate方法會導致View的重繪,重繪的時候又會回撥computeScroll方法去進行View的滑動,如此往復。

36**、工具相關 **

**請介紹下adb、ddms、aapt 的作用 **

**adb **Android Debug Bridge ,Android除錯橋的意思。一個命令列工具,Android的主要除錯工具。

ddms Dalvik Debug Monitor Service,dalvik 除錯監視服務。ddms 是一個在adb 基礎上的一個圖形化工具。ddms是程式執行的檢視器,可以查執行緒和堆疊資訊。而traceView是ddms中的一部分,用於程式效能分析。

aapt 即Android Asset Packaging Tool,在SDK 的build-tools 目錄下。該工具可以檢視,建立,更新ZIP格式的文件附件(zip, jar, apk)。也可將資原始檔編譯成二進位制檔案,儘管我們沒有直接使用過該工具,但是開發工具會使用這個工具打包apk 檔案構成一個Android 應用程式。

37**、ListView等列表控制元件 **

**優化問題: **

1、使用ViewHolder模式,建立靜態ViewHolder類,複用ConverView   2、使用分頁載入     3、使用弱引用去引用一些控制元件。因為控制元件上有Context物件,這樣做防止了記憶體洩漏。

**ViewHolder ****為什麼要宣告為靜態類? **

非靜態內部類擁有外部類物件的強引用,因此為了避免對外部類(外部類很可能是Activity)物件的引用,那麼最

好將內部類宣告為static 的。

使用Handler的時候:自定義的Handler內部類應該宣告為static,並且使用弱引用去引用Context等,防止Context不能正常銷燬而導致記憶體洩漏。

ListView****中的設計模式**:adapter模式、觀察者模式、享元模式(ItemView的複用)

ScrollView****中巢狀ListView問題: **

問題:**例如在滑動頁面中巢狀一個顯示物流資訊的ListView,這樣會導致ListView顯示不全,只顯示一個條目。

解決辦法:在ScrollView裡面加一層LinearLayout,通過程式碼動態設定ListView的高度。

38****、視屏播放 **

1、MediaPlayer   2、VideoView(內部還是使用了MediaPlayer)  3、第三方開源萬能播放器VitamioPlayer

39****、Intent **

Intent ****傳遞資料時,可以傳遞哪些型別資料? **

Intent 可以傳遞的資料型別非常的豐富,java 的基本資料型別和String 以及他們的陣列形式都可以,除此之

外還可以傳遞實現了Serializable 和Parcelable 介面的物件。

Serializable ****(Java)和Parcelable (Android)的區別 **

1.在使用記憶體的時候,Parcelable 類比Serializable 效能高,所以推薦使用Parcelable 類。

2.Serializable 在序列化的時候會產生大量的臨時變數,從而引起頻繁的GC。

3.Parcelable 不能使用在要將資料儲存在磁碟上的情況。儘管Serializable 效率低點,但在這種情況下,還是建議用Serializable 。

實現:

1 Serializable 的實現,只需要繼承Serializable ,指定序列化ID即可。這只是給物件打了一個標記,系統會自動將其序列化。

2 Parcelabel 的實現,需要在類中新增一個靜態成員變數CREATOR,這個變數需要繼承Parcelable.Creator 介面。

40****、Fragment相關**

FragmentManager****的add方法與replace方法的異同: **

1、add 的時候是把所有的Fragment 一層一層的疊加到了FrameLayout 上

2、replace 的話首先將該容器中的其他Fragment 去除掉然後將當前Fragment 新增到容器中,因此使用replace方法的時候要注意會觸發onDestroyView。**

3、一般思路是先add進來,然後通過hide以及show來進行Fragment的切換,此時Fragment的生命週期沒有變化**。

Fragment****實現Activity壓棧和出棧的效果**:通過addToBackStack方法實現,內部維護了一個雙向連結串列。

Activity和Fragment之間你是怎麼傳值的? **

  1. 通過findFragmentByTag或者getActivity獲得對方的引用(強轉)之後,再相互呼叫對方的public方法,但是這樣做一是引入了“強轉”的醜陋程式碼,另外兩個類之間各自持有對方的強引用,耦合較大,容易造成記憶體洩漏。
  2. 通過Bundle的方法進行傳值,並且在建立Fragment的時候通過setArguments方法把Bundle設定進去。
  3. 利用eventbus進行通訊,這種方法實時性高,而且Activity與Fragment之間可以完全解耦。

41****、Android中的動畫 **

動畫分類:幀動畫,補間動畫,屬性動畫(實際View的移動,點選事件會跟隨)

如何為Activity或者Fragment新增動畫? **

1、自定義主題,複寫相應的屬性,如下圖所示   2、在finish或者startActivity之後呼叫overridePendingTransition

42****、簽名、多渠道打包,上線流程 **

簽名簡介:**在Android 系統中,所有安裝到系統的應用程式都必有一個數字證照,此數字證照用於標識應用程式的作者和在 **

應用程式之間建立信任關係。Android 系統要求每一個安裝進系統的應用程式都是經過數字證照籤名的。

簽名好處:**(1)有利於程式升級,當新版程式和舊版程式的數字證照相同時,Android 系統才會認為這兩個程式是同一個程式

的不同版本。如果新版程式和舊版程式的數字證照不相同,則Android 系統認為他們是不同的程式,併產生衝突,會

要求新程式更改包名。

(2)有利於程式的模組化設計和開發。Android 系統允許擁有同一個數字簽名的程式執行在一個程式中,Android程式會將他們視為同一個程式。所以開發者可以將自己的程式分模組開發,而使用者只需要在需要的時候下載適當的模組。

在簽名時,需要考慮數字證照的有效期: **

(1)數字證照的有效期要包含程式的預計生命週期,一旦數字證照失效,持有改數字證照的程式將不能正常升級。

(2)如果多個程式使用同一個數字證照,則該數字證照的有效期要包含所有程式的預計生命週期。

(3)Android Market 強制要求所有應用程式數字證照的有效期要持續到2033 年10 月22 日以後。

相關文章