Android高新面試題2017匯總(帶答案)

?

前言介紹

最近匯總了一些大公司的部分面試題,包括騰訊、華為、阿里、網(wǎng)易等。

博客地址:

http://blog.csdn.net/androidstarjack/article

正文

?插件化、熱修復(fù) 、熱更新的理解

  • 插件化 – apk 分為宿主和插件部分,插件在需要的時(shí)候才加載進(jìn)來

  • 熱修復(fù) – 更新的類或者插件粒度較小的時(shí)候,我們會稱之為熱修復(fù),一般用于修復(fù)bug

  • 熱更新 – 2016 Google 的 Android Studio 推出了Instant Run 功能 同時(shí)提出了3個(gè)名詞

    • “ 熱部署” – 方法內(nèi)的簡單修改,無需重啟app和Activity。

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

    • “冷部署” – app需要重啟,比如繼承關(guān)系的改變或方法的簽名變化等。

  • 站在app開發(fā)者角度的“熱”是指在不發(fā)版的情況來實(shí)現(xiàn)更新

  • 而Google提出的“熱”是指值是否需要重新啟動。 - 同時(shí)在開發(fā)插件化的時(shí)候也有兩種情景

  • 一種是插件與宿主apk沒有交互,只是在用戶使用到的時(shí)候進(jìn)行一次吊起

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

你認(rèn)為Android熱更新框架哪個(gè)好:

  • 1.阿里的熱更新框架已經(jīng)開源 了。但已經(jīng)很久沒有更新過新版本了。當(dāng)前的版本只支持到了 Android 4.4。由于 5.0 起新的 ART 虛擬機(jī)、更嚴(yán)格的 SELinux 策略以及對 64 位的支持之類的事,使得 Xposed 都在開發(fā)上做了很多調(diào)整。我不知道 Dexposed 現(xiàn)在是否支持,但至少阿里沒有開源。

  • 2.在本地動態(tài)執(zhí)行遠(yuǎn)端下發(fā)的代碼是極度危險(xiǎn)的行為。利用此方法執(zhí)行非法代碼等或用于繞過 Google Play 等市場的審查是違反相關(guān)協(xié)議的,也是對用戶極度不負(fù)責(zé)任的行為。

  • 3.在一些訪問非常密集的地方使用熱更新可能會對效率產(chǎn)生相對比較大的影響,應(yīng)該避免使用.

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

  • 5.首先,檢查熱更新補(bǔ)丁的管道一定要建立在 https 上,因?yàn)橄掳l(fā)代碼是極其危險(xiǎn)的,如果被劫持,后果是無法想象的。其次,請求時(shí)最好自動帶上 Android 版本、手機(jī)型號、地區(qū)、版本號等信息,以方便更精確地下發(fā),千萬不能下發(fā)錯(cuò)。

  • 6.Java在運(yùn)行時(shí)加載對應(yīng)的類是通過ClassLoader來實(shí)現(xiàn)的,ClassLoader本身是一個(gè)抽象來,Android中使用PathClassLoader類作為Android的默認(rèn)的類加載器

  • 7.我們的如果想做hotpatch,一定要保證我們的hotpacth dex文件出現(xiàn)在dexElements列表的前面。

二.常用的熱更新技術(shù)框架:

  • 基于QQ空間的HotFix →→ 要使用到android dex分包方案→拆分dex的項(xiàng)目的話,可以參考一下谷歌的multidex方案實(shí)現(xiàn).

  • 大眾點(diǎn)評的NuWa←項(xiàng)目補(bǔ)丁自動化做的很完整

  • alibaba/AndFix

  • 阿里巴巴的DexPosed

  • dalvik_patch實(shí)現(xiàn)multidex

  • 使用React-Native實(shí)現(xiàn)app熱部署的一次實(shí)踐

  • alibaba/AndFix

基礎(chǔ)

activity生命周期圖解

注意

