2019-01-29(Android基礎面試題)

1.Dalvik和Sun JVM

共同點

都是解釋執行 byte code(字節碼)

都是每個 OS 進程運行一個 VM,並執行一個單獨的程序

在較新版本中(Froyo / Sun JDK 1.5)都實現了相當程度的 JIT compiler(即時編譯) 用於提速

不同點

dvm執行的是.dex格式文件,jvm執行的是.class文件,android程序編譯完之後生產.class文件,然後,dex工具會把.class文件處理成.dex文件,然後把資源文件和.dex文件等打包成.apk文件。apk就是android package的意思。jvm執行的是.class文件。

dvm是基於寄存器的虛擬機 而jvm執行是基於虛擬棧的虛擬機。寄存器存取速度比棧快的多,dvm可以根據硬件實現最大的優化,比較適合移動設備。

.class文件存在很多的冗餘信息,dex工具會去除冗餘信息,並把所有的.class文件整合到.dex文件中。減少了I/O操作,提高了類的查找速度。

2.IPC進程間通信

在一個應用中存在多個進程的情況(不討論兩個應用之間的多進程情況),開啓多進程:在Android的manifests文件中指定android:process屬性,除此之外沒有其他辦法。

進程名:以“:“開頭的進程屬於當前應用的私有進程,其他的應用不可以和它跑在同一個進程中,而進程名不以”:“開頭的屬於全局進程,其他應用通過shareUID方式可以和它跑在同一個進程中。Android給每一個進程都分配一個獨立的虛擬機,所以運行在不同進程中的四大組件,只要他們之間需要通過內存來共享數據,都會共享失敗,這也是多進程所帶來的主要影響。

使用多進程會造成問題:

靜態成員和單例模式完全失效;

線程同步機制完全失效;

SharedPreferences的可靠性下降;

Application會多次創建;

SharedPreferences的可靠性降低,因爲 SharedPrefrences不支持兩個進程同時執行寫操作,可能會導致一定機率的數據丟失,這是因爲sharedPrefrences底層是通過讀寫xml實現的。

實現跨進程通信的方式:

通過Intent來傳遞數據(通過Bundle來綁定數據)

共享文件和SharedPrefereneces

基於Binder的Messenger和AIDL以及Socket等

序列化:靜態成員變量屬於類不屬於對象,所以不會參與序列化過程,其次transient關鍵字標記的成員變量不參與序列化過程。 實現了Parcelable接口的類都是可以直接序列化的,Android中已經實現了parcelable類的有:Intent,Bundle, Bitmap等,同時 list 和 map 也可以序列化,前提是他們的每個元素都能序列化。實現了parcelable接口的類都可以通過Intent和Binder來傳遞。

Binder類:實現了IBinder接口,從IPC角度來說,Binder是Android中一種垮進程通信方式,還可以理解爲一種虛擬的物理設備,該通信在Linux中是沒有的。Binder是連接各種manager(ActivityManager, windowManager)和相應的ManagerService的橋樑。

binder驅動是整個流程的核心

Server將自己的binder通過binder驅動在SM中進行註冊。

binder驅動會建立一個binder實體的數據節點和實體的引用。

Binder驅動再把名字和引用打包發給SM。

Client通過binder驅動拿着他所需要的binder名字向SM請求binder。

SM在自己的查找表裏面找到對應的引用之後再通過binder驅動返回給client。

Binder流程圖

3.Intent傳遞數據

根據API文檔,Intent/Bundle支持傳遞基本類型的數據和基本類型的數組數據,以及String/CharSequence。而對於其它類型的數據貌似無能爲力,其實不然,我們可以在Intent/Bundle的API中看到Intent/Bundle還可以傳遞 Parcelable(包裹化,郵包)和Serializable(序列化)類型的數據,以及它們的數組/列表數據。

4.數據存儲

Android數據存儲方式:

SharedPreferences,鍵值對的形式存儲,底層是xml文件。並且可以設置權限,是否和其他應用共享該項文件。

使用步驟:

(1)通過getSharedPreference方法獲取一個SharedPreference對象;

(2)通過SharedPreference對象的edit方法獲取一個Editor對象;

(3)通過調用Editor的putXxxx方法進行添加內容;

