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)程:在Android
的manifests
文件中指定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
- 基于Binder的
Messenger
和AIDL
以及Socket
等
序列化:靜態(tài)成員變量屬于類不屬于對象,所以不會參與序列化過程,其次transient關(guān)鍵字標(biāo)記的成員變量不參與序列化過程。 實(shí)現(xiàn)了Parcelable
接口的類都是可以直接序列化的,Android中已經(jīng)實(shí)現(xiàn)了parcelable
類的有:Intent
,Bundle
, Bitmap
等,同時 list
和 map
也可以序列化,前提是他們的每個元素都能序列化
。實(shí)現(xiàn)了parcelable接口的類都可以通過Intent
和Binder
來傳遞。
Binder類:實(shí)現(xiàn)了IBinder接口,從IPC
角度來說,Binder
是Android
中一種垮進(jìn)程通信方式,還可以理解為一種虛擬的物理設(shè)備,該通信在Linux
中是沒有的。Binder
是連接各種manager
(ActivityManager
, windowManager
)和相應(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
。
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ù)存儲方式:SharedPreferences
,SQLite
,ContentProvider
,File
。
SharedPreferences
鍵值對的形式存儲,底層是xml
文件。并且可以設(shè)置權(quán)限,是否和其他應(yīng)用共享該項(xiàng)文件
。 File:Android
分為內(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
,ObjectAnimator
和AnimatorSet
類實(shí)現(xiàn)。
Bitmap加載:
Bitmap
代表一張圖片,BitmapFactory
提供了四類方法:decodeFile
,decodeResource
,decodeStream
和 decodeByteArray
加載bitmap
。
Retrofit優(yōu)點(diǎn)
- 采用
動態(tài)代理機(jī)制
和反射
,使代碼寫起來特別簡單,看起來也很清晰。 - 可以配合
OkHttp攔截器
,很方便的在header
加token
或者處理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)view
的layoutparameter
發(fā)生改變,并且它的值還沒能應(yīng)用到view
上,這時候適合調(diào)用這個方法。 -
invalidate:
invalidate
內(nèi)部最終會調(diào)用到performTraversals
(視圖繪制的入口),但由于沒有設(shè)置強(qiáng)制視圖重新測量的標(biāo)志位,所以只會執(zhí)行onDraw
方法。 -
postInvalidate:是在
非UI線程
使用。
Rxjava
一個詞:
異步
。
RxJava
在GitHub
主頁上的自我介紹是 "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
才能插入, 如果后面的values
是null
, 并且不知道列的名稱, 那么插入操作會失敗, 為了避免這種情況, 就出現(xiàn)了本參數(shù), 為了防止values
為null
的情況; - 參數(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)
setRequestProperty
和addRequestProperty
的區(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
對于大部分請求來說,getInputStream
和getContent
是用的最多的。
相應(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í)例的InputStream
或OutputStream
的close()
方法以釋放請求的網(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ù)更新。。。。。。