鎖定屏與解鎖屏幕 只會調(diào)用onPause(),而不會調(diào)用onStop方法,開屏后則調(diào)用onResume()。在實(shí)際操作中會有所出入,比如在三星手機(jī)測試的時(shí)候鎖定手機(jī)調(diào)用了onPause()和onStop()方法,解鎖時(shí)候調(diào)用的是:onRestart(),onStart()和 onResume()方法。

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

  • 啟動Activity:

    onCreate()—>onStart()—>onResume(),Activity進(jìn)入運(yùn)行狀態(tài)。

  • Activity退居后臺:

    當(dāng)前Activity轉(zhuǎn)到新的Activity界面或按Home鍵回到主屏: onPause()—>onStop(),進(jìn)入停滯狀態(tài)。

  • Activity返回前臺: onRestart()—>onStart()—>onResume(),再次回到運(yùn)行狀態(tài)。

  • Activity退居后臺,且系統(tǒng)內(nèi)存不足,

    系統(tǒng)會殺死這個(gè)后臺狀態(tài)的Activity,若再次回到這個(gè)Activity,則會走onCreate()–>onStart()—>onResume()

  • 鎖定屏與解鎖屏幕

    只會調(diào)用onPause(),而不會調(diào)用onStop方法,開屏后則調(diào)用onResume()

Activity銷毀但Task如果沒有銷毀掉,當(dāng)Activity重啟時(shí)這個(gè)AsyncTask該如何解決?

比如屏幕旋轉(zhuǎn)這個(gè)例子,在重建Activity的時(shí)候,會回調(diào)

Activity.onRetainNonConfigurationInstance()

重新傳遞一個(gè)新的對象給AsyncTask,完成引用的更新

若Activity已經(jīng)銷毀,此時(shí)AsynTask執(zhí)行完并返回結(jié)果,會報(bào)異常么?

  • 當(dāng)一個(gè)App旋轉(zhuǎn)時(shí),整個(gè)Activity會被銷毀和重建。

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

  • 若AsynTask正在執(zhí)行,折會報(bào) view not attached to window manager 異常

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

內(nèi)存不足時(shí),系統(tǒng)會殺死后臺的Activity,如果需要進(jìn)行一些臨時(shí)狀態(tài)的保存,在哪個(gè)方法進(jìn)行

  • Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,不同于 onCreate()、onPause()等生命周期方法,它們并不一定會被觸發(fā)。

  • 當(dāng)應(yīng)用遇到意外情況(如:內(nèi)存不足、用戶直接按Home鍵)由系統(tǒng)銷毀一個(gè)Activity,onSaveInstanceState() 會被調(diào)用。

  • 但是當(dāng)用戶主動去銷毀一個(gè)Activity時(shí),例如在應(yīng)用中按返回鍵,onSaveInstanceState()就不會被調(diào)用。除非該activity是被用戶主動銷毀的

  • 通常onSaveInstanceState()只適合用于保存一些臨時(shí)性的狀態(tài),而onPause()適合用于數(shù)據(jù)的持久化保存。

介紹Activity 四中l(wèi)aunchMode:

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

  • 1、standard

    standard模式是默認(rèn)的啟動模式,不用為配置android:launchMode屬性即可,當(dāng)然也可以指定值為standard。standard啟動模式,不管有沒有已存在的實(shí)例,都生成新的實(shí)例。

  • 2、?singleTop

    我們在上面的基礎(chǔ)上為指定屬性android:launchMode=”singleTop”,系統(tǒng)就會按照singleTop啟動模式處理跳轉(zhuǎn)行為。跳轉(zhuǎn)時(shí)系統(tǒng)會先在棧結(jié)構(gòu)中尋找是否有一個(gè)Activity實(shí)例正位于棧頂,如果有則不再生成新的,而是直接使用。如果系統(tǒng)發(fā)現(xiàn)存在有Activity實(shí)例,但不是位于棧頂,重新生成一個(gè)實(shí)例。 這就是singleTop啟動模式,如果發(fā)現(xiàn)有對應(yīng)的Activity實(shí)例正位于棧頂,則重復(fù)利用,不再生成新的實(shí)例。

  • 3、?singleTask

    如果發(fā)現(xiàn)有對應(yīng)的Activity實(shí)例,則使此Activity實(shí)例之上的其他Activity實(shí)例統(tǒng)統(tǒng)出棧,使此Activity實(shí)例成為棧頂對象,顯示到幕前。

  • 4、singleInstance

    這種啟動模式比較特殊,因?yàn)樗鼤⒂靡粋€(gè)新的棧結(jié)構(gòu),將Acitvity放置于這個(gè)新的棧結(jié)構(gòu)中,并保證不再有其他Activity實(shí)例進(jìn)入。