(4)最後通過調用Editor的apply方法提交數據;

(6)讀取數據時,調用SharedPreference的getXxx方法;

SQLite,

使用步驟:

(1)創建一個SQLiteOpenHelper的子類DbHelper;

(2)在構造器中調用父類的構造器,super(context,"myapp",null,4),參數2代表數據庫文件名,參數四代表版本信息。

(3)重寫onCreate方法,用於創建數據庫,利用SQLiteDatabase的execSQL方法創建表;

(4)重寫onUpgrade方法,用於版本升級的實現;

(5)在Activity中實例化DbHelper,調用getWritableDatabase方法,會得到一個SQLiteDatabase對象,即可創建數據庫;

(6)利用SQLiteDatabase對象的insert、delete、update、和query方法對數據進行操作;

(7)在onDestroy方法中調用SQLiteDatabase的close方法

File, Android分爲內部存儲和外部存儲,內部存儲中屬於APP私有,其他任何應用都不能訪問,APP卸載時自動刪除。外部存儲又分爲兩類:公共文件和私有文件,私有文件:本屬於您的應用且應在用戶卸載您的應用時刪除的文件。儘管這些文件在技術上可被用戶和其他應用訪問(因爲它們在外部存儲上),它們是實際上不向您的應用之外的用戶提供值的文件。當用戶卸載您的應用時,系統會刪除應用外部專用目錄中的所有文件。

內部存儲

寫數據:

通過context.openFileOutput(文件名,讀寫文件的方式)的到一個文件輸出流;

調用文件輸出流的write方法將文本信息寫到手機內存中;

讀數據:

通過context.openFileInput(文件名)獲取一個輸入流;

獲取一個字節數組輸出流,和實例化一個字節數組;

從輸入流中讀取數據寫入到內存流中,最後調用內存流的toString方法將數據輸出;

外部存儲

寫數據:

讀寫外部數據時需要設置權限;

寫數據之前首先要判斷SDCard的狀態,Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);

獲取sdcard的根路徑rootPath,Environment.getExternalStorageDirectory();

創建要寫入的sdcard的文件file,new File(sdcard的根路徑,文件名);

創建文件輸出流fos,參數爲上步的file;

調用fos的write方法,將內容寫入輸出流中;

讀數據:

第1、2、3步同寫數據的,

獲取要讀取的文件file,new File(rootPath.getAbsolutePath()+"/"+文件名);

調用file的exists方法判斷文件是否存在;

創建一個文件輸入流fis,參數爲上步的file;

創建一個字節數組輸出流(內存流),和一個自己數組;

將讀取輸入流中內容寫入到字節數組輸出流中,最後通過內存流的to;

網絡存儲

5.Android動畫

View動畫:

View動畫注意事項:View動畫執行之後並未改變View的真實佈局屬性值。切記這一點,譬如我們在Activity中有一 個Button在屏幕上方,我們設置了平移動畫移動到屏幕下方然後保持動畫最後執行狀態呆在屏幕下方,這時如果點 擊屏幕下方動畫執行之後的Button是沒有任何反應的,而點擊原來屏幕上方沒有Button的地方卻響應的是點擊Button的事件。

View動畫有四種變換效果,對應Animation的四個子類:TranslateAnimation(平移),ScaleAnimation(縮放),AlphaAnimation(透明度動畫),RotateAnimation(旋轉),一般採用XML的方式來定義動畫,可讀性更好。

幀動畫:

對應AnimationDrawale來使用幀動畫,通過XML來定義個AnimationDrawable,然後把xml作爲Drawable作爲view的背景來播放動畫就可以了。

注意:

幀動畫使用比較簡單,比較容易引起OOM,所以儘量避免使用過多尺寸較大的圖片。

屬性動畫

通過動態地改變對象的屬性從而達到動畫效果,屬性動畫爲API 11新特性。主要由ValueAnimator,ObjectAnimator和AnimatorSet類實現。

6.Bitmap加載

Bitmap代表一張圖片,BitmapFactory提供了四類方法:decodeFile,decodeResource,decodeStream和 decodeByteArray加載bitmap。

7.Retrofit優點

採用動態代理機制和反射,使代碼寫起來特別簡單,看起來也很清晰。

可以配合OkHttp攔截器,很方便的在header加token或者處理cookie等等。

