Android 經(jīng)典問題

Dalvik和Sun JVM

共同點(diǎn)

  • 都是解釋執(zhí)行 byte code(字節(jié)碼)
  • 都是每個 OS 進(jìn)程運(yùn)行一個 VM,并執(zhí)行一個單獨(dú)的程序
  • 在較新版本中(Froyo / Sun JDK 1.5)都實(shí)現(xiàn)了相當(dāng)程度的 JIT compiler(即時編譯) 用于提速

不同點(diǎn)

  • dvm執(zhí)行的是.dex格式文件,jvm執(zhí)行的是.class文件,android程序編譯完之后生產(chǎn).class文件,然后,dex工具會把.class文件處理成.dex文件,然后把資源文件.dex文件等打包成.apk文件。apk就是android package的意思。jvm執(zhí)行的是.class文件。
  • dvm是基于寄存器的虛擬機(jī) 而jvm執(zhí)行是基于虛擬棧的虛擬機(jī)。寄存器存取速度比棧快的多,dvm可以根據(jù)硬件實(shí)現(xiàn)最大的優(yōu)化,比較適合移動設(shè)備。
  • .class文件存在很多的冗余信息,dex工具會去除冗余信息,并把所有的.class文件整合到.dex文件中。減少了I/O操作,提高了類的查找速度。

IPC進(jìn)程間通信

在一個應(yīng)用中存在多個進(jìn)程的情況(不討論兩個應(yīng)用之間的多進(jìn)程情況),開啟多進(jìn)程:在Androidmanifests文件中指定android:process屬性除此之外沒有其他辦法。

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

使用多進(jìn)程會造成問題:

  • 靜態(tài)成員和單例模式完全失效
  • 線程同步機(jī)制完全失效
  • SharedPreferences的可靠性下降
  • Application會多次創(chuàng)建

SharedPreferences的可靠性降低,因?yàn)?SharedPrefrences不支持兩個進(jìn)程同時執(zhí)行寫操作,可能會導(dǎo)致一定幾率的數(shù)據(jù)丟失,這是因?yàn)?code>sharedPrefrences底層是通過讀寫xml實(shí)現(xiàn)的。

實(shí)現(xiàn)跨進(jìn)程通信的方式:

  • 通過Intent來傳遞數(shù)據(jù)(通過Bundle來綁定數(shù)據(jù))
  • 共享文件SharedPrefereneces
  • 基于BinderMessengerAIDL以及Socket

序列化靜態(tài)成員變量屬于類不屬于對象,所以不會參與序列化過程,其次transient關(guān)鍵字標(biāo)記的成員變量不參與序列化過程。 實(shí)現(xiàn)了Parcelable接口的類都是可以直接序列化的,Android中已經(jīng)實(shí)現(xiàn)了parcelable類的有:Intent,Bundle, Bitmap等,同時 listmap 也可以序列化,前提是他們的每個元素都能序列化。實(shí)現(xiàn)了parcelable接口的類都可以通過IntentBinder來傳遞。

Binder類:實(shí)現(xiàn)了IBinder接口,從IPC角度來說,BinderAndroid中一種垮進(jìn)程通信方式,還可以理解為一種虛擬的物理設(shè)備,該通信在Linux中是沒有的。Binder是連接各種managerActivityManagerwindowManager)和相應(yīng)的ManagerService的橋梁

binder驅(qū)動是整個流程的核心

  • Server將自己的binder通過binder驅(qū)動SM中進(jìn)行注冊。
  • binder驅(qū)動會建立一個binder實(shí)體的數(shù)據(jù)節(jié)點(diǎn)和實(shí)體的引用。
  • Binder驅(qū)動再把名字和引用打包發(fā)給SM。
  • Client通過binder驅(qū)動拿著他所需要的binder名字SM請求binder。
  • SM在自己的查找表里面找到對應(yīng)的引用之后再通過binder驅(qū)動返回給client
Binder流程圖

Intent傳遞數(shù)據(jù)

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

數(shù)據(jù)存儲