LaunchMode使用場景

  • singleTop適合接收通知啟動的內(nèi)容顯示頁面。

    例如,某個(gè)新聞客戶端的新聞內(nèi)容頁面,如果收到10個(gè)新聞推送,每次都打開一個(gè)新聞內(nèi)容頁面是很煩人的。

  • singleTask適合作為程序入口點(diǎn)。

    例如瀏覽器的主界面。不管從多少個(gè)應(yīng)用啟動瀏覽器,只會啟動主界面一次,其余情況都會走onNewIntent,并且會清空主界面上面的其他頁面。

  • singleInstance應(yīng)用場景:

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

  • SingleInstance

    加載模式打開的),你按返回鍵,回到的是微信的聊天界面,這是因?yàn)?AlarmAlertActivity 所在的 Task 的棧只有他一個(gè)元素, 因此退出之后這個(gè) Task 的??樟?。如果是以 SingleTask 打開 AlarmAlertActivity,那么當(dāng)鬧鈴響了的時(shí)候,按返回鍵應(yīng)該進(jìn)入鬧鈴設(shè)置界面。

如何把一個(gè)應(yīng)用設(shè)置為系統(tǒng)應(yīng)用

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

  • 如果是非root設(shè)備,需要編譯后燒寫鏡像

  • 有些權(quán)限(如WRITE_SECURE_SETTINGS)不開放給第三方應(yīng)用,只能在對應(yīng)設(shè)備源碼總編譯然后作為系統(tǒng)app使用

Activity,Window,View三者的聯(lián)系和區(qū)別?

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

  • Window像窗戶(承載模型)

  • View像窗花(顯示視圖)

  • LayoutInflater像剪刀

  • Xml配置像窗花圖紙。

Activity啟動Service的兩種方式

  • startService:生命周期和調(diào)用者不同.啟動后若調(diào)用者未調(diào)用stopService而直接退出,Service仍會運(yùn)行

  • bindService:生命周期與調(diào)用者綁定,調(diào)用者一旦退出,Service就會調(diào)用unBind->onDestory

Android兩個(gè)應(yīng)用能在同一個(gè)任務(wù)棧嗎?

棧一般以包名命名,兩個(gè)應(yīng)用的簽名和udid要相同

Fragment是什么?你曾經(jīng)遇到哪些有關(guān)Fragment的問題?

  • Fragment可以作為Activity界面的一部分組成出現(xiàn)

    • 其作用是:

      碎片整理,局部刷新。

  • 一個(gè)Activity中可以同時(shí)出現(xiàn)多個(gè)Fragment,并一個(gè)Fragment也可以在多個(gè)Activity中使用.

  • 在Activity中可以添加,刪除,替換Fragment.Fragment可以響應(yīng)自己的輸入時(shí)間,并且有自己的生命周期,但其生命周期收Activity影響.

Fragment生命周期

如何實(shí)現(xiàn)Activity窗口快速變暗

利用只讀屬性動畫+WindowManager

/* ?*@param from\>=0&&from\<=1.0f ?* @param to\>=0&&to\<=1.0f ?* ?* */ private void dimBackground(final float from, final float to) { final Window window = getWindow(); ValueAnimator valueAnimator = ValueAnimator.ofFloat(from, to); valueAnimator.setDuration(500); valueAnimator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { ?WindowManager.LayoutParams
?params = window.getAttributes();
?params.alpha = (Float) animation.getAnimatedValue(); ?window.setAttributes(params); } }); valueAnimator.start(); }

是否使用過本地廣播,和全局廣播有什么區(qū)別?

本地廣播在本應(yīng)用范圍內(nèi)傳播,不用擔(dān)心隱私數(shù)據(jù)泄露,不用擔(dān)心別的應(yīng)用偽造廣播.相比全局廣播,本地廣播更高效.

注冊廣播的幾種方法?

  • 1.靜態(tài)注冊:在清單文件中注冊, 常見的有監(jiān)聽設(shè)備啟動,常駐注冊不會隨程序生命周期改變

  • 2.動態(tài)注冊:在代碼中注冊,隨著程序的結(jié)束,也就停止接受廣播了

    補(bǔ)充一點(diǎn):有些廣播只能通過動態(tài)方式注冊,比如時(shí)間變化事件、屏幕亮滅事件、電量變更事件,因?yàn)檫@些事件觸發(fā)頻率通常很高,如果允許后臺監(jiān)聽,會導(dǎo)致進(jìn)程頻繁創(chuàng)建和銷毀,從而影響系統(tǒng)整體性能

