Activity的啟動模式
Activity的四大啟動模式:
- standard:標準模式凄杯,每次都會在活動棧中生成一個新的Activity實例师溅。通常我們使用的活動都是標準模式。
- singleTop:棧頂復用盾舌,如果Activity實例已經存在棧頂墓臭,那么就不會在活動棧中創(chuàng)建新的實例。比較常見的場景就是給通知跳轉的Activity設置妖谴,因為你肯定不想前臺Activity已經是該Activity的情況下窿锉,點擊通知酌摇,又給你再創(chuàng)建一個同樣的Activity。
- singleInstance:棧內復用嗡载,如果Activity實例在當前棧中已經存在窑多,就會將當前Activity實例上面的其他Activity實例都移除棧。常見于跳轉到主界面洼滚。
- singleTask:單實例模式埂息,創(chuàng)建一個新的任務棧,這個活動實例獨自處在這個活動棧中遥巴。
Activity中onStart和onResume的區(qū)別千康?onPause和onStop的區(qū)別?
Activity有三類:
- 可見可交互Activity:活躍的Activity铲掐,正在和用戶交互的Activity烈评。
生命周期:
onCreate->onStart->onResume
- 可見不可交互的Activity:用戶可以看到該Activity逞力,但是無法與該也看進行交互。例子:在一個Activity1中啟動一個Activity2,背景透明或者為Dialog樣式疯攒,處在Activity2下面的Activity1就是可見不可交互的Activity赋荆。
生命周期:
Activity1 : onCreate->onStart->onResume
Activity2 : onCreate->onStart->onResume
Activity1 : onPause->onStop
- 不可見不可交互Activity:已經被暫停的Activity邪狞,比如已經執(zhí)行了onStop方法挖垛。
結論:
onStart執(zhí)行后,Activity為可見婉支,執(zhí)行onResume后鸯隅,Activity為可見可交互。
onPause執(zhí)行后磅摹,Activity為可見不可交互滋迈,執(zhí)行onStop后,Activity為不可見不可交互户誓。
注:可見可交互Activity可以稱為前臺活躍Activity饼灿,可見不可交互的Activity可以成為前臺不活躍Activity,不可見不可交互Activity為后臺Activity帝美。
屏幕適配
平時如何有使用屏幕適配嗎碍彭?原理是什么呢?
平時的屏幕適配一般采用的頭條的屏幕適配方案悼潭。簡單來說庇忌,以屏幕的一邊作為適配,通常是寬舰褪。
原理:設備像素px
和設備獨立像素dp
之間的關系是
px = dp * density
假設UI給的設計圖屏幕寬度基于360dp皆疹,那么設備寬的像素點已知,即px占拍,dp也已知略就,360dp捎迫,所以density = px / dp
,之后根據這個修改系統(tǒng)中跟density
相關的知識點即可表牢。
Handler消息機制
Handler機制的作用:
負責跨線程通信窄绒,這是因為在主線程不能做耗時操作,而子線程不能更新UI,所以當子線程中進行耗時操作后需要更新UI時崔兴,通過Handler將有關UI的操作切換到主線程中執(zhí)行彰导。
Handler機制的成員:
- Message(消息):需要被傳遞的消息,消息分為硬件產生的消息(如按鈕敲茄、觸摸)和軟件生成的消息位谋;
- MessageQueue(消息隊列):負責消息的存儲與管理,負責管理有Handler發(fā)送過來的Message折汞。讀取會自動刪除消息倔幼,單鏈表維護盖腿,插入和刪除上有優(yōu)勢爽待。在MessageQueue.next方法中會無線循環(huán),不斷判斷是否有消息翩腐,有就返回這條消息并移除鸟款。另外MessageQueue.enqueueMessage會向消息池中投遞消息。
- Handler(消息處理器):負責Message的發(fā)送與處理茂卦,主要功能向消息池發(fā)送各種消息事件(Handler.sendMessage)和處理相應消息事件(Handler.handleMessage)何什,按照先進先出執(zhí)行,內部使用的是單鏈表結構等龙。
- Looper(消息池):負責關聯線程以及消息的分發(fā)处渣,在該線程下從MessageQueue獲取Message,分發(fā)給Handler蛛砰,Looper創(chuàng)建的時候罐栈,會創(chuàng)建一個MessageQueue,調用loop()方法的時候泥畅,消息循環(huán)開始荠诬,其中會不斷的調用messageQueue的next()方法,當有消息就處理位仁,否則阻塞在messageQueue的next()方法中柑贞。當Looper的quit()被調用的時候會調用messageQueue的quit(),此時next()會返回null聂抢,然后loop()方法也就跟著退出钧嘶。
Handler運行過程:
- 在主線程創(chuàng)建的時候會創(chuàng)建一個Looper,同時也會在在Looper內部創(chuàng)建一個消息隊列琳疏。而在創(chuàng)鍵Handler的時候取出當前線程的Looper有决,并通過該Looper對象獲得消息隊列摄欲,然后Handler在子線程中通過MessageQueue.enqueueMessage在消息隊列中添加一條Message。
- 通過Looper.loop()開啟消息循環(huán)不斷輪詢調用MessageQueue.next()疮薇,取得對應的Message并且通過Handler.dispatchMessage傳遞給Handler胸墙,最終調用Handler.handlerMessage處理消息。
一個線程能否創(chuàng)建多個 Handler按咒,Handler 跟 Looper 之間的對應關系?
說到這個問題迟隅,先了解一下ThreadLocal機制。
Looper中還有一個ThreadLocal励七。ThreadLocal不是線程智袭,它的作用是可以在每個線程中存儲數據。
Handler創(chuàng)建的時候會采用當前線程的Looper來構造消息循環(huán)系統(tǒng)掠抬。
那么Handler內部如何獲取當前線程的Looper呢吼野?
這就要使用ThreadLocal。Looper類中使用ThreadLocal來存儲Looper對象两波。
那么為什么需要ThreadLocal來存儲Looper呢瞳步?
因為Looper的構造函數是私有的,無法創(chuàng)建Looper進行賦值腰奋。只能將Looper的引用存在變量中单起,而且每個線程都有自己對應的Looper,則需要用到ThreadLocal來存儲劣坊。因為ThreadLocal可以在不同的線程中互不干擾的存儲并提供數據嘀倒,通過ThreadLocal可以輕松獲取每個線程的Looper。
而Looper中又有這樣一段代碼:
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
從上面代碼可以看出局冰,如果獲取sThreadLocal.get()不為空测蘑,就會拋出異常。代表sThreadLocal.set只會執(zhí)行一次康二。由此得出結論:
一個Thread只能有一個Looper碳胳,一個MessageQueue,可以有多個Handler。
線程池的相關知識
Android 中的線程池都是直接或間接通過配置 ThreadPoolExecutor 來實現不同 特性的線程池.Android 中最常見的類具有不同特性的線程池分別為 FixThreadPool赠摇、CachedhreadPool固逗、SingleThreadPool、ScheduleThreadExecutr藕帜。
- FixThreadPool:只有核心線程,并且數量固定的,也不會被回收,所有線程都活動時,因為隊列沒有限制大小,新任務會等待執(zhí)行烫罩。優(yōu)點:更快的響應外界請求。
- SingleThreadPool:只有一個核心線程,確保所有的任務都在同一線程中按序完成洽故。因此不需要處理線程同步的問題贝攒。
- CachedThreadPool:只有非核心線程,最大線程數非常大,所有線程都活動時會為新任務創(chuàng)建新線程, 否則會利用空閑線程(60s 空閑時間,過了就會被回收,所以線程池中有 0 個線程的可能)處理任務。優(yōu)點:任何任務都會被立即執(zhí)行(任務隊列 SynchronousQuue 相當于一個空集合); 比較適合執(zhí)行大量的耗時較少的任務时甚。
- ScheduledThreadPool:核心線程數固定,非核心線程(閑著沒活干會被立即回收數)沒有限制隘弊。優(yōu)點:執(zhí)行定時任務以及有固定周期的重復任務哈踱。
Fragment 加載到 Activity 的 2 種方式
Fragment 加載到 Activity 的方式分為靜態(tài)加載和動態(tài)加載,下面我們看看這兩種加載方 式:
靜態(tài)加載:直接在 Activity 布局文件中指定 Fragment梨熙。使用指定屬性 name 即可开镣,代碼 如下所示:
<fragment
android:name="com.example.myfragment.MyFragment"
android:id="@+id/myfragment_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
動態(tài)加載: 動態(tài)加載需要使用到 FragmentManager,這種動態(tài)加載的方式在開發(fā)中是 非常常見的咽扇,示例代碼如下:
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginT ransaction();
//將FragmentA從容器中移除掉邪财,減少內存的消耗
fragmentTransaction.remove(fragmentA);
fragmentTransaction.add(R.id.fragment_layout,new FragmentB());
fragmentTransaction.commit();
理解Activity,View,Window三者關系
這個問題真的很不好回答质欲。所以這里先來個算是比較恰當的比喻來形容下它們的關系吧树埠。Activity像一個工匠(控制單元),Window像窗戶(承載模型)嘶伟,View像窗花(顯示視圖)LayoutInflater像剪刀怎憋,Xml配置像窗花圖紙。
1:Activity構造的時候會初始化一個Window九昧,準確的說是PhoneWindow绊袋。
2:這個PhoneWindow有一個“ViewRoot”,這個“ViewRoot”是一個View或者說ViewGroup耽装,是最初始的根視圖愤炸。
3:“ViewRoot”通過addView方法來一個個的添加View期揪。比如TextView掉奄,Button等
4:這些View的事件監(jiān)聽,是由WindowManagerService來接受消息凤薛,并且回調Activity函數姓建。比如onClickListener,onKeyDown等缤苫。
View的事件分發(fā)機制
事件分發(fā)本質:就是對MotionEvent事件分發(fā)的過程速兔。即當一個MotionEvent產生了以后,系統(tǒng)需要將這個點擊事件傳遞到一個具體的View上活玲。
點擊事件的傳遞順序:Activity(Window) -> ViewGroup -> View
三個主要方法:
dispatchTouchEvent:進行事件的分發(fā)(傳遞)涣狗。返回值是 boolean 類型,受當前onTouchEvent和下級view的dispatchTouchEvent影響
onInterceptTouchEvent:對事件進行攔截舒憾。該方法只在ViewGroup中有镀钓,View(不包含 ViewGroup)是沒有的。一旦攔截镀迂,則執(zhí)行ViewGroup的onTouchEvent丁溅,在ViewGroup中處理事件,而不接著分發(fā)給View探遵。且只調用一次窟赏,所以后面的事件都會交給ViewGroup處理妓柜。
onTouchEvent:進行事件處理。
View 的繪制過程涯穷,自定義View棍掐。
View 的繪制過程
關于View的繪制過程,可以簡單的分成三個步驟:
1)measure 過程:
作用:測量View的寬拷况、高
流程:performMeasure() --- measure() --- onMeasure() --- 子View的measure()
備注:在onMeasure() 方法中會對所有的子元素進行measure過程
2)layout 過程:
作用:通過確定View四個頂點的位置塌衰,從而確定View的位置
流程:performLayout() --- layout() --- onLayout() ---子View的layout過程
備注:在OnLayout()方法中會對所有子元素進行l(wèi)ayout過程
3)draw 過程:
作用:將View繪制在屏幕上
流程:performDraw() --- draw() --- onDraw() --- 子View 的 draw 過程
自定義View
自定義View分為以下幾種:
類型 | 定義 |
---|---|
自定義組合控件 | 多個控件組合成為一個新的控件,方便多處復用 |
繼承系統(tǒng)View控件 | 繼承自TextView等系統(tǒng)控件蝠嘉,在系統(tǒng)控件的基礎功能上進行擴展 |
繼承View | 不復用系統(tǒng)控件邏輯最疆,繼承View進行功能定義 |
繼承系統(tǒng)ViewGroup | 繼承自LinearLayout等系統(tǒng)控件,在系統(tǒng)控件的基礎功能上進行擴展 |
繼承ViewViewGroup | 不復用系統(tǒng)控件邏輯蚤告,繼承ViewGroup進行功能定義 |
詳情參考Android自定義View全解
Android有哪些序列化方式努酸?
為了解決Android中內存序列化速度過慢的問題,Android使用了Parcelable
杜恰。
對比 | Serializable | Parcelable |
---|---|---|
易用性 | 簡單 | 需要實現特定方法 |
效率 | 低 | 高 |
場景 | IO获诈、網絡和數據庫 | 內存中 |