Android數(shù)據(jù)存儲方式SharedPreferencesSQLiteContentProvider,File
SharedPreferences鍵值對的形式存儲,底層是xml文件。并且可以設(shè)置權(quán)限,是否和其他應(yīng)用共享該項(xiàng)文件。 FileAndroid分為內(nèi)部存儲外部存儲內(nèi)部存儲中屬于APP私有,其他任何應(yīng)用都不能訪問,APP卸載時自動刪除。外部存儲又分為兩類:公共文件私有文件私有文件:本屬于您的應(yīng)用且應(yīng)在用戶卸載您的應(yīng)用時刪除的文件。盡管這些文件在技術(shù)上可被用戶和其他應(yīng)用訪問(因?yàn)樗鼈冊谕獠看鎯ι希?,它們是?shí)際上不向您的應(yīng)用之外的用戶提供值的文件。當(dāng)用戶卸載您的應(yīng)用時,系統(tǒng)會刪除應(yīng)用外部專用目錄中的所有文件。

Android動畫

View動畫
View動畫注意事項(xiàng):View動畫執(zhí)行之后并未改變View的真實(shí)布局屬性值。切記這一點(diǎn),譬如我們在Activity中有一 個Button在屏幕上方,我們設(shè)置了平移動畫移動到屏幕下方然后保持動畫最后執(zhí)行狀態(tài)呆在屏幕下方,這時如果點(diǎn) 擊屏幕下方動畫執(zhí)行之后的Button是沒有任何反應(yīng)的,而點(diǎn)擊原來屏幕上方?jīng)]有Button的地方卻響應(yīng)的是點(diǎn)擊Button的事件。
View動畫有四種變換效果,對應(yīng)Animation的四個子類:TranslateAnimation(平移),ScaleAnimation(縮放),AlphaAnimation(透明度動畫),RotateAnimation(旋轉(zhuǎn)),一般采用XML的方式來定義動畫,可讀性更好。

幀動畫
對應(yīng)AnimationDrawale來使用幀動畫,通過XML來定義個AnimationDrawable,然后把xml作為Drawable作為view的背景來播放動畫就可以了。

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

屬性動畫
主要由ValueAnimator,ObjectAnimatorAnimatorSet類實(shí)現(xiàn)。

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

Retrofit優(yōu)點(diǎn)

  • 采用動態(tài)代理機(jī)制反射,使代碼寫起來特別簡單,看起來也很清晰。
  • 可以配合OkHttp攔截器,很方便的在headertoken或者處理cookie等等。
  • 可配合RxJava,可以讓多個接口調(diào)用組合變的更簡單。

RequestLayout,invalidate和postInvalidate

  • requestLayout:當(dāng)view確定自身已經(jīng)不再適合現(xiàn)有的區(qū)域時,該view本身調(diào)用這個方法要求parent view重新調(diào)用他的onMeasure,onLayout來對重新設(shè)置自己位置。
    特別的當(dāng)viewlayoutparameter發(fā)生改變,并且它的值還沒能應(yīng)用到view上,這時候適合調(diào)用這個方法。
  • invalidateinvalidate內(nèi)部最終會調(diào)用到performTraversals(視圖繪制的入口),但由于沒有設(shè)置強(qiáng)制視圖重新測量的標(biāo)志位,所以只會執(zhí)行onDraw方法。
  • postInvalidate:是在非UI線程使用。

Rxjava

一個詞:異步
RxJavaGitHub 主頁上的自我介紹是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一個在 Java VM上使用可觀測的序列來組成異步的、基于事件的程序的庫)。這就是 RxJava ,概括得非常精準(zhǔn)。
RxJava默認(rèn)規(guī)則中,事件的發(fā)出和消費(fèi)都是在同一個線程的。在不指定線程的情況下, RxJava 遵循的是線程不變的原則,即:在哪個線程調(diào)用 subscribe(),就在哪個線程生產(chǎn)事件;在哪個線程生產(chǎn)事件,就在哪個線程消費(fèi)事件。如果需要切換線程,就需要用到 Scheduler (調(diào)度器)。
RxJava 的異步實(shí)現(xiàn),是通過一種擴(kuò)展的觀察者模式來實(shí)現(xiàn)的。

