您的位置:首頁>正文

Android拿高薪面試題必看

外掛程式化、熱修復 、熱更新的理解

外掛程式化 – apk 分為宿主和外掛程式部分, 外掛程式在需要的時候才載入進來

熱修復 – 更新的類或者外掛程式細微性較小的時候, 我們會稱之為熱修復, 一般用於修復bug

熱更新 – 2016 Google 的 Android Studio 推出了Instant Run 功能 同時提出了3個名詞

“冷部署” – app需要重啟, 比如繼承關係的改變或方法的簽名變化等。

“ 熱部署” – 方法內的簡單修改, 無需重啟app和Activity。

“暖部署” – app無需重啟, 但是activity需要重啟, 比如資源的修改。

站在app開發者角度的“熱”是指在不發版的情況來實現更新

而Google提出的“熱”是指值是否需要重新開機。 - 同時在開發外掛程式化的時候也有兩種情景

一種是外掛程式與宿主apk沒有交互, 只是在用戶使用到的時候進行一次吊起

還有一種是與宿主有很多的交互

你認為android熱更新框架哪個好:

1.阿裡的熱更新框架已經開源 了。 但已經很久沒有更新過新版本了。 當前的版本只支持到了 Android 4.4。 由於 5.0 起新的 ART 虛擬機器、更嚴格的 SELinux 策略以及對 64 位的支援之類的事, 使得 Xposed 都在開發上做了很多調整。 我不知道 Dexposed 現在是否支持, 但至少阿裡沒有開源。

2.在本地動態執行遠端下發的代碼是極度危險的行為。 利用此方法執行非法代碼等或用於繞過 Google Play 等市場的審查是違反相關協議的, 也是對使用者極度不負責任的行為。

3.在一些訪問非常密集的地方使用熱更新可能會對效率產生相對比較大的影響,

應該避免使用.

4.我們可以對 Java 的 ScriptEngine 進行一些封裝成為一個 HotPatch 類使得它更適合做熱更新的工作。

5.首先,檢查熱更新補丁的管道一定要建立在 https 上, 因為下發代碼是極其危險的, 如果被劫持, 後果是無法想像的。 其次,請求時最好自動帶上 Android 版本、手機型號、地區、版本號等資訊, 以方便更精確地下發, 千萬不能下發錯。

6.Java在運行時載入對應的類是通過ClassLoader來實現的, ClassLoader本身是一個抽象來, Android中使用PathClassLoader類作為Android的默認的類載入器

7.我們的如果想做hotpatch, 一定要保證我們的hotpacth dex檔出現在dexElements列表的前面。

二.常用的熱更新技術框架:

基於QQ空間的HotFix →→ 要使用到android dex分包方案→拆分dex的專案的話, 可以參考一下穀歌的multidex方案實現.

大眾點評的NuWa←項目補丁自動化做的很完整

alibaba/AndFix

阿裡巴巴的DexPosed

dalvik_patch實現multidex

使用React-Native實現app熱部署的一次實踐

alibaba/AndFix

基礎

activity生命週期圖解

Markdown

注意:

鎖定屏與解鎖螢幕 只會調用onPause(), 而不會調用onStop方法, 開屏後則調用onResume()。 在實際操作中會有所出入, 比如在三星手機測試的時候鎖定手機調用了onPause()和onStop()方法,

解鎖時候調用的是:onRestart(), onStart()和 onResume()方法。

介紹不同場景下Activity生命週期的變化過程

啟動Activity:

onCreate()—>onStart()—>onResume(), Activity進入運行狀態。

Activity退居後臺:

當前Activity轉到新的Activity介面或按Home鍵回到主屏: onPause()—>onStop(), 進入停滯狀態。

Activity返回前臺:

onRestart()—>onStart()—>onResume(), 再次回到運行狀態。

Activity退居後臺, 且系統記憶體不足,

系統會殺死這個後臺狀態的Activity, 若再次回到這個Activity,則會走onCreate()–>onStart()—>onResume()

鎖定屏與解鎖螢幕

只會調用onPause(), 而不會調用onStop方法, 開屏後則調用onResume()

Activity銷毀但Task如果沒有銷毀掉, 當Activity重啟時這個AsyncTask該如何解決?

比如螢幕旋轉這個例子, 在重建Activity的時候, 會回檔

Activity.onRetainNonConfigurationInstance()

重新傳遞一個新的物件給AsyncTask, 完成引用的更新

若Activity已經銷毀,此時AsynTask執行完並返回結果,會報異常麼?

當一個App旋轉時, 整個Activity會被銷毀和重建。

當Activity重啟時, AsyncTask中對該Activity的引用是無效的, 因此onPostExecute()就不會起作用

若AsynTask正在執行,

折會報 view not attached to window manager 異常

同樣也是生命週期的問題, 在 Activity 的onDestory()方法中調用Asyntask.cancal方法, 讓二者的生命週期同步

記憶體不足時,系統會殺死後臺的Activity,如果需要進行一些臨時狀態的保存,在哪個方法進行

Activity的 onSaveInstanceState() 和 onRestoreInstanceState()並不是生命週期方法,不同於 onCreate()、onPause()等生命週期方法, 它們並不一定會被觸發。

當應用遇到意外情況(如:記憶體不足、使用者直接按Home鍵)由系統銷毀一個Activity, onSaveInstanceState() 會被調用。

但是當用戶主動去銷毀一個Activity時, 例如在應用中按返回鍵, onSaveInstanceState()就不會被調用。 除非該activity是被用戶主動銷毀的

通常onSaveInstanceState()只適合用於保存一些臨時性的狀態, 而onPause()適合用於資料的持久化保存。

介紹Activity 四中launchMode:

我們可以在AndroidManifest.xml配置的android:launchMode屬性為以下四種之一。

1、standard

standard模式是預設的啟動模式, 不用為配置android:launchMode屬性即可, 當然也可以指定值為standard。 standard啟動模式,不管有沒有已存在的實例,都生成新的實例。