可配合RxJava,可以讓多個接口調用組合變的更簡單。

8.RequestLayout,invalidate和postInvalidate

requestLayout:當view確定自身已經不再適合現有的區域時,該view本身調用這個方法要求parent view重新調用他的onMeasure,onLayout來對重新設置自己位置。

特別的當view的layoutparameter發生改變,並且它的值還沒能應用到view上,這時候適合調用這個方法。

invalidate:invalidate內部最終會調用到performTraversals(視圖繪製的入口),但由於沒有設置強制視圖重新測量的標誌位,所以只會執行onDraw方法。

postInvalidate:是在非UI線程使用

9.Rxjava

一個詞:異步。

RxJava 在 GitHub 主頁上的自我介紹是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一個在 Java VM上使用可觀測的序列來組成異步的、基於事件的程序的庫)。這就是 RxJava ,概括得非常精準。

在 RxJava 的默認規則中,事件的發出和消費都是在同一個線程的。在不指定線程的情況下, RxJava 遵循的是線程不變的原則,即:在哪個線程調用 subscribe(),就在哪個線程生產事件;在哪個線程生產事件,就在哪個線程消費事件。如果需要切換線程,就需要用到 Scheduler (調度器)。

RxJava 的異步實現,是通過一種擴展的觀察者模式來實現的

變換(map(),flatmap()):

Map行爲:

創建了一個新的 Observable

創建了一個新的 OnSubscribe: 其中的 call 方法是整個調用鏈的關鍵. 它調用了上一級 Observable.onSubscribe.call, 同時, 還將結果通過transform 對 ‘第一步’ 處理後的結果進行變形, 然後將變形後的結果再轉發給‘第三步’ 中 subscribe(Subscriber…) 中的 Subscriber 處理. 那我們馬上看一下 ‘第三步’。

10.Glide優點

默認Bitmap格式是RGB_565,內存佔用更少,原因在於Picasso是加載了全尺寸的圖片到內存,然後讓GPU來實時重繪大小。而Glide加載的大小和ImageView的大小是一致的,因此更小。

磁盤緩存

Picasso和Glide在磁盤緩存策略上有很大的不同。Picasso緩存的是全尺寸的,而Glide緩存的是跟ImageView尺寸相同。

Glide可以加載GIF動態圖,而Picasso不能。

除了gif動畫之外,Glide還可以將任何的本地視頻解碼成一張靜態圖片。

11.Material Design

TextInputLayout必須把EditText包含起來,不能單獨使用。

FloatingActionButton繼承自ImageView。

NavigationView實現DrawerLayout導航菜單界面,通過

app:headerLayout="@layout/navigation_header"app:menu="@menu/drawer_view"

12.SQLite

public long insert (String table, String nullColumnHack, ContentValues values) 插入數據參數介紹 :

參數① table : 數據庫中的表名, 要插入數據的表;

參數② nullColumnHack : 該參數是可選的, 數據庫表中不允許插入一行空的數據, 插入數據至少有一列不爲null才能插入, 如果後面的values是null, 並且不知道列的名稱, 那麼插入操作會失敗, 爲了避免這種情況, 就出現了本參數, 爲了防止 values爲null的情況;

參數③ ContentValues : 相當於一個Map集合,鍵是列名,值是對應列名要插入的數據;

插入原則 :不管第三個 ContentValues參數是否爲null, 執行insert()方法都會添加一條記錄, 如果values參數爲null, 會添加一個除主鍵之外其它字段都爲null的記錄;

nullColumnHack參數作用分析SQL語句 : 在SQL語句中在表名後面必須跟着一個列名, 例如 " insert into appale_info(name) values("喬幫主")", 這是values參數不爲null的情況下,如果values參數爲null, 那麼導致表名 "apple_info" 後面的列名也爲null, 這樣SQL語句就不合法了, 因此這裏必須加上一個默認的列名, 以防values參數爲null;

13.HttpURLConnection

設置請求頭或響應頭

HTTP請求允許一個key帶多個用逗號分開的values,但是HttpURLConnection只提供了單個操作的方法:

setRequestProperty(key,value)

addRequestProperty(key,value)

