本地廣播在本應用范圍內(nèi)傳播,不用擔心隱私數(shù)據(jù)泄露,不用擔心別的應用偽造廣播.相比全局廣播,本地廣播更高效.
1.靜態(tài)注冊:在清單文件中注冊, 常見的有監(jiān)聽設(shè)備啟動,常駐注冊不會隨程序生命周期改變 2.動態(tài)注冊:在代碼中注冊,隨著程序的結(jié)束,也就停止接受廣播了
補充一點:有些廣播只能通過動態(tài)方式注冊,比如時間變化事件、屏幕亮滅事件、電量變更事件,因為這些事件觸發(fā)頻率通常很高,如果允許后臺監(jiān)聽,會導致進程頻繁創(chuàng)建和銷毀,從而影響系統(tǒng)整體性能
為什么Android引入廣播機制?
a:從MVC的角度考慮(應用程序內(nèi)) 其實回答這個問題的時候還可以這樣問,android為什么要有那4大組件,現(xiàn)在的移動開發(fā)模型基本上也是照搬的web那一套MVC架構(gòu),只不過是改了點嫁妝而已。android的四大組件本質(zhì)上就是為了實現(xiàn)移動或者說嵌入式設(shè)備上的MVC架構(gòu),它們之間有時候是一種相互依存的關(guān)系,有時候又是一種補充關(guān)系,引入廣播機制可以方便幾大組件的信息和數(shù)據(jù)交互。 b:程序間互通消息(例如在自己的應用程序內(nèi)監(jiān)聽系統(tǒng)來電) c:效率上(參考UDP的廣播協(xié)議在局域網(wǎng)的方便性) d:設(shè)計模式上(反轉(zhuǎn)控制的一種應用,類似監(jiān)聽者模式)
BroadCastReceiver的安全性問題
具體參見:[http://blog.csdn.net/t12x3456/article/details/9256609]
了解IntentServices嗎?
IntentService是Service的子類,是一個異步的,會自動停止的服務(wù),很好解決了傳統(tǒng)的Service中處理完耗時操作忘記停止并銷毀Service的問題
生成一個默認的且與線程相互獨立的工作線程執(zhí)行所有發(fā)送到onStartCommand()方法的Intent,可以在onHandleIntent()中處理.
串行隊列,每次只運行一個任務(wù),不存在線程安全問題,所有任務(wù)執(zhí)行完后自動停止服務(wù),不需要自己手動調(diào)用stopSelf()來停止.
Service的onCreate運行在哪個線程中?
UI線程
提升Service進程優(yōu)先級
在AndroidManifest.xml文件中對于intent-filter可以通過android:priority = “1000”這個屬性設(shè)置最高優(yōu)先級,1000是最高值,如果數(shù)字越小則優(yōu)先級越低,同時適用于廣播。
介紹Android下的數(shù)據(jù)存儲方式
SharedPreference內(nèi)部存儲外部存儲SQLite網(wǎng)絡(luò)存儲ContentProvider是如何實現(xiàn)數(shù)據(jù)共享
當一個應用程序需要把自己的數(shù)據(jù)暴露給其他程序使用時,該就用程序就可通過提供ContentProvider來實現(xiàn);其他應用程序就可通過ContentResolver來操作ContentProvider暴露的數(shù)據(jù)。 一旦某個應用程序通過ContentProvider暴露了自己的數(shù)據(jù)操作接口,那么不管該應用程序是否啟動,其他應用程序都可以通過該接口來操作該應用程序的內(nèi)部數(shù)據(jù),包括增加數(shù)據(jù)、刪除數(shù)據(jù)、修改數(shù)據(jù)、查詢數(shù)據(jù)等。
ContentProvider以某種Uri的形式對外提供數(shù)據(jù),允許其他應用訪問或修改數(shù)據(jù);其他應用程序使用ContentResolver根據(jù)Uri去訪問操作指定數(shù)據(jù)。 步驟: 1. 定義自己的ContentProvider類,該類需要繼承Android提供的ContentProvider基類。 2. 在AndroidManifest.xml文件中注冊個ContentProvider,注冊ContenProvider時需要為它綁定一個URL。 例: android:authorities=”com.myit.providers.MyProvider” /> 說明:authorities就相當于為該ContentProvider指定URL。 注冊后,其他應用程序就可以通過該Uri來訪問MyProvider所暴露的數(shù)據(jù)了。 3. 接下來,使用ContentResolver操作數(shù)據(jù),Context提供了如下方法來獲取ContentResolver對象。 一般來說,ContentProvider是單例模式,當多個應用程序通過ContentResolver來操作 ContentProvider提供的數(shù)據(jù)時,ContentResolver調(diào)用的數(shù)據(jù)操作將會委托給同一個ContentProvider處理。 使用ContentResolver操作數(shù)據(jù)只需兩步: 1、調(diào)用Activity的ContentResolver獲取ContentResolver對象。 2、根據(jù)需要調(diào)用ContentResolver的insert()、delete()、update()和query()方法操作數(shù)據(jù)即可
ContentProvider和sql的區(qū)別
ContentProvider的主要還是用于數(shù)據(jù)共享,其可以對Sqlite,SharePreferences,F(xiàn)ile等進行數(shù)據(jù)操作用來共享數(shù)據(jù)。而sql的可以理解為數(shù)據(jù)庫的一門語言,可以使用它完成CRUD等一系列的操作
數(shù)據(jù)存儲相關(guān)
文件存儲: 通過Java.io.FileInputStream和java.io.FileOutputStream這兩個類來實現(xiàn)對文件的讀寫,java.io.File類則用來構(gòu)造一個具體指向某個文件或者文件夾的對象。
SharedPreferences: SharedPreferences是一種輕量級的數(shù)據(jù)存儲機制,他將一些簡單的數(shù)據(jù)類型的數(shù)據(jù),包括boolean類型,int類型,float類型,long類型以及String類型的數(shù)據(jù),以鍵值對的形式存儲在應用程序的私有Preferences目錄(/data/data/<包名>/shared_prefs/)中,這種Preferences機制廣泛應用于存儲應用程序中的配置信息。
SQLite數(shù)據(jù)庫: 當應用程序需要處理的數(shù)據(jù)量比較大時,為了更加合理地存儲、管理、查詢數(shù)據(jù),我們往往使用關(guān)系數(shù)據(jù)庫來存儲數(shù)據(jù)。Android系統(tǒng)的很多用戶數(shù)據(jù),如聯(lián)系人信息,通話記錄,短信息等,都是存儲在SQLite數(shù)據(jù)庫當中的,所以利用操作SQLite數(shù)據(jù)庫的API可以同樣方便的訪問和修改這些數(shù)據(jù)。
ContentProvider: 主要用于在不同的應用程序之間實現(xiàn)數(shù)據(jù)共享的功能,不同于sharepreference和文件存儲中的兩種全局可讀寫操作模式,內(nèi)容提供其可以選擇只對哪一部分數(shù)據(jù)進行共享,從而保證我們程序中的隱私數(shù)據(jù)不會有泄漏的風險
如何導入外部數(shù)據(jù)庫?
如何將打開res aw目錄中的數(shù)據(jù)庫文件?
在Android中不能直接打開res aw目錄中的數(shù)據(jù)庫文件,而需要在程序第一次啟動時將該文件復制到手機內(nèi)存或SD卡的某個目錄中,然后再打開該數(shù)據(jù)庫文件。復制的基本方法是使用getResources().openRawResource方法獲得res aw目錄中資源的 InputStream對象,然后將該InputStream對象中的數(shù)據(jù)寫入其他的目錄中相應文件中。在Android SDK中可以使用SQLiteDatabase.openOrCreateDatabase方法來打開任意目錄中的SQLite數(shù)據(jù)庫文件。
一條最長的短信息約占多少byte?
中文70(包括標點),英文160,160個字節(jié)。
Context與applicationContext的區(qū)別,
Application的Context是一個全局靜態(tài)變量,SDK的說明是只有當你引用這個context的生命周期超過了當前activity的生命周期,而和整個應用的生命周期掛鉤時,才去使用這個application的context。 在android中context可以作很多操作,但是最主要的功能是加載和訪問資源。在android中有兩種context,一種是 application context,一種是activity context,通常我們在各種類和方法間傳遞的是activity context。
什么是aar?aar是jar有什么區(qū)別?
“aar”包是 Android 的類庫項目的二進制發(fā)行包。 文件擴展名是.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帶參數(shù)–output-text-symbols的輸出結(jié)果。 jar打包不能包含資源文件,比如一些drawable文件、xml資源文件之類的,aar可以。
SQLite支持事務(wù)嗎?添加刪除如何提高性能?
SQLite作為輕量級的數(shù)據(jù)庫,比MySQL還小,但支持SQL語句查詢,提高性能可以考慮通過原始經(jīng)過優(yōu)化的SQL查詢語句方式處理
SQLite優(yōu)化
參考:[http://www.cnblogs.com/devinzhang/archive/2012/01/16/2323949.html]
如何將SQLite數(shù)據(jù)庫(dictionary.db文件)與apk文件一起發(fā)布?
可以將dictionary.db文件復制到Eclipse Android工程中的res aw目錄中。所有在res aw目錄中的文件不會被壓縮,這樣可以直接提取該目錄中的文件。可以將dictionary.db文件復制到res aw目錄中
Webview中的漏洞
[http://jiajixin.cn/2014/09/16/webview-js-safety/]
Service和Activity通信
通過Binder通過broadcast如何保證Service在后臺不被kill
Service設(shè)置成START_STICKY kill 后會被重啟(等待5秒左右),重傳Intent,保持與重啟前一樣
通過 startForeground將進程設(shè)置為前臺進程, 做前臺服務(wù),優(yōu)先級和前臺應用一個級別?,除非在系統(tǒng)內(nèi)存非常缺,否則此進程不會被 kill
雙進程Service: 讓2個進程互相保護**,其中一個Service被清理后,另外沒被清理的進程可以立即重啟進程
QQ黑科技: 在應用退到后臺后,另起一個只有 1 像素的頁面停留在桌面上,讓自己保持前臺狀態(tài),保護自己不被后臺清理工具殺死
在已經(jīng)root的設(shè)備下,修改相應的權(quán)限文件,將App偽裝成系統(tǒng)級的應用 Android4.0系列的一個漏洞,已經(jīng)確認可行
用C編寫守護進程(即子進程) : Android系統(tǒng)中當前進程(Process)fork出來的子進程,被系統(tǒng)認為是兩個不同的進程。當父進程被殺死的時候,子進程仍然可以存活,并不受影響。鑒于目前提到的在Android->- Service層做雙守護都會失敗,我們可以fork出c進程,多進程守護。死循環(huán)在那檢查是否還存在,具體的思路如下(Android5.0以上的版本不可行)
用C編寫守護進程(即子進程),守護進程做的事情就是循環(huán)檢查目標進程是否存在,不存在則啟動它。在NDK環(huán)境中將1中編寫的C代碼編譯打包成可執(zhí)行文件(BUILD_EXECUTABLE)。主進程啟動時將守護進程放入私有目錄下,賦予可執(zhí)行權(quán)限,啟動它即可。
聯(lián)系廠商,加入白名單
談?wù)勀銓ndroid中Context的理解
參考:[http://blog.csdn.net/qinjuning/article/details/7310620]
RemoteView的應用
widget和Notification中
Android中如何獲得手機的唯一標示.
1 首先嘗試讀取IMEI、Mac地址、CPU號等物理信息(有不少工具可以修改IMEI); 2 如果均失敗,可以自己生成UUID然后保存到文件(文件也可能被篡改或刪除)
參考:[http://blog.csdn.net/xushuaic/article/details/25077179]
Android應用中驗證碼登錄都有哪些實現(xiàn)方案
驗證碼應該只有兩種獲取方式: 從服務(wù)器端獲取圖片, 通過短信服務(wù),將驗證碼發(fā)送給客戶端這兩種
為什么要設(shè)計Bundle而不是直接使用Map?
Map里實現(xiàn)了Serializable接口,而在Bundle實現(xiàn)了Parcelable的接口 Bundle 父類 BaseBundle內(nèi)部確實有個 ArrayMap
Android中XML解析方式的比較急優(yōu)缺點
DOM,SAX,Pull解析。 SAX解析器的優(yōu)點是解析速度快,占用內(nèi)存少; DOM在內(nèi)存中以樹形結(jié)構(gòu)存放,因此檢索和更新效率會更高。但是對于特別大的文檔,解析和加載整個文檔將會很耗資源,不適合移動端; PULL解析器的運行方式和SAX類似,都是基于事件的模式,PULL解析器小巧輕便,解析速度快,簡單易用,非常適合在Android移動設(shè)備中使用,Android系統(tǒng)內(nèi)部在解析各種XML時也是用PULL解析器。
布局相關(guān)
LinearLayout和RelativeLayout性能對比
1 RelativeLayout會讓子View調(diào)用2次onMeasure,LinearLayout 在有weight時,也會調(diào)用子View2次onMeasure 2 RelativeLayout的子View如果高度和RelativeLayout不同,則會引發(fā)效率問題,當子View很復雜時,這個問題會更加嚴重。如果可以,盡量使用padding代替margin。 3 在不影響層級深度的情況下,使用LinearLayout和FrameLayout而不是RelativeLayout。 最后再思考一下文章開頭那個矛盾的問題,為什么Google給開發(fā)者默認新建了個RelativeLayout,而自己卻在DecorView中用了個LinearLayout。因為DecorView的層級深度是已知而且固定的,上面一個標題欄,下面一個內(nèi)容欄。采用RelativeLayout并不會降低層級深度,所以此時在根節(jié)點上用LinearLayout是效率最高的。而之所以給開發(fā)者默認新建了個RelativeLayout是希望開發(fā)者能采用盡量少的View層級來表達布局以實現(xiàn)性能最優(yōu),因為復雜的View嵌套對性能的影響會更大一些。
屏幕適配相關(guān)
dp, dip, dpi, px, sp是什么意思以及他們的換算公式?layout-sw400dp, layout-h400dp分別代表什么意思
布局優(yōu)化
避免OverDraw過渡繪制優(yōu)化布局層級避免嵌套過多無用布局當我們在畫布局的時候,如果能實現(xiàn)相同的功能,優(yōu)先考慮相對布局,然后在考慮別的布局,不要用絕對布局。使用<include />標簽把復雜的界面需要抽取出來使用<merge />標簽,因為它在優(yōu)化UI結(jié)構(gòu)時起到很重要的作用。目的是通過刪減多余或者額外的層級,從而優(yōu)化整個Android Layout的結(jié)構(gòu)。核心功能就是減少冗余的層次從而達到優(yōu)化UI的目的!ViewStub 是一個隱藏的,不占用內(nèi)存空間的視圖對象,它可以在運行時延遲加載布局資源文件。mipmap文件夾和drawable文件夾的區(qū)別
它只是用來放啟動圖標的,好處就是,你只用放一個mipmap圖標,它就會給你各種版本(比如平板,手機)的apk自動生成相應分辨率的圖標,以節(jié)約空間。
ListView卡頓的原因以及優(yōu)化策略
重用converView: 通過復用converview來減少不必要的view的創(chuàng)建,另外Infalte操作會把xml文件實例化成相應的View實例,屬于IO操作,是耗時操作。
減少findViewById()操作: 將xml文件中的元素封裝成viewholder靜態(tài)類,通過converview的setTag和getTag方法將view與相應的holder對象綁定在一起,避免不必要的findviewbyid操作
避免在 getView 方法中做耗時的操作: 例如加載本地 Image 需要載入內(nèi)存以及解析 Bitmap ,都是比較耗時的操作,如果用戶快速滑動listview,會因為getview邏輯過于復雜耗時而造成滑動卡頓現(xiàn)象。用戶滑動時候不要加載圖片,待滑動完成再加載,可以使用這個第三方庫glide
Item的布局層次結(jié)構(gòu)盡量簡單,避免布局太深或者不必要的重繪
盡量能保證 Adapter 的 hasStableIds() 返回 true 這樣在 notifyDataSetChanged() 的時候,如果item內(nèi)容并沒有變化,ListView 將不會重新繪制這個 View,達到優(yōu)化的目的
在一些場景中,ScollView內(nèi)會包含多個ListView,可以把listview的高度寫死固定下來。 由于ScollView在快速滑動過程中需要大量計算每一個listview的高度,阻塞了UI線程導致卡頓現(xiàn)象出現(xiàn),如果我們每一個item的高度都是均勻的,可以通過計算把listview的高度確定下來,避免卡頓現(xiàn)象出現(xiàn)
使用 RecycleView 代替listview: 每個item內(nèi)容的變動,listview都需要去調(diào)用notifyDataSetChanged來更新全部的item,太浪費性能了。RecycleView可以實現(xiàn)當個item的局部刷新,并且引入了增加和刪除的動態(tài)效果,在性能上和定制上都有很大的改善
ListView 中元素避免半透明: 半透明繪制需要大量乘法計算,在滑動時不停重繪會造成大量的計算,在比較差的機子上會比較卡。 在設(shè)計上能不半透明就不不半透明。實在要弄就把在滑動的時候把半透明設(shè)置成不透明,滑動完再重新設(shè)置成半透明。
盡量開啟硬件加速: 硬件加速提升巨大,避免使用一些不支持的函數(shù)導致含淚關(guān)閉某個地方的硬件加速。當然這一條不只是對 ListView。
如何實現(xiàn)一個局部更新的ListView
如何實現(xiàn)ListView多種布局
ViewHolder為什么要被聲明成靜態(tài)內(nèi)部類
這個是考靜態(tài)內(nèi)部類和非靜態(tài)內(nèi)部類的主要區(qū)別之一。非靜態(tài)內(nèi)部類會隱式持有外部類的引用,就像大家經(jīng)常將自定義的adapter在Activity類里,然后在adapter類里面是可以隨意調(diào)用外部activity的方法的。當你將內(nèi)部類定義為static時,你就調(diào)用不了外部類的實例方法了,因為這時候靜態(tài)內(nèi)部類是不持有外部類的引用的。聲明ViewHolder靜態(tài)內(nèi)部類,可以將ViewHolder和外部類解引用。大家會說一般ViewHolder都很簡單,不定義為static也沒事吧。確實如此,但是如果你將它定義為static的,說明你懂這些含義。萬一有一天你在這個ViewHolder加入一些復雜邏輯,做了一些耗時工作,那么如果ViewHolder是非靜態(tài)內(nèi)部類的話,就很容易出現(xiàn)內(nèi)存泄露。如果是靜態(tài)的話,你就不能直接引用外部類,迫使你關(guān)注如何避免相互引用。 所以將 ViewHolder內(nèi)部類 定義為靜態(tài)的,是一種好習慣
進程,線程
有哪些進程通信的方式?
IntentBinder(AIDLMessengerBroadcastReceiverAIDL是什么?
AIDL全程是Android Interface Definition Language,用于生成兩個進程之間通信(IPC)的代碼.
AIDL 體現(xiàn)了哪些設(shè)計思想
代理
Binder機制
很多人吧Binder的原理解釋的很復雜,讓人看著就頭大,但是熟悉linux開發(fā)的小伙伴可以一下想到Binder驅(qū)動本質(zhì)就是文件,實現(xiàn)采用了代理而已.具體看下圖: 
簡單的說說Handler機制
Handler通過調(diào)用sendmessage方法把消息放在消息隊列MessageQueue中,Looper負責把消息從消息隊列中取出來,重新再交給Handler進行處理,三者形成一個循環(huán)通過構(gòu)建一個消息隊列,把所有的Message進行統(tǒng)一的管理,當Message不用了,并不作為垃圾回收,而是放入消息隊列中,供下次handler創(chuàng)建消息時候使用,提高了消息對象的復用,減少系統(tǒng)垃圾回收的次數(shù)每一個線程,都會單獨對應的一個looper,這個looper通過ThreadLocal來創(chuàng)建,保證每個線程只創(chuàng)建一個looper,looper初始化后就會調(diào)用looper.loop創(chuàng)建一個MessageQueue,這個方法在UI線程初始化的時候就會完成,我們不需要手動創(chuàng)建
動畫相關(guān)
Android中的動畫有哪些?
逐幀動畫(Drawable Animation): 加載一系列Drawable資源來創(chuàng)建動畫,簡單來說就是播放一系列的圖片來實現(xiàn)動畫效果,可以自定義每張圖片的持續(xù)時間
補間動畫(Tween Animation): Tween可以對View對象實現(xiàn)一系列簡單的動畫效果,比如位移,縮放,旋轉(zhuǎn),透明度等等。但是它并不會改變View屬性的值,只是改變了View的繪制的位置,比如,一個按鈕在動畫過后,不在原來的位置,但是觸發(fā)點擊事件的仍然是原來的坐標。
屬性動畫(Property Animation): 動畫的對象除了傳統(tǒng)的View對象,還可以是Object對象,動畫結(jié)束后,Object對象的屬性值被實實在在的改變了
Android動畫原理
Animation框架定義了透明度,旋轉(zhuǎn),縮放和位移幾種常見的動畫,而且控制的是整個View,實現(xiàn)原理是每次繪制視圖時View所在的ViewGroup中的drawChild函數(shù)獲取該View的Animation的Transformation值,然后調(diào)用canvas.concat(transformToApply.getMatrix()),通過矩陣運算完成動畫幀,如果動畫沒有完成,繼續(xù)調(diào)用invalidate()函數(shù),啟動下次繪制來驅(qū)動動畫,動畫過程中的幀之間間隙時間是繪制函數(shù)所消耗的時間,可能會導致動畫消耗比較多的CPU資源,最重要的是,動畫改變的只是顯示,并不能相應事件
Android屬性動畫特性
如果你的需求中只需要對View進行移動、縮放、旋轉(zhuǎn)和淡入淡出操作,那么補間動畫確實已經(jīng)足夠健全了。但是很顯然,這些功能是不足以覆蓋所有的場景的,一旦我們的需求超出了移動、縮放、旋轉(zhuǎn)和淡入淡出這四種對View的操作,那么補間動畫就不能再幫我們忙了,也就是說它在功能和可擴展方面都有相當大的局限性,那么下面我們就來看看補間動畫所不能勝任的場景。 注意上面我在介紹補間動畫的時候都有使用“對View進行操作”這樣的描述,沒錯,補間動畫是只能夠作用在View上的。也就是說,我們可以對一個Button、TextView、甚至是LinearLayout、或者其它任何繼承自View的組件進行動畫操作,但是如果我們想要對一個非View的對象進行動畫操作,抱歉,補間動畫就幫不上忙了。可能有的朋友會感到不能理解,我怎么會需要對一個非View的對象進行動畫操作呢?這里我舉一個簡單的例子,比如說我們有一個自定義的View,在這個View當中有一個Point對象用于管理坐標,然后在onDraw()方法當中就是根據(jù)這個Point對象的坐標值來進行繪制的。也就是說,如果我們可以對Point對象進行動畫操作,那么整個自定義View的動畫效果就有了。顯然,補間動畫是不具備這個功能的,這是它的第一個缺陷。 然后補間動畫還有一個缺陷,就是它只能夠?qū)崿F(xiàn)移動、縮放、旋轉(zhuǎn)和淡入淡出這四種動畫操作,那如果我們希望可以對View的背景色進行動態(tài)地改變呢?很遺憾,我們只能靠自己去實現(xiàn)了。說白了,之前的補間動畫機制就是使用硬編碼的方式來完成的,功能限定死就是這些,基本上沒有任何擴展性可言。 最后,補間動畫還有一個致命的缺陷,就是它只是改變了View的顯示效果而已,而不會真正去改變View的屬性。什么意思呢?比如說,現(xiàn)在屏幕的左上角有一個按鈕,然后我們通過補間動畫將它移動到了屏幕的右下角,現(xiàn)在你可以去嘗試點擊一下這個按鈕,點擊事件是絕對不會觸發(fā)的,因為實際上這個按鈕還是停留在屏幕的左上角,只不過補間動畫將這個按鈕繪制到了屏幕的右下角而已。
View繪制相關(guān)
SurfaceView和View的區(qū)別
SurfaceView中采用了雙緩存技術(shù),在單獨的線程中更新界面 View在UI線程中更新界面
介紹下自定義view的基本流程
明確需求,確定你想實現(xiàn)的效果確定是使用組合控件的形式還是全新自定義的形式,組合控件即使用多個系統(tǒng)控件來合成一個新控件,你比如titilebar,這種形式相對簡單,參考如果是完全自定義一個view的話,你首先需要考慮繼承哪個類,是View呢,還是ImageView等子類。根據(jù)需要去復寫View#onDraw、View#onMeasure、View#onLayout方法根據(jù)需要去復寫dispatchTouchEvent、onTouchEvent方法根據(jù)需要為你的自定義view提供自定義屬性,即編寫attr.xml,然后在代碼中通過TypedArray等類獲取到自定義屬性值 7.需要處理滑動沖突、像素轉(zhuǎn)換等問題談?wù)刅iew的繪制流程
measure()方法,layout(),draw()三個方法主要存放了一些標識符,來判斷每個View是否需要再重新測量,布局或者繪制,主要的繪制過程還是在onMeasure,onLayout,onDraw這個三個方法中
1.onMesarue() 為整個View樹計算實際的大小,即設(shè)置實際的高(對應屬性:mMeasuredHeight)和寬(對應屬性: mMeasureWidth),每個View的控件的實際寬高都是由父視圖和本身視圖決定的。
2.onLayout() 為將整個根據(jù)子視圖的大小以及布局參數(shù)將View樹放到合適的位置上。
3. onDraw() 開始繪制圖像,繪制的流程如下
首先繪制該View的背景調(diào)用onDraw()方法繪制視圖本身 (每個View都需要重載該方法,ViewGroup不需要實現(xiàn)該方法)如果該View是ViewGroup,調(diào)用dispatchDraw ()方法繪制子視圖繪制滾動條自定義View執(zhí)行invalidate()方法,為什么有時候不會回調(diào)onDraw()
自定義一個view時,重寫onDraw。調(diào)用view.invalidate(),會觸發(fā)onDraw和computeScroll()。前提是該view被附加在當前窗口. view.postInvalidate(); //是在非UI線程上調(diào)用的
自定義一個ViewGroup,重寫onDraw。onDraw可能不會被調(diào)用,原因是需要先設(shè)置一個背景(顏色或圖)。表示這個group有東西需要繪制了,才會觸發(fā)draw,之后是onDraw。因此,一般直接重寫dispatchDraw來繪制viewGroup.自定義一個ViewGroup,dispatchDraw會調(diào)用drawChild.
如何實現(xiàn)一個字體的描邊與陰影效果
事件傳遞機制
談?wù)則ouch事件的傳遞流程
1. 所有Touch事件都被封裝成了MotionEvent對象,包括Touch的位置、時間、歷史記錄以及第幾個手指(多指觸摸)等。 2. 事件類型分為ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每個事件都是以ACTION_DOWN開始ACTION_UP結(jié)束。 3. 對事件的處理包括三類,分別為傳遞——dispatchTouchEvent()函數(shù)、攔截——onInterceptTouchEvent()函數(shù)、消費——onTouchEvent()函數(shù)和OnTouchListener()
簡單來說:
事件從Activity.dispatchTouchEvent()開始傳遞,只要沒有被停止或攔截,從最上層的View(ViewGroup)開始一直往下(子View)傳遞。子View可以通過onTouchEvent()對事件進行處理。
事件由父View(ViewGroup)傳遞給子View,ViewGroup可以通過onInterceptTouchEvent()對事件做攔截,停止其往下傳遞。
如果事件從上往下傳遞過程中一直沒有被停止,且最底層子View沒有消費事件,事件會反向往上傳遞,這時父View(ViewGroup)可以進行消費,如果還是沒有被消費的話,最后會到Activity的onTouchEvent()函數(shù)。
如果View沒有對ACTION_DOWN進行消費,之后的其他事件不會傳遞過來。
OnTouchListener優(yōu)先于onTouchEvent()對事件進行消費。 上面的消費即表示相應函數(shù)返回值為true。
View中setOnTouchListener中的onTouch,onTouchEvent,onClick的執(zhí)行順序
onTouch優(yōu)于onTouchEvent,onTouchEvent優(yōu)于onClick
Android下滑沖突的常見解決思路
相關(guān)的滑動組件 重寫onInterceptTouchEvent,然后判斷根據(jù)xy值,來決定是否要攔截當前操作
高效使用Bitmap
談?wù)勀銓itmap的理解,以及什么時候該bitmap.recycle()
Bitmap是android中經(jīng)常使用的一個類,它代表了一個圖片資源。 Bitmap消耗內(nèi)存很嚴重,如果不注意優(yōu)化代碼,經(jīng)常會出現(xiàn)OOM問題,優(yōu)化方式通常有這么幾種: 1. 使用緩存; 2. 壓縮圖片; 3. 及時回收;
至于什么時候需要手動調(diào)用recycle,這就看具體場景了,原則是當我們不再使用Bitmap時,需要回收。另外,我們需要注意,2.3之前Bitmap對象與像素數(shù)據(jù)是分開存放的,Bitmap對象存在Java Heap中而像素數(shù)據(jù)存放在Native Memory中,這時很有必要調(diào)用recycle回收內(nèi)存。但是2.3之后,Bitmap對象和像素數(shù)據(jù)都是存在Heap中,GC可以回收其內(nèi)存。
反射相關(guān)
什么時候會用到反射?
JAVA反射機制是在#運行時#,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意一個方法;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機制。 Java反射機制主要提供了以下功能: a)在運行時判斷任意一個對象所屬的類; b)在運行時構(gòu)造任意一個類的對象; c)在運行時判斷任意一個類所具有的成員變量和方法; d)在運行時調(diào)用任意一個對象的方法;生成動態(tài)代理。
你曾經(jīng)利用反射做過什么?
JNI系列
NDK是什么?
NDK是一些列工具的集合, NDK提供了一系列的工具,幫助開發(fā)者迅速的開發(fā)C/C++的動態(tài)庫,并能自動將so和java 應用打成apk包。 NDK集成了交叉編譯器,并提供了相應的mk文件和隔離cpu、平臺等的差異,開發(fā)人員只需簡單的修改mk文件就可以創(chuàng)建出so
Android ndk主要在哪些場景下使用?有啥坑?
加密音視頻解碼圖像操作安全相關(guān),比如hookt增量更新游戲開發(fā)NDK開發(fā)需要注意什么?
[https://developer.android.com/training/articles/perf-jni.html]
使用JNI的流程?
JAVA中聲明native 方法如private native String printJNI(String inputStr);使用javah工具生成.h頭文件這時候頭文件中就會自動生成對應的函數(shù)JNIEXPORT jstring JNICALL Java_com_wenming_HelloWorld_printJNI實現(xiàn)JNI原生函數(shù)源文件,新建HelloWorld.c文件,對剛才自動生成的函數(shù)進行具體的邏輯書寫,例如返回一個java叫做HelloWorld的字符串等編譯生成動態(tài)鏈接so文件**Java中調(diào)用Sysytem.load方法把剛才的so庫加載進來,就可以調(diào)用native方法了如何通過JNI傳遞String對象
Java的String和C++的string是不能對等起來的,所以當我們拿到.h文件下面的jstring對象,會做一次轉(zhuǎn)換我們把jstring轉(zhuǎn)換為C下面的char*類型, 獲取值 constchar* str; str = env->GetStringUTFChars(prompt,false); 賦予值 char* tmpstr ="return string succeeded"; jstring rtstr = env->NewStringUTF(tmpstr);
網(wǎng)絡(luò)優(yōu)化
移動端獲取數(shù)據(jù)優(yōu)化的幾個點
連接復用 : 節(jié)省連接建立時間,如開啟 keep-alive。 對于 Android 來說默認情況下 HttpURLConnection 和 HttpClient 都開啟了 keep-alive。只是 2.2 之前 HttpURLConnection 存在影響連接池的 Bug,具體可見:Android HttpURLConnection 及 HttpClient 選擇請求合并: 即將多個請求合并為一個進行請求,比較常見的就是網(wǎng)頁中的 CSS Image Sprites。如果某個頁面內(nèi)請求過多,也可以考慮做一定的請求合并。減少請求數(shù)據(jù)的大小: 對于post請求,body可以做gzip壓縮的,header也可以作數(shù)據(jù)壓縮(不過只支持http 2.0)。返回的數(shù)據(jù)的body也可以作gzip壓縮,body數(shù)據(jù)體積可以縮小到原來的30%左右。(也可以考慮壓縮返回的json數(shù)據(jù)的key數(shù)據(jù)的體積,尤其是針對返回數(shù)據(jù)格式變化不大的情況,支付寶聊天返回的數(shù)據(jù)用到了)根據(jù)用戶的當前的網(wǎng)絡(luò)質(zhì)量來判斷下載什么質(zhì)量的圖片(電商用的比較多)。如何設(shè)計一個良好的網(wǎng)絡(luò)層?
[http://blog.csdn.net/column/details/simple-net.html]
如何防止重復發(fā)送網(wǎng)絡(luò)請求
點擊activity上的一個按鈕,發(fā)送網(wǎng)絡(luò)請求,在網(wǎng)絡(luò)比較慢的情況下,用戶可能會繼續(xù)去點擊按鈕,這個時候,發(fā)送其他無謂的請求,不知道大家是怎么處理這類問題來攔截? HTTP header中加入max-age,這樣某個固定的時間內(nèi)都將返回empty body,當然這個方法是死的,把時間完全限制了,這個方法回掉也會同樣要執(zhí)行多次。 還有個暈招,就是直接設(shè)置按鈕的clickable為false,或者使用progressbar,類似于樓主的方法,比如點贊的場景。 使用Map的話,在回掉的時候,還是需要回收HashMap的,維護Map還不如只維護一個boolean呢。 Volley中如果開了緩存的話, 相同的請求同時只會有一個去真正的請求, 后續(xù)都走緩存, 雖然不會請求多次, 但是回調(diào)是會執(zhí)行多次的, 和這個需求不match
如何實現(xiàn)wap聯(lián)網(wǎng)
參考:[http://blog.csdn.net/asce1885/article/details/7844159]
測試與調(diào)試
如何調(diào)試Android應用程序
Debug Log
Android中常用的測試工具?
內(nèi)存分析:mat,ddms,leakcanary 靜態(tài)分析:find bugs 壓力測試:monkey 自動化測試:UIAutomatorMonkeyRunner,Rubotium
內(nèi)存泄漏/內(nèi)存溢出相關(guān)
內(nèi)存泄漏問題
資源對象沒有關(guān)閉造成,如查詢數(shù)據(jù)庫沒有關(guān)閉游標構(gòu)造Adapter時,沒有使用緩存ConvertViewBitmap對象在不使用時調(diào)用recycle()釋放內(nèi)存context逃逸問題注冊沒有取消,如動態(tài)注冊廣播在Activity銷毀前沒有unregisterReceiver集合對象未清理,如無用時沒有釋放對象的引用在Activity中使用非靜態(tài)的內(nèi)部類,并開啟一個長時間運行的線程,因為內(nèi)部類持有Activity的引用,會導致Activity本來可以被gc時卻長期得不到回收哪些情況下發(fā)生OOM
類的靜態(tài)變量持有大數(shù)據(jù)對象 靜態(tài)變量長期維持到大數(shù)據(jù)對象的引用,阻止垃圾回收。
非靜態(tài)內(nèi)部類存在靜態(tài)實例 非靜態(tài)內(nèi)部類會維持一個到外部類實例的引用,如果非靜態(tài)內(nèi)部類的實例是靜態(tài)的,就會間接長期維持著外部類的引用,阻止被回收掉。
資源對象未關(guān)閉 資源性對象比如(Cursor,F(xiàn)ile文件等)往往都用了一些緩沖,我們在不使用的時候,應該及時關(guān)閉它們, 以便它們的緩沖及時回收內(nèi)存。它們的緩沖不僅存在于java虛擬機內(nèi),還存在于java虛擬機外。 如果我們僅僅是把它的引用設(shè)置為null,而不關(guān)閉它們,往往會造成內(nèi)存泄露。 解決辦法: 比如SQLiteCursor(在析構(gòu)函數(shù)finalize(),如果我們沒有關(guān)閉它,它自己會調(diào)close()關(guān)閉), 如果我們沒有關(guān)閉它,系統(tǒng)在回收它時也會關(guān)閉它,但是這樣的效率太低了。 因此對于資源性對象在不使用的時候,應該調(diào)用它的close()函數(shù),將其關(guān)閉掉,然后才置為null. 在我們的程序退出時一定要確保我們的資源性對象已經(jīng)關(guān)閉。 程序中經(jīng)常會進行查詢數(shù)據(jù)庫的操作,但是經(jīng)常會有使用完畢Cursor后沒有關(guān)閉的情況。如果我們的查詢結(jié)果集比較小, 對內(nèi)存的消耗不容易被發(fā)現(xiàn),只有在常時間大量操作的情況下才會復現(xiàn)內(nèi)存問題,這樣就會給以后的測試和問題排查帶來困難和風險,記得try catch后,在finally方法中關(guān)閉連接
Handler內(nèi)存泄漏 Handler作為內(nèi)部類存在于Activity中,但是Handler生命周期與Activity生命周期往往并不是相同的,比如當Handler對象有Message在排隊,則無法釋放,進而導致本該釋放的Acitivity也沒有辦法進行回收。 解決辦法:
聲明handler為static類,這樣內(nèi)部類就不再持有外部類的引用了,就不會阻塞Activity的釋放如果內(nèi)部類實在需要用到外部類的對象,可在其內(nèi)部聲明一個弱引用引用外部類一些不良代碼習慣 有些代碼并不造成內(nèi)存泄露,但是他們的資源沒有得到重用,頻繁的申請內(nèi)存和銷毀內(nèi)存,消耗CPU資源的同時,也引起內(nèi)存抖動 解決方案 如果需要頻繁的申請內(nèi)存對象和和釋放對象,可以考慮使用對象池來增加對象的復用。 例如ListView便是采用這種思想,通過復用converview來避免頻繁的GC
如何排查OOM
參見:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0920/3478.html
如何避免OOM
1. 使用更加輕量的數(shù)據(jù)結(jié)構(gòu) 例如,我們可以考慮使用ArrayMap/SparseArray而不是HashMap等傳統(tǒng)數(shù)據(jù)結(jié)構(gòu)。通常的HashMap的實現(xiàn)方式更加消耗內(nèi)存,因為它需要一個額外的實例對象來記錄Mapping操作。另外,SparseArray更加高效,在于他們避免了對key與value的自動裝箱(autoboxing),并且避免了裝箱后的解箱。
2. 避免在Android里面使用Enum Android官方培訓課程提到過“Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.”,具體原理請參考《Android性能優(yōu)化典范(三)》,所以請避免在Android里面使用到枚舉。
3. 減小Bitmap對象的內(nèi)存占用 Bitmap是一個極容易消耗內(nèi)存的大胖子,減小創(chuàng)建出來的Bitmap的內(nèi)存占用可謂是重中之重,,通常來說有以下2個措施: inSampleSize:縮放比例,在把圖片載入內(nèi)存之前,我們需要先計算出一個合適的縮放比例,避免不必要的大圖載入。 decode format:解碼格式,選擇ARGB_6666/RBG_545/ARGB_4444/ALPHA_6,存在很大差異
4.Bitmap對象的復用 縮小Bitmap的同時,也需要提高BitMap對象的復用率,避免頻繁創(chuàng)建BitMap對象,復用的方法有以下2個措施 LRUCache : “最近最少使用算法”在Android中有極其普遍的應用。ListView與GridView等顯示大量圖片的控件里,就是使用LRU的機制來緩存處理好的Bitmap,把近期最少使用的數(shù)據(jù)從緩存中移除,保留使用最頻繁的數(shù)據(jù), inBitMap高級特性:利用inBitmap的高級特性提高Android系統(tǒng)在Bitmap分配與釋放執(zhí)行效率。使用inBitmap屬性可以告知Bitmap解碼器去嘗試使用已經(jīng)存在的內(nèi)存區(qū)域,新解碼的Bitmap會嘗試去使用之前那張Bitmap在Heap中所占據(jù)的pixel data內(nèi)存區(qū)域,而不是去問內(nèi)存重新申請一塊區(qū)域來存放Bitmap。利用這種特性,即使是上千張的圖片,也只會僅僅只需要占用屏幕所能夠顯示的圖片數(shù)量的內(nèi)存大小
4. 使用更小的圖片 在涉及給到資源圖片時,我們需要特別留意這張圖片是否存在可以壓縮的空間,是否可以使用更小的圖片。盡量使用更小的圖片不僅可以減少內(nèi)存的使用,還能避免出現(xiàn)大量的InflationException。假設(shè)有一張很大的圖片被XML文件直接引用,很有可能在初始化視圖時會因為內(nèi)存不足而發(fā)生InflationException,這個問題的根本原因其實是發(fā)生了OOM。
5.StringBuilder 在有些時候,代碼中會需要使用到大量的字符串拼接的操作,這種時候有必要考慮使用StringBuilder來替代頻繁的“+”。
4.避免在onDraw方法里面執(zhí)行對象的創(chuàng)建 類似onDraw等頻繁調(diào)用的方法,一定需要注意避免在這里做創(chuàng)建對象的操作,因為他會迅速增加內(nèi)存的使用,而且很容易引起頻繁的gc,甚至是內(nèi)存抖動。
5. 避免對象的內(nèi)存泄露 android中內(nèi)存泄漏的場景以及解決辦法,參考上一問
ANR錯誤
什么是ANR
ANR全稱Application Not Responding,意思就是程序未響應。如果一個應用無法響應用戶的輸入,系統(tǒng)就會彈出一個ANR對話框,用戶可以自行選擇繼續(xù)等待亦或者是停止當前程序。一旦出現(xiàn)下面兩種情況,則彈出ANR對話框 1. 應用在5秒內(nèi)未響應用戶的輸入事件(如按鍵或者觸摸) 2. BroadcastReceiver未在10秒內(nèi)完成相關(guān)的處理
Service在特定的時間內(nèi)無法處理完成 超時的原因一般有兩種: (1)當前的事件沒有機會得到處理(UI線程正在處理前一個事件沒有及時完成或者looper被某種原因阻塞住) (2)當前的事件正在處理,但沒有及時完成 UI線程盡量只做跟UI相關(guān)的工作,耗時的工作(數(shù)據(jù)庫操作,I/O,連接網(wǎng)絡(luò)或者其他可能阻礙UI線程的操作)放入單獨的線程處理,盡量用Handler來處理UI thread和thread之間的交互。 UI線程主要包括如下: ? Activity:onCreate(), onResume(), onDestroy(), onKeyDown(), onClick() ? AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel() ? Mainthread handler: handleMessage(), post(runnable r)
如何定位ANR錯誤
開發(fā)機器上,查看/data/anr/traces.text.最新的ANR信息在最開始部分.
如何避免ANR
避免ANR最核心的一點就是在主線程減少耗時操作.通常需要從以下幾個方案下手:
使用子線程處理耗時IO操作。
降低子線程優(yōu)先級使用Thread或者HandlerThread時,調(diào)用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)設(shè)置優(yōu)先級,否則仍然會降低程序響應,因為默認Thread的優(yōu)先級和主線程相同。
使用Handler處理子線程結(jié)果,而不是使用Thread.wait()或者Thread.sleep()來阻塞主線程。
Activity的onCreate和onResume回調(diào)中盡量避免耗時的代碼
BroadcastReceiver中onReceive代碼也要盡量減少耗時操作建議使用IntentService處理。IntentService是一個異步的,會自動停止的服務(wù),很好解決了傳統(tǒng)的Service中處理完耗時操作忘記停止并銷毀Service的問題
安全相關(guān)
本地存儲的數(shù)據(jù)怎么加密好?比如:shared_prefs,sqlite數(shù)據(jù),用戶名,密碼等.如果是aes加密,怎么保存key?
密碼不要存在本地,一般保存token。最基本的要代碼混淆,可以的話加殼,防止反編譯
系統(tǒng)相關(guān)
Android各版本API區(qū)別
參考:[http://blog.csdn.net/lijun952048910/article/details/7980562]
什么是Dalvik虛擬機
Dalvik虛擬機是Android平臺的核心。它可以支持.dex格式的程序的運行,.dex格式是專為Dalvik設(shè)計的一種壓縮格式,可以減少整體文件尺寸,提高I/O操作的速度,適合內(nèi)存和處理器速度有限的系統(tǒng)
Dalvik虛擬機和JVM有什么區(qū)別
Dalvik 基于寄存器,而 JVM 基于棧。基于寄存器的虛擬機對于更大的程序來說,在它們編譯的時候,花費的時間更短。Dalvik執(zhí)行.dex格式的字節(jié)碼,而JVM執(zhí)行.class格式的字節(jié)碼Android為每個應用程序分配的內(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
Android系統(tǒng)啟動流程分析
打開adb shell 然后執(zhí)行ps命令,可以看到首先執(zhí)行的是init方法!找到init.c這個文件.然后走init里面的main方法,在這main方法里面執(zhí)行mkdir進行創(chuàng)建很多的文件夾,和掛載一些目錄然后回去初始化init.rc這個配置文件!在這個配置文件里面回去啟動孵化器這個服務(wù),這個服務(wù)會去啟動app_process這個文件夾,這個文件夾里面有個app_main.cpp這個文件!然后在app_main.cpp這個c文件里面在main方法里面它會去啟動安卓的虛擬機,然后安卓虛擬機會去啟動os.zygoteinit這個服務(wù)!zygoteinit這是個java代碼寫的,然后我們找到了main方法,在這個方法里面我們看到他首先設(shè)置虛擬機的最小堆內(nèi)存為5兆,然后走到preloadclasses()這個方法來加載安卓系統(tǒng)所有的2000多個類通過類加載器加載進來,比如activity,contentx,http,…(其實沒有必要一下子全部加載下來,我們可以等用到的時候在加載也可以!)然后又走preloadresources()這個方法來預加載安卓中定義好的資源比如顏色,圖片,系統(tǒng)的id等等。。。都加載了!(其實這也是沒必要的! )然后又走startSystemServer(),這個方法來加載系統(tǒng)的服務(wù)!他會先使用natvieJNI去調(diào)用C去初始化界面和聲音的服務(wù),這就是我們?yōu)槭裁聪嚷牭铰曇艉徒缑娴脑颍∽詈蟮确?wù)加載完成后也就啟動起來了!總結(jié) linux啟動->init進程啟動(加載init.rc配置)->zygote啟動->systemServer啟動,systemServer會通過init1和init2啟動navite世界和java世界_