2、 singleTop

我們在上面的基礎上為指定屬性android:launchMode=”singleTop”,系統就會按照singleTop啟動模式處理跳轉行為。跳轉時系統會先在棧結構中尋找是否有一個Activity實例正位於棧頂,如果有則不再生成新的,而是直接使用。如果系統發現存在有Activity實例,但不是位於棧頂,重新生成一個實例。 這就是singleTop啟動模式,如果發現有對應的Activity實例正位於棧頂,則重複利用,不再生成新的實例。

3、 singleTask

如果發現有對應的Activity實例,則使此Activity實例之上的其他Activity實例統統出棧,使此Activity實例成為棧頂物件,顯示到幕前。

4、singleInstance

這種啟動模式比較特殊,因為它會啟用一個新的棧結構,將Acitvity放置於這個新的棧結構中,並保證不再有其他Activity實例進入。

LaunchMode使用場景

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

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

singleTask適合作為程式入口點。

例如流覽器的主介面。不管從多少個應用啟動流覽器,只會啟動主介面一次,其餘情況都會走onNewIntent,並且會清空主介面上面的其他頁面。

singleInstance應用場景:

鬧鈴的響鈴介面。 你以前設置了一個鬧鈴:上午6點。在上午5點58分,你啟動了鬧鈴設置介面,並按 Home 鍵回桌面;在上午5點59分時,你在微信和朋友聊天;在6點時,鬧鈴響了,並且彈出了一個對話方塊形式的 Activity(名為 AlarmAlertActivity) 提示你到6點了(這個 Activity 就是以

SingleInstance

載入模式打開的),你按返回鍵,回到的是微信的聊天介面,這是因為 AlarmAlertActivity 所在的 Task 的棧只有他一個元素, 因此退出之後這個 Task 的棧空了。如果是以 SingleTask 打開 AlarmAlertActivity,那麼當鬧鈴響了的時候,按返回鍵應該進入鬧鈴設置介面。

如何把一個應用設置為系統應用

Android設置是Debug版本,且root,直接將該apk用adb工具push到system/app或system/priv-app

如果是非root設備,需要編譯後燒寫鏡像

有些許可權(如WRITE_SECURE_SETTINGS)不開放給協力廠商應用,只能在對應設備源碼總編譯然後作為系統app使用

Activity,Window,View三者的聯繫和區別?

Activity像一個工匠(控制單元)

Window像窗戶(承載模型)

View像窗花(顯示視圖)

LayoutInflater像剪刀

Xml配置像窗花圖紙。

Activity啟動Service的兩種方式

startService:生命週期和調用者不同.啟動後若調用者未調用stopService而直接退出,Service仍會運行

bindService:生命週期與調用者綁定,調用者一旦退出,Service就會調用unBind->onDestory

Android兩個應用能在同一個任務棧嗎?

棧一般以包名命名,兩個應用的簽名和udid要相同

Fragment是什麼?你曾經遇到哪些有關Fragment的問題?

Fragment可以作為Activity介面的一部分組成出現

其作用是:

磁碟重組,局部刷新。

一個Activity中可以同時出現多個Fragment,並一個Fragment也可以在多個Activity中使用.

在Activity中可以添加,刪除,替換Fragment.Fragment可以回應自己的輸入時間,並且有自己的生命週期,但其生命週期收Activity影響.

Fragment生命週期

Markdown

如何實現Activity視窗快速變暗

利用唯讀屬性動畫+WindowManager