setRequestProperty和addRequestProperty的區別就是,setRequestProperty會覆蓋已經存在的key的所有values,有清零重新賦值的作用。而addRequestProperty則是在原來key的基礎上繼續添加其他value。

發送URL請求

建立實際連接之後,就是發送請求,把請求參數傳到服務器,這就需要使用outputStream把請求參數傳給服務器:

getOutputStream

獲取響應

請求發送成功之後,即可獲取響應的狀態碼,如果成功既可以讀取響應中的數據,獲取這些數據的方法包括:

getContent

getHeaderField

getInputStream

對於大部分請求來說,getInputStream和getContent是用的最多的。

相應的信息頭用以下方法獲取:

getContentEncoding

getContentLength

getContentType

getDate

getExpiration

getLastModifed

任何網絡連接都需要經過socket才能連接,HttpURLConnection不需要設置socket,所以,HttpURLConnection並不是底層的連接,而是在底層連接上的一個請求。這就是爲什麼HttpURLConneciton只是一個抽象類,自身不能被實例化的原因。HttpURLConnection只能通過URL.openConnection()方法創建具體的實例。雖然底層的網絡連接可以被多個HttpURLConnection實例共享,但每一個HttpURLConnection實例只能發送一個請求。請求結束之後,應該調用HttpURLConnection實例的InputStream或OutputStream的close()方法以釋放請求的網絡資源,不過這種方式對於持久化連接沒用。對於持久化連接,得用disconnect()方法關閉底層連接的socket。

14.Json

一種輕量級的數據交換格式,具有良好的可讀和便於快速編寫的特性。可在不同平臺之間進行數據交換。JSON採用兼容性很高的文本格式,同時也具備類似於C語言體系的行爲。

優點:

數據格式比較簡單,易於讀寫,格式都是壓縮的,佔用帶寬小;

易於解析

支持多種語言,包括ActionScript, C, C#, ColdFusion, Java, JavaScript, Perl, PHP, Python, Ruby等服務器端語言,便於服務器端的解析;

因爲JSON格式能直接爲服務器端代碼使用,大大簡化了服務器端和客戶端的代碼開發量,且完成任務不變,並且易於維護。

缺點 :

沒有XML格式這麼推廣的深入人心和喜用廣泛,沒有XML那麼通用性;

JSON格式目前在Web Service中推廣還屬於初級階段

15.Parcelable和Serializable

作用:

Serializable的作用是爲了保存對象的屬性到本地文件、數據庫、網絡流、rmi以方便數據傳輸,當然這種傳輸可以是程序內的也可以是兩個程序間的。簡單易用,這種方法的缺點是使用了反射,序列化的過程較慢。這種機制會在序列化的時候創建許多的臨時對象,容易觸發垃圾回收。

而Android的Parcelable的設計初衷是因爲Serializable效率過慢,爲了在程序內不同組件間以及不同Android程序間(AIDL)高效的傳輸數據而設計,這些數據僅在內存中存在,Parcelable是通過IBinder通信的消息的載體。

效率:

Parcelable的性能比Serializable好,在內存開銷方面較小,所以在內存間數據傳輸時推薦使用Parcelable,如activity間傳輸數據,而Serializable可將數據持久化方便保存,所以在需要保存或網絡傳輸數據時選擇Serializable,因爲android不同版本Parcelable可能不同,所以不推薦使用Parcelable進行數據持久化

從上面的設計上我們就可以看出優劣了。

整個讀寫全是在內存中進行,所以效率比JAVA序列化中使用外部存儲器會高很多;

讀寫時是4字節對齊的

如果預分配的空間不夠時,會一次多分配50%;

對於普通數據,使用的是mData內存地址,對於IBinder類型的數據以及FileDescriptor使用的是mObjects內存地址。後者 是通過flatten_binder()和unflatten_binder()實現的,目的是反序列化時讀出的對象就是原對象而不用重新new一個新對象。

16.Android 四大組件

Lemon_95的Android 四大組件

17.Application context和Activity context的區別有哪些?

(1)Application的context是一個全局靜態變量,官方文檔表明,只有當你引用這個context的生命週期超過了當前activity的生命週期,而和整個應用的生命週期掛鉤時,纔會使用Application的context;

注:一種推薦的用法就是應用程序註冊廣播broadcast時,使用這個context。