變換(map(),flatmap()):
Map行為:

  • 創(chuàng)建了一個新的 Observable
  • 創(chuàng)建了一個新的 OnSubscribe: 其中的 call 方法是整個調(diào)用鏈的關(guān)鍵. 它調(diào)用了上一級 Observable.onSubscribe.call, 同時, 還將結(jié)果通過transform 對 ‘第一步’ 處理后的結(jié)果進(jìn)行變形, 然后將變形后的結(jié)果再轉(zhuǎn)發(fā)給‘第三步’ 中 subscribe(Subscriber…) 中的 Subscriber 處理. 那我們馬上看一下 ‘第三步’。

Glide優(yōu)點(diǎn)

  • 默認(rèn)Bitmap格式是RGB_565,內(nèi)存占用更少,原因在于Picasso是加載了全尺寸的圖片到內(nèi)存,然后讓GPU來實(shí)時重繪大小。而Glide加載的大小ImageView的大小是一致的,因此更小。
  • 磁盤緩存
  • Picasso和Glide在磁盤緩存策略上有很大的不同。Picasso緩存的是全尺寸的,而Glide緩存的是跟ImageView尺寸相同。
  • Glide可以加載GIF動態(tài)圖,而Picasso不能。
  • 除了gif動畫之外,Glide還可以將任何的本地視頻解碼成一張靜態(tài)圖片。

Material Design

  • TextInputLayout 必須把EditText包含起來,不能單獨(dú)使用。
<android.support.design.widget.TextInputLayout
        android:id="@+id/til_pwd"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

</android.support.design.widget.TextInputLayout>
  • FloatingActionButton繼承自ImageView。
  • NavigationView實(shí)現(xiàn)DrawerLayout導(dǎo)航菜單界面,通過
app:headerLayout="@layout/navigation_header"
        app:menu="@menu/drawer_view" 

來設(shè)置.

SQLite

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

  • 參數(shù)① table : 數(shù)據(jù)庫中的表名, 要插入數(shù)據(jù)的表;
  • 參數(shù)② nullColumnHack : 該參數(shù)是可選的, 數(shù)據(jù)庫表中不允許插入一行空的數(shù)據(jù), 插入數(shù)據(jù)至少有一列不為null才能插入, 如果后面的valuesnull, 并且不知道列的名稱, 那么插入操作會失敗, 為了避免這種情況, 就出現(xiàn)了本參數(shù), 為了防止 valuesnull的情況;
  • 參數(shù)③ ContentValues : 相當(dāng)于一個Map集合,鍵是列名,值是對應(yīng)列名要插入的數(shù)據(jù);

插入原則 : 不管第三個 ContentValues參數(shù)是否為null, 執(zhí)行insert()方法都會添加一條記錄, 如果values參數(shù)為null, 會添加一個除主鍵之外其它字段都為null的記錄;
nullColumnHack參數(shù)作用分析SQL語句 : 在SQL語句中在表名后面必須跟著一個列名, 例如 " insert into appale_info(name) values("喬幫主")", 這是values參數(shù)不為null的情況下,如果values參數(shù)為null, 那么導(dǎo)致表名 "apple_info" 后面的列名也為null, 這樣SQL語句就不合法了, 因此這里必須加上一個默認(rèn)的列名, 以防values參數(shù)為null;

HttpURLConnection

設(shè)置請求頭或響應(yīng)頭
HTTP請求允許一個key帶多個用逗號分開的values,但是HttpURLConnection只提供了單個操作的方法:

  • setRequestProperty(key,value)
  • addRequestProperty(key,value)

setRequestPropertyaddRequestProperty的區(qū)別就是,setRequestProperty會覆蓋已經(jīng)存在的key的所有values,有清零重新賦值的作用。而addRequestProperty則是在原來key的基礎(chǔ)上繼續(xù)添加其他value

發(fā)送URL請求
建立實(shí)際連接之后,就是發(fā)送請求,把請求參數(shù)傳到服務(wù)器,這就需要使用outputStream把請求參數(shù)傳給服務(wù)器:

  • getOutputStream

獲取響應(yīng)
請求發(fā)送成功之后,即可獲取響應(yīng)的狀態(tài)碼,如果成功既可以讀取響應(yīng)中的數(shù)據(jù),獲取這些數(shù)據(jù)的方法包括:

  • getContent
  • getHeaderField
  • getInputStream

對于大部分請求來說,getInputStreamgetContent是用的最多的。
相應(yīng)的信息頭用以下方法獲取:

  • getContentEncoding
  • getContentLength
  • getContentType
  • getDate
  • getExpiration
  • getLastModifed