為什么Android引入廣播機(jī)制?
  • a:從MVC的角度考慮(應(yīng)用程序內(nèi)) 其實(shí)回答這個(gè)問題的時(shí)候還可以這樣問,android為什么要有那4大組件,現(xiàn)在的移動開發(fā)模型基本上也是照搬的web那一套MVC架構(gòu),只不過是改了點(diǎn)嫁妝而已。

    • android的四大組件本質(zhì)上就是為了實(shí)現(xiàn)移動或者說嵌入式設(shè)備上的MVC架構(gòu)

    • 它們之間有時(shí)候是一種相互依存的關(guān)系,有時(shí)候又是一種補(bǔ)充關(guān)系,引入廣播機(jī)制可以方便幾大組件的信息和數(shù)據(jù)交互。

  • b:程序間互通消息(例如在自己的應(yīng)用程序內(nèi)監(jiān)聽系統(tǒng)來電)

  • c:效率上(參考UDP的廣播協(xié)議在局域網(wǎng)的方便性)

  • d:設(shè)計(jì)模式上(反轉(zhuǎn)控制的一種應(yīng)用,類似監(jiān)聽者模式)

了解IntentServices嗎?

  • IntentService是Service的子類,是一個(gè)異步的,會自動停止的服務(wù),很好解決了傳統(tǒng)的Service中處理完耗時(shí)操作忘記停止并銷毀Service的問題

  • 生成一個(gè)默認(rèn)的且與線程相互獨(dú)立的工作線程執(zhí)行所有發(fā)送到onStartCommand()方法的Intent,可以在onHandleIntent()中處理.

  • 串行隊(duì)列,每次只運(yùn)行一個(gè)任務(wù),不存在線程安全問題,所有任務(wù)執(zhí)行完后自動停止服務(wù),不需要自己手動調(diào)用stopSelf()來停止.

如何提升Service進(jìn)程優(yōu)先級

在AndroidManifest.xml文件中對于intent-filter可以通過android:priority = “1000”這個(gè)屬性設(shè)置最高優(yōu)先級,1000是最高值,如果數(shù)字越小則優(yōu)先級越低,同時(shí)適用于廣播。

ContentProvider和sql的區(qū)別

ContentProvider的主要還是用于數(shù)據(jù)共享,其可以對Sqlite,SharePreferences,F(xiàn)ile等進(jìn)行數(shù)據(jù)操作用來共享數(shù)據(jù)。而sql的可以理解為數(shù)據(jù)庫的一門語言,可以使用它完成CRUD等一系列的操作

數(shù)據(jù)存儲相關(guān)
  • 文件存儲:

    通過Java.io.FileInputStream和java.io.FileOutputStream這兩個(gè)類來實(shí)現(xiàn)對文件的讀寫,java.io.File類則用來構(gòu)造一個(gè)具體指向某個(gè)文件或者文件夾的對象。

  • SharedPreferences:

    SharedPreferences是一種輕量級的數(shù)據(jù)存儲機(jī)制,他將一些簡單的數(shù)據(jù)類型的數(shù)據(jù),包括boolean類型,int類型,float類型,long類型以及String類型的數(shù)據(jù),以鍵值對的形式存儲在應(yīng)用程序的私有Preferences目錄(/data/data/<包名>/shared_prefs/)中,這種Preferences機(jī)制廣泛應(yīng)用于存儲應(yīng)用程序中的配置信息。

  • SQLite數(shù)據(jù)庫:

    當(dāng)應(yīng)用程序需要處理的數(shù)據(jù)量比較大時(shí),為了更加合理地存儲、管理、查詢數(shù)據(jù),我們往往使用關(guān)系數(shù)據(jù)庫來存儲數(shù)據(jù)。Android系統(tǒng)的很多用戶數(shù)據(jù),如聯(lián)系人信息,通話記錄,短信息等,都是存儲在SQLite數(shù)據(jù)庫當(dāng)中的,所以利用操作SQLite數(shù)據(jù)庫的API可以同樣方便的訪問和修改這些數(shù)據(jù)。

  • ContentProvider:

    主要用于在不同的應(yīng)用程序之間實(shí)現(xiàn)數(shù)據(jù)共享的功能,不同于sharepreference和文件存儲中的兩種全局可讀寫操作模式,內(nèi)容提供其可以選擇只對哪一部分?jǐn)?shù)據(jù)進(jìn)行共享,從而保證我們程序中的隱私數(shù)據(jù)不會有泄漏的風(fēng)險(xiǎn)