(2)引用Application context不會導致內存泄漏,引用activity的context纔會導致內存泄漏,當你的引用對象的生命週期超過了當前activity的生命週期時,系統回收你的activity時發現還有一個context的強引用,而不去銷燬這個activity,導致內存泄漏;

注:在開發過程中,需要非常重視這一點,一個全距靜態變量在引用context時一定要使用application的context而不使用activity的;

(3)避免context相關的內存泄漏:

不要讓比Activity聲明週期長的對象引用Activity context,即保證引用activity的對象要與activity本身生命週期是一樣的;

對於生命週期長的對象可以使用Application context,

避免非靜態的內部類,儘量使用靜態類,避免聲明週期問題,注意內部類對外部對象的引用導致的生命週期變化。

18.請分析一張400*500尺寸的PNG圖片加載到程序中佔用內存中的大小?

一張圖片佔用的內存=圖片長度 x 圖片寬度 x 單位像素佔用的字節數;

注:圖片長度和寬度的單位是像素;

創建一個Bitmap時,其單位像素佔用的字節數由其參數BitmapFactory.Options的inPrefenredConfig變量決定,inPreferredConfig爲Bitmap.Config類型,(Bitmap.Config類是個枚舉類型),其取值如下圖所示:

在Android4.0之前,Bitmap的內存是分配在Native堆中,調用recycle可以立即釋放Native內存;

在Android4.0開始,Bitmap的內存是分配在dalvik堆中,即java堆中的。

19.xml三種解析方式的區別sax、pull、dom,官方推薦哪種?]

(1)解析XML:

pull(開發首選);

原理:pull的解析方式與SAX解析類似,都是基於事件的模式,pull提供了開始元素和結束元素,當某個元素開始時,我們可以調用parser.nextText從XML文檔中提取所有字符數據,與sax不同的是,在pull解析過程中觸發相應的事件調用方法返回的是數字,且我們需要自己獲取產生的事件然後做出相應操作,而不像SAX那樣由處理器觸發一種事件的方法而執行代碼,當解釋到一個文檔結束時,自動生成EndDocument事件;

優點:SAX的優點pull都有,而且解析方法比sax更加簡單;

缺點:可擴展性差,無法對xml數內容進行修改;

使用情境:適用於需要處理大型XML文檔、性能要求較高、不需要對解析文檔進行修改且不需要對解析文檔多次訪問的場合。

dom;

原理:基於文檔驅動,是先把dom全部文件讀入到內存中,構建一個主流內存的樹結構,然後使用dom的API遍歷所有數據,調用API檢索想要的數據和操作數據;

優點:整個文檔樹存在內存中,課對XML文檔進行操作,刪除、修改等待,可多次訪問已解析的文檔,由於在內存中以樹形結構存放,因此檢索和更新效率會更高。

缺點:解析xml文件時會將整個XML文件的內容解析成樹形結構存放在內存中並創建新對象,比較消耗時間和內存。

使用情境:對於像手機這樣的啓動設備來講,內存是非常有效的,在XML文檔比較小、需要對解析文檔進行一定的操作且一旦解析了文檔需要多次訪問這些數據的情況下可以考慮使用dom方式,因爲其檢索和解析效率較高。

sax;

原理:基於事件驅動,在讀取XML文檔內容時,事件源順序地對文檔進行掃描,當掃描到文檔的開始與結束(Document)標籤、節點元素的開始與結束(Element)標籤時,直接調用對應的方法,並將狀態信息以參數的形式傳遞到方法中,然後我們可以依據狀態信息來執行相關的自定義操作。

優點:解析效率高、佔存少、靈活性高;

缺點:解析方式複雜,代碼量大,可擴展性差,無法對XML樹內容結構進行任何修改;

使用情境:適用於需要處理大型XML文檔、性能要求高、不需要對文檔進行修改且不需要對解析文檔多次訪問的場合。

(2) 解析JSON

JSON-java(原生);

fastjson;

Gson;

json解析框架的原理:

利用反射和註解,屬性名和註解的對應,如果屬性名和字段名一樣直接賦值,不一樣的話,利用註解,如果屬性對應的類型不同,Gson的解決方案是構造一個適配器,fastjson的方案是利用註解進行方法的回調。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章