/*

是否使用過本地廣播,和全域廣播有什麼區別?

本地廣播在本應用範圍內傳播,不用擔心隱私資料洩露,不用擔心別的應用偽造廣播.相比全域廣播,本地廣播更高效.

註冊廣播的幾種方法?

1.靜態註冊:在清單檔中註冊, 常見的有監聽設備啟動,常駐註冊不會隨程式生命週期改變

2.動態註冊:在代碼中註冊,隨著程式的結束,也就停止接受廣播了

補充一點:有些廣播只能通過動態方式註冊,比如時間變化事件、螢幕亮滅事件、電量變更事件,因為這些事件觸發頻率通常很高,如果允許後臺監聽,會導致進程頻繁創建和銷毀,從而影響系統整體性能

為什麼Android引入廣播機制?

a:從MVC的角度考慮(應用程式內) 其實回答這個問題的時候還可以這樣問,android為什麼要有那4大元件,現在的移動開發模型基本上也是照搬的web那一套MVC架構,只不過是改了點嫁妝而已。

它們之間有時候是一種相互依存的關係,有時候又是一種補充關係,引入廣播機制可以方便幾大元件的資訊和資料交互。

android的四大組件本質上就是為了實現移動或者說嵌入式設備上的MVC架構

b:程式間互通消息(例如在自己的應用程式內監聽系統來電)

c:效率上(參考UDP的廣播協定在局域網的方便性)

d:設計模式上(反轉控制的一種應用,類似監聽者模式)

瞭解IntentServices嗎?

IntentService是Service的子類,是一個非同步的,會自動停止的服務,很好解決了傳統的Service中處理完耗時操作忘記停止並銷毀Service的問題

生成一個默認的且與執行緒相互獨立的工作執行緒執行所有發送到onStartCommand()方法的Intent,可以在onHandleIntent()中處理.

串列佇列,每次只運行一個任務,不存在執行緒安全問題,所有任務執行完後自動停止服務,不需要自己手動調用stopSelf()來停止.

如何提升Service進程優先順序

在AndroidManifest.xml檔中對於intent-filter可以通過android:priority = “1000”這個屬性設置最高優先順序,1000是最高值,如果數字越小則優先順序越低,同時適用於廣播。

ContentProvider和sql的區別

ContentProvider的主要還是用於資料共用,其可以對Sqlite,SharePreferences,File等進行資料操作用來共用資料。而sql的可以理解為資料庫的一門語言,可以使用它完成CRUD等一系列的操作

資料存儲相關

檔存儲:

通過Java.io.FileInputStream和java.io.FileOutputStream這兩個類來實現對檔的讀寫,java.io.File類則用來構造一個具體指向某個檔或者資料夾的物件。

SharedPreferences:

SharedPreferences是一種羽量級的資料存儲機制,他將一些簡單的資料類型的資料,包括boolean類型,int類型,float類型,long類型以及String類型的資料,以鍵值對的形式存儲在應用程式的私有Preferences目錄(/data/data/<包名>/shared_prefs/)中,這種Preferences機制廣泛應用于存儲應用程式中的配置資訊。

SQLite資料庫:

當應用程式需要處理的資料量比較大時,為了更加合理地存儲、管理、查詢資料,我們往往使用關聯式資料庫來存儲資料。Android系統的很多使用者資料,如連絡人資訊,通話記錄,短資訊等,都是存儲在SQLite資料庫當中的,所以利用操作SQLite資料庫的API可以同樣方便的訪問和修改這些資料。

ContentProvider:

主要用於在不同的應用程式之間實現資料共用的功能,不同於sharepreference和檔存儲中的兩種全域可讀寫操作模式,內容提供其可以選擇只對哪一部分資料進行共用,從而保證我們程式中的隱私資料不會有洩漏的風險

如何將打開res aw目錄中的資料庫檔?

在Android中不能直接打開res aw目錄中的資料庫檔,而需要在程式第一次啟動時將該檔複製到手機記憶體或SD卡的某個目錄中,然後再打開該資料庫檔。

複製的基本方法是使用getResources().openRawResource方法獲得res aw目錄中資源的 InputStream物件,然後將該InputStream物件中的資料寫入其他的目錄中相應檔中。

在Android SDK中可以使用SQLiteDatabase.openOrCreateDatabase方法來打開任意目錄中的SQLite資料庫檔。

什麼是aar?aar是jar有什麼區別?

“aar”包是 Android 的類庫專案的二進位發行包。

文件副檔名是.aar,maven 專案類型應該也是aar,但檔本身是帶有以下各項的 zip 檔:

/AndroidManifest.xml (mandatory)

/classes.jar (mandatory)

/res/ (mandatory)

/R.txt (mandatory)

/assets/ (optional)

/libs/*.jar (optional)

/jni//*.so (optional)

/proguard.txt (optional)

/lint.jar (optional)

這些條目是直接位於 zip 檔根目錄的。 其中R.txt 檔是aapt帶參數–output-text-symbols的輸出結果。

jar打包不能包含資源檔,比如一些drawable檔、xml資源檔之類的,aar可以。

SQLite支援事務嗎?添加刪除如何提高性能?

SQLite作為羽量級的資料庫,比MySQL還小,但支持SQL語句查詢,提高性能可以考慮通過原始經過優化的SQL查詢語句方式處理

如何將SQLite資料庫(dictionary.db檔)與apk檔一起發佈?

可以將dictionary.db檔複製到Eclipse Android工程中的res aw目錄中。所有在res aw目錄中的檔不會被壓縮,這樣可以直接提取該目錄中的檔。可以將dictionary.db檔複製到res aw目錄中

如何保證Service在後臺不被kill

Service設置成START_STICKY kill 後會被重啟(等待5秒左右),重傳Intent,保持與重啟前一樣

通過 startForeground將進程設置為前臺進程, 做前臺服務,優先順序和前臺應用一個級別,除非在系統記憶體非常缺,否則此進程不會被 kill

雙進程Service: 讓2個進程互相保護**,其中一個Service被清理後,另外沒被清理的進程可以立即重啟進程

QQ黑科技: 在應用退到後臺後,另起一個只有 1 圖元的頁面停留在桌面上,讓自己保持前臺狀態,保護自己不被後臺清理工具殺死

在已經root的設備下,修改相應的許可權檔,將App偽裝成系統級的應用 Android4.0系列的一個漏洞,已經確認可行

用C編寫守護進程(即子進程) : Android系統中當前進程(Process)fork出來的子進程,被系統認為是兩個不同的進程。當父進程被殺死的時候,子進程仍然可以存活,並不受影響。*鑒於目前提到的在Android->- Service層做雙守護都會失敗*,我們可以fork出c進程,多進程守護。閉環在那檢查是否還存在,具體的思路如下(Android5.0以上的版本不可行)

用C編寫守護進程(即子進程),守護進程做的事情就是迴圈檢查目標進程是否存在,不存在則啟動它。

在NDK環境中將1中編寫的C代碼編譯打包成可執行檔(BUILD_EXECUTABLE)。主進程啟動時將守護進程放入私有目錄下,賦予可執行許可權,啟動它即可。

聯繫廠商,加入白名單

Android中如何獲得手機的唯一標示.

1 首先嘗試讀取IMEI、Mac位址、CPU號等物理資訊(有不少工具可以修改IMEI);

2 如果均失敗,可以自己生成UUID然後保存到檔(檔也可能被篡改或刪除)

參考:[blog.csdn.net/xushuaic/ar…]

mipmap資料夾和drawable資料夾的區別

它只是用來放啟動圖示的,好處就是,你只用放一個mipmap圖示,它就會給你各種版本(比如平板,手機)的apk自動生成相應解析度的圖示,以節約空間。

ListView卡頓的原因以及優化策略

重用converView: 通過複用converview來減少不必要的view的創建,另外Infalte操作會把xml檔產生實體成相應的View實例,屬於IO操作,是耗時操作。

減少findViewById()操作: 將xml檔中的元素封裝成viewholder靜態類,通過converview的setTag和getTag方法將view與相應的holder物件綁定在一起,避免不必要的findviewbyid操作

避免在 getView 方法中做耗時的操作: 例如載入本地 Image 需要載入記憶體以及解析 Bitmap ,都是比較耗時的操作,如果用戶快速滑動listview,會因為getview邏輯過於複雜耗時而造成滑動卡頓現象。使用者滑動時候不要載入圖片,待滑動完成再載入,可以使用這個協力廠商庫glide

Item的佈局層次結構儘量簡單,避免佈局太深或者不必要的重繪

儘量能保證 Adapter 的 hasStableIds() 返回 true 這樣在 notifyDataSetChanged() 的時候,如果item內容並沒有變化,ListView 將不會重新繪製這個 View,達到優化的目的

在一些場景中,ScollView內會包含多個ListView,可以把listview的高度寫死固定下來。 由於ScollView在快速滑動過程中需要大量計算每一個listview的高度,阻塞了UI執行緒導致卡頓現象出現,如果我們每一個item的高度都是均勻的,可以通過計算把listview的高度確定下來,避免卡頓現象出現

使用 RecycleView 代替listview: 每個item內容的變動,listview都需要去調用notifyDataSetChanged來更新全部的item,太浪費性能了。RecycleView可以實現當 個item的局部刷新,並且引入了增加和刪除的動態效果,在性能上和定制上都有很大的改善

ListView 中元素避免半透明: 半透明繪製需要大量乘法計算,在滑動時不停重繪會造成大量的計算,在比較差的機子上會比較卡。 在設計上能不半透明就不不半透明。實在要弄就把在滑動的時候把半透明設置成不透明,滑動完再重新設置成半透明。

儘量開啟硬體加速: 硬體加速提升巨大,避免使用一些不支援的函數導致含淚關閉某個地方的硬體加速。當然這一條不只是對 ListView。

ViewHolder為什麼要被聲明成靜態內部類

這個是考靜態內部類和非靜態內部類的主要區別之一。非靜態內部類會隱式持有外部類的引用,就像大家經常將自訂的adapter在Activity類裡,然後在adapter類裡面是可以隨意調用外部activity的方法的。

當你將內部類定義為static時,你就調用不了外部類的實例方法了,因為這時候靜態內部類是不持有外部類的引用的。聲明ViewHolder靜態內部類,可以將ViewHolder和外部類解引用。

大家會說一般ViewHolder都很簡單,不定義為static也沒事吧。確實如此,但是如果你將它定義為static的,說明你懂這些含義。萬一有一天你在這個ViewHolder加入一些複雜邏輯,做了一些耗時工作,那麼如果ViewHolder是非靜態內部類的話,就很容易出現記憶體洩露。

如果是靜態的話,你就不能直接引用外部類,迫使你關注如何避免相互引用。 所以將 ViewHolder內部類 定義為靜態的,是一種好習慣

動畫相關

Android中的動畫有哪些?

逐幀動畫(Drawable Animation):

載入一系列Drawable資源來創建動畫,簡單來說就是播放一系列的圖片來實現動畫效果,可以自訂每張圖片的持續時間

補間動畫(Tween Animation):

Tween可以對View物件實現一系列簡單的動畫效果,比如位移,縮放,旋轉,透明度等等。但是它並不會改變View屬性的值,只是改變了View的繪製的位置,比如,一個按鈕在動畫過後,不在原來的位置,但是觸發點擊事件的仍然是原來的座標。

屬性動畫(Property Animation):

動畫的物件除了傳統的View物件,還可以是Object物件,動畫結束後,Object物件的屬性值被實實在在的改變了

Android動畫原理

Animation框架定義了透明度,旋轉,縮放和位移幾種常見的動畫,而且控制的是整個View

實現原理是每次繪製視圖時View所在的ViewGroup中的drawChild函數獲取該View的Animation的Transformation值

然後調用canvas.concat(transformToApply.getMatrix()),通過矩陣運算完成動畫幀,如果動畫沒有完成,繼續調用invalidate()函數,啟動下次繪製來驅動動畫

動畫過程中的幀之間間隙時間是繪製函數所消耗的時間,可能會導致動畫消耗比較多的CPU資源,最重要的是,動畫改變的只是顯示,並不能相應事件

View繪製相關

SurfaceView和View的區別

SurfaceView中採用了雙緩存技術,在單獨的執行緒中更新介面

View在UI執行緒中更新介面

介紹下自訂view的基本流程

1、 明確需求,確定你想實現的效果

2、確定是使用群組控制項的形式還是全新自訂的形式,群組控制項即使用多個系統控制項來合成一個新控制項,你比如titilebar,這種形式相對簡單,參考

3、如果是完全自訂一個view的話,你首先需要考慮繼承哪個類,是View呢,還是ImageView等子類。

4、根據需要去複寫View#onDraw、View#onMeasure、View#onLayout方法

5.根據需要去複寫dispatchTouchEvent、onTouchEvent方法

6、根據需要為你的自訂view提供自訂屬性,即編寫attr.xml,然後在代碼中通過TypedArray等類獲取到自訂屬性值

7、需要處理滑動衝突、圖元轉換等問題

談談View的繪製流程

談談View的繪製流程

Markdown

measure()方法,layout(),draw()三個方法主要存放了一些識別字,來判斷每個View是否需要再重新測量,佈局或者繪製,主要的繪製過程還是在onMeasure,onLayout,onDraw這個三個方法中

1.onMesarue() 為整個View樹計算實際的大小,即設置實際的高(對應屬性:mMeasuredHeight)和寬(對應屬性: mMeasureWidth),每個View的控制項的實際寬高都是由父視圖和本身視圖決定的。

2.onLayout() 為將整個根據子視圖的大小以及佈局參數將View樹放到合適的位置上。

3.onDraw() 開始繪製圖像,繪製的流程如下

首先繪製該View的背景

調用onDraw()方法繪製視圖本身 (每個View都需要重載該方法,ViewGroup不需要實現該方法)

如果該View是ViewGroup,調用dispatchDraw ()方法繪製子視圖

繪製捲軸

自訂View執行invalidate()方法,為什麼有時候不會回檔onDraw()

自訂一個view時,重寫onDraw。調用view.invalidate(),會觸發onDraw和computeScroll()。前提是該view被附加在當前窗口.

view.postInvalidate(); //是在非UI執行緒上調用的

自訂一個ViewGroup,重寫onDraw。onDraw可能不會被調用,原因是需要先設置一個背景(顏色或圖)。表示這個group有東西需要繪製了,才會觸發draw,之後是onDraw。因此,一般直接重寫dispatchDraw來繪製viewGroup.自訂一個ViewGroup,dispatchDraw會調用drawChild.

事件傳遞機制

談談touch事件的傳遞流程

Markdown

所有Touch事件都被封裝成了MotionEvent物件,包括Touch的位置、時間、歷史記錄以及第幾個手指(多指觸摸)等。

事件類型分為ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每個事件都是以ACTION_DOWN開始ACTION_UP結束。

對事件的處理包括三類,分別為傳遞——dispatchTouchEvent()函數、攔截——onInterceptTouchEvent()函數、消費——onTouchEvent()函數和OnTouchListener()

簡單來說:

事件從Activity.dispatchTouchEvent()開始傳遞,只要沒有被停止或攔截,從最上層的View(ViewGroup)開始一直往下(子View)傳遞。子View可以通過onTouchEvent()對事件進行處理。

事件由父View(ViewGroup)傳遞給子View,ViewGroup可以通過onInterceptTouchEvent()對事件做攔截,停止其往下傳遞。

如果事件從上往下傳遞過程中一直沒有被停止,且最底層子View沒有消費事件,事件會反嚮往上傳遞,這時父View(ViewGroup)可以進行消費,如果還是沒有被消費的話,最後會到Activity的onTouchEvent()函數。

如果View沒有對ACTION_DOWN進行消費,之後的其他事件不會傳遞過來。

= OnTouchListener優先於onTouchEvent()對事件進行消費。

上面的消費即表示相應函數返回值為true。

View中setOnTouchListener中的onTouch,onTouchEvent,onClick的執行順序

onTouch優於onTouchEvent,onTouchEvent優於onClick

觸摸事件的分發機制詳見:

Android觸摸事件分發機制完全解析《一》

什麼是Dalvik虛擬機器

Dalvik虛擬機器是Android平臺的核心。

它可以支援.dex格式的程式的運行

.dex格式是專為Dalvik設計的一種壓縮格式

可以減少整體檔尺寸

提高I/O操作的速度

適合記憶體和處理器速度有限的系統

Dalvik虛擬機器和JVM有什麼區別

Dalvik 基於寄存器,而 JVM 基於棧。基於寄存器的虛擬機器對於更大的程式來說,在它們編譯的時候,花費的時間更短。

Dalvik執行.dex格式的位元組碼,而JVM執行.class格式的位元組碼

Android為每個應用程式分配的記憶體大小是多少

一般是16m或者24m,但是可以通過android:largeHeap申請更多記憶體

具體參考:

[liuzhichao.com/2016/use-an…]

[www.cnblogs.com/mythou/p/32…]

如何解決方法數65k問題?

使用Android Studio 的gradle 可以構建MutilDex

相信自己,沒有做不到的,只有想不到的

standard啟動模式,不管有沒有已存在的實例,都生成新的實例。

2、 singleTop

我們在上面的基礎上為指定屬性android:launchMode=”singleTop”,系統就會按照singleTop啟動模式處理跳轉行為。跳轉時系統會先在棧結構中尋找是否有一個Activity實例正位於棧頂,如果有則不再生成新的,而是直接使用。如果系統發現存在有Activity實例,但不是位於棧頂,重新生成一個實例。 這就是singleTop啟動模式,如果發現有對應的Activity實例正位於棧頂,則重複利用,不再生成新的實例。

3、 singleTask

如果發現有對應的Activity實例,則使此Activity實例之上的其他Activity實例統統出棧,使此Activity實例成為棧頂物件,顯示到幕前。

4、singleInstance

這種啟動模式比較特殊,因為它會啟用一個新的棧結構,將Acitvity放置於這個新的棧結構中,並保證不再有其他Activity實例進入。

LaunchMode使用場景

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

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

singleTask適合作為程式入口點。

例如流覽器的主介面。不管從多少個應用啟動流覽器,只會啟動主介面一次,其餘情況都會走onNewIntent,並且會清空主介面上面的其他頁面。

singleInstance應用場景:

鬧鈴的響鈴介面。 你以前設置了一個鬧鈴:上午6點。在上午5點58分,你啟動了鬧鈴設置介面,並按 Home 鍵回桌面;在上午5點59分時,你在微信和朋友聊天;在6點時,鬧鈴響了,並且彈出了一個對話方塊形式的 Activity(名為 AlarmAlertActivity) 提示你到6點了(這個 Activity 就是以

SingleInstance

載入模式打開的),你按返回鍵,回到的是微信的聊天介面,這是因為 AlarmAlertActivity 所在的 Task 的棧只有他一個元素, 因此退出之後這個 Task 的棧空了。如果是以 SingleTask 打開 AlarmAlertActivity,那麼當鬧鈴響了的時候,按返回鍵應該進入鬧鈴設置介面。

如何把一個應用設置為系統應用

Android設置是Debug版本,且root,直接將該apk用adb工具push到system/app或system/priv-app

如果是非root設備,需要編譯後燒寫鏡像

有些許可權(如WRITE_SECURE_SETTINGS)不開放給協力廠商應用,只能在對應設備源碼總編譯然後作為系統app使用

Activity,Window,View三者的聯繫和區別?

Activity像一個工匠(控制單元)

Window像窗戶(承載模型)

View像窗花(顯示視圖)

LayoutInflater像剪刀

Xml配置像窗花圖紙。

Activity啟動Service的兩種方式

startService:生命週期和調用者不同.啟動後若調用者未調用stopService而直接退出,Service仍會運行

bindService:生命週期與調用者綁定,調用者一旦退出,Service就會調用unBind->onDestory

Android兩個應用能在同一個任務棧嗎?

棧一般以包名命名,兩個應用的簽名和udid要相同

Fragment是什麼?你曾經遇到哪些有關Fragment的問題?

Fragment可以作為Activity介面的一部分組成出現

其作用是:

磁碟重組,局部刷新。

一個Activity中可以同時出現多個Fragment,並一個Fragment也可以在多個Activity中使用.

在Activity中可以添加,刪除,替換Fragment.Fragment可以回應自己的輸入時間,並且有自己的生命週期,但其生命週期收Activity影響.

Fragment生命週期

Markdown

如何實現Activity視窗快速變暗

利用唯讀屬性動畫+WindowManager

/*

是否使用過本地廣播,和全域廣播有什麼區別?

本地廣播在本應用範圍內傳播,不用擔心隱私資料洩露,不用擔心別的應用偽造廣播.相比全域廣播,本地廣播更高效.

註冊廣播的幾種方法?

1.靜態註冊:在清單檔中註冊, 常見的有監聽設備啟動,常駐註冊不會隨程式生命週期改變

2.動態註冊:在代碼中註冊,隨著程式的結束,也就停止接受廣播了

補充一點:有些廣播只能通過動態方式註冊,比如時間變化事件、螢幕亮滅事件、電量變更事件,因為這些事件觸發頻率通常很高,如果允許後臺監聽,會導致進程頻繁創建和銷毀,從而影響系統整體性能

為什麼Android引入廣播機制?

a:從MVC的角度考慮(應用程式內) 其實回答這個問題的時候還可以這樣問,android為什麼要有那4大元件,現在的移動開發模型基本上也是照搬的web那一套MVC架構,只不過是改了點嫁妝而已。

它們之間有時候是一種相互依存的關係,有時候又是一種補充關係,引入廣播機制可以方便幾大元件的資訊和資料交互。

android的四大組件本質上就是為了實現移動或者說嵌入式設備上的MVC架構

b:程式間互通消息(例如在自己的應用程式內監聽系統來電)

c:效率上(參考UDP的廣播協定在局域網的方便性)

d:設計模式上(反轉控制的一種應用,類似監聽者模式)

瞭解IntentServices嗎?

IntentService是Service的子類,是一個非同步的,會自動停止的服務,很好解決了傳統的Service中處理完耗時操作忘記停止並銷毀Service的問題

生成一個默認的且與執行緒相互獨立的工作執行緒執行所有發送到onStartCommand()方法的Intent,可以在onHandleIntent()中處理.

串列佇列,每次只運行一個任務,不存在執行緒安全問題,所有任務執行完後自動停止服務,不需要自己手動調用stopSelf()來停止.

如何提升Service進程優先順序

在AndroidManifest.xml檔中對於intent-filter可以通過android:priority = “1000”這個屬性設置最高優先順序,1000是最高值,如果數字越小則優先順序越低,同時適用於廣播。

ContentProvider和sql的區別

ContentProvider的主要還是用於資料共用,其可以對Sqlite,SharePreferences,File等進行資料操作用來共用資料。而sql的可以理解為資料庫的一門語言,可以使用它完成CRUD等一系列的操作

資料存儲相關

檔存儲:

通過Java.io.FileInputStream和java.io.FileOutputStream這兩個類來實現對檔的讀寫,java.io.File類則用來構造一個具體指向某個檔或者資料夾的物件。

SharedPreferences:

SharedPreferences是一種羽量級的資料存儲機制,他將一些簡單的資料類型的資料,包括boolean類型,int類型,float類型,long類型以及String類型的資料,以鍵值對的形式存儲在應用程式的私有Preferences目錄(/data/data/<包名>/shared_prefs/)中,這種Preferences機制廣泛應用于存儲應用程式中的配置資訊。

SQLite資料庫:

當應用程式需要處理的資料量比較大時,為了更加合理地存儲、管理、查詢資料,我們往往使用關聯式資料庫來存儲資料。Android系統的很多使用者資料,如連絡人資訊,通話記錄,短資訊等,都是存儲在SQLite資料庫當中的,所以利用操作SQLite資料庫的API可以同樣方便的訪問和修改這些資料。

ContentProvider:

主要用於在不同的應用程式之間實現資料共用的功能,不同於sharepreference和檔存儲中的兩種全域可讀寫操作模式,內容提供其可以選擇只對哪一部分資料進行共用,從而保證我們程式中的隱私資料不會有洩漏的風險

如何將打開res aw目錄中的資料庫檔?

在Android中不能直接打開res aw目錄中的資料庫檔,而需要在程式第一次啟動時將該檔複製到手機記憶體或SD卡的某個目錄中,然後再打開該資料庫檔。

複製的基本方法是使用getResources().openRawResource方法獲得res aw目錄中資源的 InputStream物件,然後將該InputStream物件中的資料寫入其他的目錄中相應檔中。

在Android SDK中可以使用SQLiteDatabase.openOrCreateDatabase方法來打開任意目錄中的SQLite資料庫檔。

什麼是aar?aar是jar有什麼區別?

“aar”包是 Android 的類庫專案的二進位發行包。

文件副檔名是.aar,maven 專案類型應該也是aar,但檔本身是帶有以下各項的 zip 檔:

/AndroidManifest.xml (mandatory)

/classes.jar (mandatory)

/res/ (mandatory)

/R.txt (mandatory)

/assets/ (optional)

/libs/*.jar (optional)

/jni//*.so (optional)

/proguard.txt (optional)

/lint.jar (optional)

這些條目是直接位於 zip 檔根目錄的。 其中R.txt 檔是aapt帶參數–output-text-symbols的輸出結果。

jar打包不能包含資源檔,比如一些drawable檔、xml資源檔之類的,aar可以。

SQLite支援事務嗎?添加刪除如何提高性能?

SQLite作為羽量級的資料庫,比MySQL還小,但支持SQL語句查詢,提高性能可以考慮通過原始經過優化的SQL查詢語句方式處理

如何將SQLite資料庫(dictionary.db檔)與apk檔一起發佈?

可以將dictionary.db檔複製到Eclipse Android工程中的res aw目錄中。所有在res aw目錄中的檔不會被壓縮,這樣可以直接提取該目錄中的檔。可以將dictionary.db檔複製到res aw目錄中

如何保證Service在後臺不被kill

Service設置成START_STICKY kill 後會被重啟(等待5秒左右),重傳Intent,保持與重啟前一樣

通過 startForeground將進程設置為前臺進程, 做前臺服務,優先順序和前臺應用一個級別,除非在系統記憶體非常缺,否則此進程不會被 kill

雙進程Service: 讓2個進程互相保護**,其中一個Service被清理後,另外沒被清理的進程可以立即重啟進程

QQ黑科技: 在應用退到後臺後,另起一個只有 1 圖元的頁面停留在桌面上,讓自己保持前臺狀態,保護自己不被後臺清理工具殺死

在已經root的設備下,修改相應的許可權檔,將App偽裝成系統級的應用 Android4.0系列的一個漏洞,已經確認可行

用C編寫守護進程(即子進程) : Android系統中當前進程(Process)fork出來的子進程,被系統認為是兩個不同的進程。當父進程被殺死的時候,子進程仍然可以存活,並不受影響。*鑒於目前提到的在Android->- Service層做雙守護都會失敗*,我們可以fork出c進程,多進程守護。閉環在那檢查是否還存在,具體的思路如下(Android5.0以上的版本不可行)

用C編寫守護進程(即子進程),守護進程做的事情就是迴圈檢查目標進程是否存在,不存在則啟動它。

在NDK環境中將1中編寫的C代碼編譯打包成可執行檔(BUILD_EXECUTABLE)。主進程啟動時將守護進程放入私有目錄下,賦予可執行許可權,啟動它即可。

聯繫廠商,加入白名單

Android中如何獲得手機的唯一標示.

1 首先嘗試讀取IMEI、Mac位址、CPU號等物理資訊(有不少工具可以修改IMEI);

2 如果均失敗,可以自己生成UUID然後保存到檔(檔也可能被篡改或刪除)

參考:[blog.csdn.net/xushuaic/ar…]

mipmap資料夾和drawable資料夾的區別

它只是用來放啟動圖示的,好處就是,你只用放一個mipmap圖示,它就會給你各種版本(比如平板,手機)的apk自動生成相應解析度的圖示,以節約空間。

ListView卡頓的原因以及優化策略

重用converView: 通過複用converview來減少不必要的view的創建,另外Infalte操作會把xml檔產生實體成相應的View實例,屬於IO操作,是耗時操作。

減少findViewById()操作: 將xml檔中的元素封裝成viewholder靜態類,通過converview的setTag和getTag方法將view與相應的holder物件綁定在一起,避免不必要的findviewbyid操作

避免在 getView 方法中做耗時的操作: 例如載入本地 Image 需要載入記憶體以及解析 Bitmap ,都是比較耗時的操作,如果用戶快速滑動listview,會因為getview邏輯過於複雜耗時而造成滑動卡頓現象。使用者滑動時候不要載入圖片,待滑動完成再載入,可以使用這個協力廠商庫glide

Item的佈局層次結構儘量簡單,避免佈局太深或者不必要的重繪

儘量能保證 Adapter 的 hasStableIds() 返回 true 這樣在 notifyDataSetChanged() 的時候,如果item內容並沒有變化,ListView 將不會重新繪製這個 View,達到優化的目的

在一些場景中,ScollView內會包含多個ListView,可以把listview的高度寫死固定下來。 由於ScollView在快速滑動過程中需要大量計算每一個listview的高度,阻塞了UI執行緒導致卡頓現象出現,如果我們每一個item的高度都是均勻的,可以通過計算把listview的高度確定下來,避免卡頓現象出現

使用 RecycleView 代替listview: 每個item內容的變動,listview都需要去調用notifyDataSetChanged來更新全部的item,太浪費性能了。RecycleView可以實現當 個item的局部刷新,並且引入了增加和刪除的動態效果,在性能上和定制上都有很大的改善

ListView 中元素避免半透明: 半透明繪製需要大量乘法計算,在滑動時不停重繪會造成大量的計算,在比較差的機子上會比較卡。 在設計上能不半透明就不不半透明。實在要弄就把在滑動的時候把半透明設置成不透明,滑動完再重新設置成半透明。

儘量開啟硬體加速: 硬體加速提升巨大,避免使用一些不支援的函數導致含淚關閉某個地方的硬體加速。當然這一條不只是對 ListView。

ViewHolder為什麼要被聲明成靜態內部類

這個是考靜態內部類和非靜態內部類的主要區別之一。非靜態內部類會隱式持有外部類的引用,就像大家經常將自訂的adapter在Activity類裡,然後在adapter類裡面是可以隨意調用外部activity的方法的。

當你將內部類定義為static時,你就調用不了外部類的實例方法了,因為這時候靜態內部類是不持有外部類的引用的。聲明ViewHolder靜態內部類,可以將ViewHolder和外部類解引用。

大家會說一般ViewHolder都很簡單,不定義為static也沒事吧。確實如此,但是如果你將它定義為static的,說明你懂這些含義。萬一有一天你在這個ViewHolder加入一些複雜邏輯,做了一些耗時工作,那麼如果ViewHolder是非靜態內部類的話,就很容易出現記憶體洩露。

如果是靜態的話,你就不能直接引用外部類,迫使你關注如何避免相互引用。 所以將 ViewHolder內部類 定義為靜態的,是一種好習慣

動畫相關

Android中的動畫有哪些?

逐幀動畫(Drawable Animation):

載入一系列Drawable資源來創建動畫,簡單來說就是播放一系列的圖片來實現動畫效果,可以自訂每張圖片的持續時間

補間動畫(Tween Animation):

Tween可以對View物件實現一系列簡單的動畫效果,比如位移,縮放,旋轉,透明度等等。但是它並不會改變View屬性的值,只是改變了View的繪製的位置,比如,一個按鈕在動畫過後,不在原來的位置,但是觸發點擊事件的仍然是原來的座標。

屬性動畫(Property Animation):

動畫的物件除了傳統的View物件,還可以是Object物件,動畫結束後,Object物件的屬性值被實實在在的改變了

Android動畫原理

Animation框架定義了透明度,旋轉,縮放和位移幾種常見的動畫,而且控制的是整個View

實現原理是每次繪製視圖時View所在的ViewGroup中的drawChild函數獲取該View的Animation的Transformation值

然後調用canvas.concat(transformToApply.getMatrix()),通過矩陣運算完成動畫幀,如果動畫沒有完成,繼續調用invalidate()函數,啟動下次繪製來驅動動畫

動畫過程中的幀之間間隙時間是繪製函數所消耗的時間,可能會導致動畫消耗比較多的CPU資源,最重要的是,動畫改變的只是顯示,並不能相應事件

View繪製相關

SurfaceView和View的區別

SurfaceView中採用了雙緩存技術,在單獨的執行緒中更新介面

View在UI執行緒中更新介面

介紹下自訂view的基本流程

1、 明確需求,確定你想實現的效果

2、確定是使用群組控制項的形式還是全新自訂的形式,群組控制項即使用多個系統控制項來合成一個新控制項,你比如titilebar,這種形式相對簡單,參考

3、如果是完全自訂一個view的話,你首先需要考慮繼承哪個類,是View呢,還是ImageView等子類。

4、根據需要去複寫View#onDraw、View#onMeasure、View#onLayout方法

5.根據需要去複寫dispatchTouchEvent、onTouchEvent方法

6、根據需要為你的自訂view提供自訂屬性,即編寫attr.xml,然後在代碼中通過TypedArray等類獲取到自訂屬性值

7、需要處理滑動衝突、圖元轉換等問題

談談View的繪製流程

談談View的繪製流程

Markdown

measure()方法,layout(),draw()三個方法主要存放了一些識別字,來判斷每個View是否需要再重新測量,佈局或者繪製,主要的繪製過程還是在onMeasure,onLayout,onDraw這個三個方法中

1.onMesarue() 為整個View樹計算實際的大小,即設置實際的高(對應屬性:mMeasuredHeight)和寬(對應屬性: mMeasureWidth),每個View的控制項的實際寬高都是由父視圖和本身視圖決定的。

2.onLayout() 為將整個根據子視圖的大小以及佈局參數將View樹放到合適的位置上。

3.onDraw() 開始繪製圖像,繪製的流程如下

首先繪製該View的背景

調用onDraw()方法繪製視圖本身 (每個View都需要重載該方法,ViewGroup不需要實現該方法)

如果該View是ViewGroup,調用dispatchDraw ()方法繪製子視圖

繪製捲軸

自訂View執行invalidate()方法,為什麼有時候不會回檔onDraw()

自訂一個view時,重寫onDraw。調用view.invalidate(),會觸發onDraw和computeScroll()。前提是該view被附加在當前窗口.

view.postInvalidate(); //是在非UI執行緒上調用的

自訂一個ViewGroup,重寫onDraw。onDraw可能不會被調用,原因是需要先設置一個背景(顏色或圖)。表示這個group有東西需要繪製了,才會觸發draw,之後是onDraw。因此,一般直接重寫dispatchDraw來繪製viewGroup.自訂一個ViewGroup,dispatchDraw會調用drawChild.

事件傳遞機制

談談touch事件的傳遞流程

Markdown

所有Touch事件都被封裝成了MotionEvent物件,包括Touch的位置、時間、歷史記錄以及第幾個手指(多指觸摸)等。

事件類型分為ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每個事件都是以ACTION_DOWN開始ACTION_UP結束。

對事件的處理包括三類,分別為傳遞——dispatchTouchEvent()函數、攔截——onInterceptTouchEvent()函數、消費——onTouchEvent()函數和OnTouchListener()

簡單來說:

事件從Activity.dispatchTouchEvent()開始傳遞,只要沒有被停止或攔截,從最上層的View(ViewGroup)開始一直往下(子View)傳遞。子View可以通過onTouchEvent()對事件進行處理。

事件由父View(ViewGroup)傳遞給子View,ViewGroup可以通過onInterceptTouchEvent()對事件做攔截,停止其往下傳遞。

如果事件從上往下傳遞過程中一直沒有被停止,且最底層子View沒有消費事件,事件會反嚮往上傳遞,這時父View(ViewGroup)可以進行消費,如果還是沒有被消費的話,最後會到Activity的onTouchEvent()函數。

如果View沒有對ACTION_DOWN進行消費,之後的其他事件不會傳遞過來。

= OnTouchListener優先於onTouchEvent()對事件進行消費。

上面的消費即表示相應函數返回值為true。

View中setOnTouchListener中的onTouch,onTouchEvent,onClick的執行順序

onTouch優於onTouchEvent,onTouchEvent優於onClick

觸摸事件的分發機制詳見:

Android觸摸事件分發機制完全解析《一》

什麼是Dalvik虛擬機器

Dalvik虛擬機器是Android平臺的核心。

它可以支援.dex格式的程式的運行

.dex格式是專為Dalvik設計的一種壓縮格式

可以減少整體檔尺寸

提高I/O操作的速度

適合記憶體和處理器速度有限的系統

Dalvik虛擬機器和JVM有什麼區別

Dalvik 基於寄存器,而 JVM 基於棧。基於寄存器的虛擬機器對於更大的程式來說,在它們編譯的時候,花費的時間更短。

Dalvik執行.dex格式的位元組碼,而JVM執行.class格式的位元組碼

Android為每個應用程式分配的記憶體大小是多少

一般是16m或者24m,但是可以通過android:largeHeap申請更多記憶體

具體參考:

[liuzhichao.com/2016/use-an…]

[www.cnblogs.com/mythou/p/32…]

如何解決方法數65k問題?

使用Android Studio 的gradle 可以構建MutilDex

相信自己,沒有做不到的,只有想不到的

同類文章
Next Article
喜欢就按个赞吧!!!
点击关闭提示