如何將打開res aw目錄中的數(shù)據(jù)庫文件?

  • 在Android中不能直接打開res aw目錄中的數(shù)據(jù)庫文件,而需要在程序第一次啟動時(shí)將該文件復(fù)制到手機(jī)內(nèi)存或SD卡的某個(gè)目錄中,然后再打開該數(shù)據(jù)庫文件。

  • 復(fù)制的基本方法是使用getResources().openRawResource方法獲得res aw目錄中資源的 InputStream對象,然后將該InputStream對象中的數(shù)據(jù)寫入其他的目錄中相應(yīng)文件中。

  • 在Android SDK中可以使用SQLiteDatabase.openOrCreateDatabase方法來打開任意目錄中的SQLite數(shù)據(jù)庫文件。

什么是aar?aar是jar有什么區(qū)別?

“aar”包是 Android 的類庫項(xiàng)目的二進(jìn)制發(fā)行包。 文件擴(kuò)展名是.aar,maven 項(xiàng)目類型應(yīng)該也是aar,但文件本身是帶有以下各項(xiàng)的 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帶參數(shù)–output-text-symbols的輸出結(jié)果。

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

SQLite支持事務(wù)嗎?添加刪除如何提高性能?

SQLite作為輕量級的數(shù)據(jù)庫,比MySQL還小,但支持SQL語句查詢,提高性能可以考慮通過原始經(jīng)過優(yōu)化的SQL查詢語句方式處理

如何將SQLite數(shù)據(jù)庫(dictionary.db文件)與apk文件一起發(fā)布?

可以將dictionary.db文件復(fù)制到Eclipse Android工程中的res aw目錄中。所有在res aw目錄中的文件不會被壓縮,這樣可以直接提取該目錄中的文件??梢詫ictionary.db文件復(fù)制到res aw目錄中

如何保證Service在后臺不被kill

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

  • 通過 startForeground將進(jìn)程設(shè)置為前臺進(jìn)程, 做前臺服務(wù),優(yōu)先級和前臺應(yīng)用一個(gè)級別,除非在系統(tǒng)內(nèi)存非常缺,否則此進(jìn)程不會被 kill

  • 雙進(jìn)程Service: 讓2個(gè)進(jìn)程互相保護(hù)**,其中一個(gè)Service被清理后,另外沒被清理的進(jìn)程可以立即重啟進(jìn)程

  • QQ黑科技: 在應(yīng)用退到后臺后,另起一個(gè)只有 1 像素的頁面停留在桌面上,讓自己保持前臺狀態(tài),保護(hù)自己不被后臺清理工具殺死

  • 在已經(jīng)root的設(shè)備下,修改相應(yīng)的權(quán)限文件,將App偽裝成系統(tǒng)級的應(yīng)用 Android4.0系列的一個(gè)漏洞,已經(jīng)確認(rèn)可行

  • 用C編寫守護(hù)進(jìn)程(即子進(jìn)程) : Android系統(tǒng)中當(dāng)前進(jìn)程(Process)fork出來的子進(jìn)程,被系統(tǒng)認(rèn)為是兩個(gè)不同的進(jìn)程。當(dāng)父進(jìn)程被殺死的時(shí)候,子進(jìn)程仍然可以存活,并不受影響。鑒于目前提到的在Android->-?Service層做雙守護(hù)都會失敗,我們可以fork出c進(jìn)程,多進(jìn)程守護(hù)。死循環(huán)在那檢查是否還存在,具體的思路如下(Android5.0以上的版本不可行)

  • 用C編寫守護(hù)進(jìn)程(即子進(jìn)程),守護(hù)進(jìn)程做的事情就是循環(huán)檢查目標(biāo)進(jìn)程是否存在,不存在則啟動它。 在NDK環(huán)境中將1中編寫的C代碼編譯打包成可執(zhí)行文件(BUILD_EXECUTABLE)。主進(jìn)程啟動時(shí)將守護(hù)進(jìn)程放入私有目錄下,賦予可執(zhí)行權(quán)限,啟動它即可。

  • 聯(lián)系廠商,加入白名單