任何網(wǎng)絡(luò)連接都需要經(jīng)過socket才能連接,HttpURLConnection不需要設(shè)置socket,所以,HttpURLConnection并不是底層的連接,而是在底層連接上的一個請求。這就是為什么HttpURLConneciton只是一個抽象類,自身不能被實(shí)例化的原因。HttpURLConnection只能通過URL.openConnection()方法創(chuàng)建具體的實(shí)例。雖然底層的網(wǎng)絡(luò)連接可以被多個HttpURLConnection實(shí)例共享,但每一個HttpURLConnection實(shí)例只能發(fā)送一個請求。請求結(jié)束之后,應(yīng)該調(diào)用HttpURLConnection實(shí)例的InputStreamOutputStreamclose()方法以釋放請求的網(wǎng)絡(luò)資源,不過這種方式對于持久化連接沒用。對于持久化連接,得用disconnect()方法關(guān)閉底層連接的socket。

ViewStub、include、merge

好文章

Json

一種輕量級的數(shù)據(jù)交換格式,具有良好的可讀和便于快速編寫的特性??稍诓煌脚_之間進(jìn)行數(shù)據(jù)交換。JSON采用兼容性很高的文本格式,同時也具備類似于C語言體系的行為。

優(yōu)點(diǎn)

  • 數(shù)據(jù)格式比較簡單,易于讀寫,格式都是壓縮的,占用帶寬小
  • 易于解析
  • 支持多種語言,包括ActionScript, C, C#, ColdFusion, Java, JavaScript, Perl, PHP, Python, Ruby等服務(wù)器端語言,便于服務(wù)器端的解析;
  • 因?yàn)镴SON格式能直接為服務(wù)器端代碼使用,大大簡化了服務(wù)器端和客戶端的代碼開發(fā)量,且完成任務(wù)不變,并且易于維護(hù)。

缺點(diǎn)

  • 沒有XML格式這么推廣的深入人心和喜用廣泛,沒有XML那么通用性;
  • JSON格式目前在Web Service中推廣還屬于初級階段

Android中Parcelable和Serializable

作用

Serializable的作用是為了保存對象的屬性到本地文件、數(shù)據(jù)庫、網(wǎng)絡(luò)流、rmi以方便數(shù)據(jù)傳輸,當(dāng)然這種傳輸可以是程序內(nèi)的也可以是兩個程序間的。簡單易用,這種方法的缺點(diǎn)是使用了反射,序列化的過程較慢。這種機(jī)制會在序列化的時候創(chuàng)建許多的臨時對象,容易觸發(fā)垃圾回收。

而Android的Parcelable的設(shè)計初衷是因?yàn)?code>Serializable效率過慢,為了在程序內(nèi)不同組件間以及不同Android程序間(AIDL)高效的傳輸數(shù)據(jù)而設(shè)計,這些數(shù)據(jù)僅在內(nèi)存中存在Parcelable是通過IBinder通信的消息的載體。

效率

Parcelable的性能比Serializable好,在內(nèi)存開銷方面較小,所以在內(nèi)存間數(shù)據(jù)傳輸時推薦使用Parcelable,如activity間傳輸數(shù)據(jù),而Serializable可將數(shù)據(jù)持久化方便保存,所以在需要保存或網(wǎng)絡(luò)傳輸數(shù)據(jù)時選擇Serializable,因?yàn)閍ndroid不同版本Parcelable可能不同,所以不推薦使用Parcelable進(jìn)行數(shù)據(jù)持久化

從上面的設(shè)計上我們就可以看出優(yōu)劣了。

  • 整個讀寫全是在內(nèi)存中進(jìn)行,所以效率比JAVA序列化中使用外部存儲器會高很多;
  • 讀寫時是4字節(jié)對齊的
  • 如果預(yù)分配的空間不夠時,會一次多分配50%;
  • 對于普通數(shù)據(jù),使用的是mData內(nèi)存地址,對于IBinder類型的數(shù)據(jù)以及FileDescriptor使用的是mObjects內(nèi)存地址。后者 是通過flatten_binder()unflatten_binder()實(shí)現(xiàn)的,目的是反序列化時讀出的對象就是原對象而不用重新new一個新對象。

后期持續(xù)更新。。。。。。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容