Android中如何獲得手機(jī)的唯一標(biāo)示.

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

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

參考:[http://blog.csdn.net/xushuaic/article/details/25077179]

mipmap文件夾和drawable文件夾的區(qū)別

它只是用來放啟動圖標(biāo)的,好處就是,你只用放一個(gè)mipmap圖標(biāo),它就會給你各種版本(比如平板,手機(jī))的apk自動生成相應(yīng)分辨率的圖標(biāo),以節(jié)約空間。

ListView卡頓的原因以及優(yōu)化策略

  • 重用converView: 通過復(fù)用converview來減少不必要的view的創(chuàng)建,另外Infalte操作會把xml文件實(shí)例化成相應(yīng)的View實(shí)例,屬于IO操作,是耗時(shí)操作。

  • 減少findViewById()操作: 將xml文件中的元素封裝成viewholder靜態(tài)類,通過converview的setTag和getTag方法將view與相應(yīng)的holder對象綁定在一起,避免不必要的findviewbyid操作

  • 避免在 getView 方法中做耗時(shí)的操作: 例如加載本地 Image 需要載入內(nèi)存以及解析 Bitmap ,都是比較耗時(shí)的操作,如果用戶快速滑動listview,會因?yàn)間etview邏輯過于復(fù)雜耗時(shí)而造成滑動卡頓現(xiàn)象。用戶滑動時(shí)候不要加載圖片,待滑動完成再加載,可以使用這個(gè)第三方庫glide

  • Item的布局層次結(jié)構(gòu)盡量簡單,避免布局太深或者不必要的重繪

  • 盡量能保證 Adapter 的 hasStableIds() 返回 true 這樣在 notifyDataSetChanged() 的時(shí)候,如果item內(nèi)容并沒有變化,ListView 將不會重新繪制這個(gè) View,達(dá)到優(yōu)化的目的

  • 在一些場景中,ScollView內(nèi)會包含多個(gè)ListView,可以把listview的高度寫死固定下來。 由于ScollView在快速滑動過程中需要大量計(jì)算每一個(gè)listview的高度,阻塞了UI線程導(dǎo)致卡頓現(xiàn)象出現(xiàn),如果我們每一個(gè)item的高度都是均勻的,可以通過計(jì)算把listview的高度確定下來,避免卡頓現(xiàn)象出現(xiàn)

  • 使用 RecycleView 代替listview: 每個(gè)item內(nèi)容的變動,listview都需要去調(diào)用notifyDataSetChanged來更新全部的item,太浪費(fèi)性能了。RecycleView可以實(shí)現(xiàn)當(dāng)個(gè)item的局部刷新,并且引入了增加和刪除的動態(tài)效果,在性能上和定制上都有很大的改善

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

  • 盡量開啟硬件加速: 硬件加速提升巨大,避免使用一些不支持的函數(shù)導(dǎo)致含淚關(guān)閉某個(gè)地方的硬件加速。當(dāng)然這一條不只是對 ListView。

ViewHolder為什么要被聲明成靜態(tài)內(nèi)部類

  • 這個(gè)是考靜態(tài)內(nèi)部類和非靜態(tài)內(nèi)部類的主要區(qū)別之一。非靜態(tài)內(nèi)部類會隱式持有外部類的引用,就像大家經(jīng)常將自定義的adapter在Activity類里,然后在adapter類里面是可以隨意調(diào)用外部activity的方法的。

  • 當(dāng)你將內(nèi)部類定義為static時(shí),你就調(diào)用不了外部類的實(shí)例方法了,因?yàn)檫@時(shí)候靜態(tài)內(nèi)部類是不持有外部類的引用的。聲明ViewHolder靜態(tài)內(nèi)部類,可以將ViewHolder和外部類解引用。

  • 大家會說一般ViewHolder都很簡單,不定義為static也沒事吧。確實(shí)如此,但是如果你將它定義為static的,說明你懂這些含義。萬一有一天你在這個(gè)ViewHolder加入一些復(fù)雜邏輯,做了一些耗時(shí)工作,那么如果ViewHolder是非靜態(tài)內(nèi)部類的話,就很容易出現(xiàn)內(nèi)存泄露。

  • 如果是靜態(tài)的話,你就不能直接引用外部類,迫使你關(guān)注如何避免相互引用。 所以將 ViewHolder內(nèi)部類 定義為靜態(tài)的,是一種好習(xí)慣

動畫相關(guān)

Android中的動畫有哪些?

  • 逐幀動畫(Drawable Animation):

    加載一系列Drawable資源來創(chuàng)建動畫,簡單來說就是播放一系列的圖片來實(shí)現(xiàn)動畫效果,可以自定義每張圖片的持續(xù)時(shí)間

  • 補(bǔ)間動畫(Tween Animation):

    Tween可以對View對象實(shí)現(xiàn)一系列簡單的動畫效果,比如位移,縮放,旋轉(zhuǎn),透明度等等。但是它并不會改變View屬性的值,只是改變了View的繪制的位置,比如,一個(gè)按鈕在動畫過后,不在原來的位置,但是觸發(fā)點(diǎn)擊事件的仍然是原來的坐標(biāo)。

  • 屬性動畫(Property Animation):

    動畫的對象除了傳統(tǒng)的View對象,還可以是Object對象,動畫結(jié)束后,Object對象的屬性值被實(shí)實(shí)在在的改變了

Android動畫原理

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

  • 實(shí)現(xiàn)原理是每次繪制視圖時(shí)View所在的ViewGroup中的drawChild函數(shù)獲取該View的Animation的Transformation值

  • 然后調(diào)用canvas.concat(transformToApply.getMatrix()),通過矩陣運(yùn)算完成動畫幀,如果動畫沒有完成,繼續(xù)調(diào)用invalidate()函數(shù),啟動下次繪制來驅(qū)動動畫

  • 動畫過程中的幀之間間隙時(shí)間是繪制函數(shù)所消耗的時(shí)間,可能會導(dǎo)致動畫消耗比較多的CPU資源,最重要的是,動畫改變的只是顯示,并不能相應(yīng)事件

View繪制相關(guān)

SurfaceView和View的區(qū)別

  • SurfaceView中采用了雙緩存技術(shù),在單獨(dú)的線程中更新界面

  • View在UI線程中更新界面

介紹下自定義view的基本流程

  • 1、 明確需求,確定你想實(shí)現(xiàn)的效果

  • 2、確定是使用組合控件的形式還是全新自定義的形式,組合控件即使用多個(gè)系統(tǒng)控件來合成一個(gè)新控件,你比如titilebar,這種形式相對簡單,參考

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

  • 4、根據(jù)需要去復(fù)寫View#onDraw、View#onMeasure、View#onLayout方法

  • 5.根據(jù)需要去復(fù)寫dispatchTouchEvent、onTouchEvent方法

  • 6、根據(jù)需要為你的自定義view提供自定義屬性,即編寫attr.xml,然后在代碼中通過TypedArray等類獲取到自定義屬性值

  • 7、需要處理滑動沖突、像素轉(zhuǎn)換等問題 談?wù)刅iew的繪制流程

談?wù)刅iew的繪制流程

measure()方法,layout(),draw()三個(gè)方法主要存放了一些標(biāo)識符,來判斷每個(gè)View是否需要再重新測量,布局或者繪制,主要的繪制過程還是在onMeasure,onLayout,onDraw這個(gè)三個(gè)方法中

  • 1.onMesarue() 為整個(gè)View樹計(jì)算實(shí)際的大小,即設(shè)置實(shí)際的高(對應(yīng)屬性:mMeasuredHeight)和寬(對應(yīng)屬性: mMeasureWidth),每個(gè)View的控件的實(shí)際寬高都是由父視圖和本身視圖決定的。

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

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

    • 首先繪制該View的背景

    • 調(diào)用onDraw()方法繪制視圖本身 (每個(gè)View都需要重載該方法,ViewGroup不需要實(shí)現(xiàn)該方法)

    • 如果該View是ViewGroup,調(diào)用dispatchDraw ()方法繪制子視圖 繪制滾動條

自定義View執(zhí)行invalidate()方法,為什么有時(shí)候不會回調(diào)onDraw()

  • 自定義一個(gè)view時(shí),重寫onDraw。調(diào)用view.invalidate(),會觸發(fā)onDraw和computeScroll()。前提是該view被附加在當(dāng)前窗口. view.postInvalidate(); //是在非UI線程上調(diào)用的

  • 自定義一個(gè)ViewGroup,重寫onDraw。onDraw可能不會被調(diào)用,原因是需要先設(shè)置一個(gè)背景(顏色或圖)。表示這個(gè)group有東西需要繪制了,才會觸發(fā)draw,之后是onDraw。因此,一般直接重寫dispatchDraw來繪制viewGroup.自定義一個(gè)ViewGroup,dispatchDraw會調(diào)用drawChild.

事件傳遞機(jī)制

談?wù)則ouch事件的傳遞流程

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

  • 事件類型分為ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每個(gè)事件都是以ACTION_DOWN開始ACTION_UP結(jié)束。

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

簡單來說:

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

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

  • 如果事件從上往下傳遞過程中一直沒有被停止,且最底層子View沒有消費(fèi)事件,事件會反向往上傳遞,這時(shí)父View(ViewGroup)可以進(jìn)行消費(fèi),如果還是沒有被消費(fèi)的話,最后會到Activity的onTouchEvent()函數(shù)。

  • 如果View沒有對ACTION_DOWN進(jìn)行消費(fèi),之后的其他事件不會傳遞過來。

= OnTouchListener優(yōu)先于onTouchEvent()對事件進(jìn)行消費(fèi)。 上面的消費(fèi)即表示相應(yīng)函數(shù)返回值為true。

View中setOnTouchListener中的onTouch,onTouchEvent,onClick的執(zhí)行順序

onTouch優(yōu)于onTouchEvent,onTouchEvent優(yōu)于onClick

觸摸事件的分發(fā)機(jī)制詳見:

Android觸摸事件分發(fā)機(jī)制完全解析《一》

什么是Dalvik虛擬機(jī)

  • Dalvik虛擬機(jī)是Android平臺的核心。

  • 它可以支持.dex格式的程序的運(yùn)行

  • .dex格式是專為Dalvik設(shè)計(jì)的一種壓縮格式

  • 可以減少整體文件尺寸

  • 提高I/O操作的速度

  • 適合內(nèi)存和處理器速度有限的系統(tǒng)

Dalvik虛擬機(jī)和JVM有什么區(qū)別

  • Dalvik 基于寄存器,而 JVM 基于棧?;诩拇嫫鞯奶摂M機(jī)對于更大的程序來說,在它們編譯的時(shí)候,花費(fèi)的時(shí)間更短。

  • Dalvik執(zhí)行.dex格式的字節(jié)碼,而JVM執(zhí)行.class格式的字節(jié)碼

Android為每個(gè)應(yīng)用程序分配的內(nèi)存大小是多少

  • 一般是16m或者24m,但是可以通過android:largeHeap申請更多內(nèi)存

具體參考:

[https://liuzhichao.com/2016/use-android_largeHeap.html]

[http://www.cnblogs.com/mythou/p/3203536.html]

如何解決方法數(shù)65k問題?

使用Android Studio 的gradle 可以構(gòu)建MutilDex




最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,118評論 25 709
  • 介紹自己負(fù)責(zé)的部分,如何實(shí)現(xiàn)的。 框架的搭建排查問題以及結(jié)解決方式兼容性保證性能優(yōu)化上線之后模塊導(dǎo)致crash的比...
    黃海佳閱讀 13,399評論 6 350
  • 1,java 接口的意義: 規(guī)范,擴(kuò)展,回調(diào) 規(guī)范:比如,有兩個(gè)及上的的類擁有相同的方法,但是實(shí)現(xiàn)功能不一樣,就可...
    漫唐閱讀 1,056評論 0 6
  • ——讀申賦漁《一個(gè)一個(gè)人》 有感 1990年,我出生在四川西南某著名貧困山村。 2009年,我懷揣某著名大學(xué)錄取通...
    路飛Luffy閱讀 518評論 0 1
  • 矛盾那么多
    TT平常心閱讀 253評論 0 0

友情鏈接更多精彩內(nèi)容