摘要:生命周期生命周期啟動方式有兩種,一種是通過方式進行啟動,另一種是通過方式進行啟動。這種注冊方式優先級較高。虛擬機運行的是字節碼。一共有三種類型,分別是和。
1、Activity生命周期?
onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDetroy()
2、Service生命周期?service 啟動方式有兩種,一種是通過startService()方式進行啟動,另一種是通過bindService()方式進行啟動。不同的啟動方式他們的生命周期是不一樣.
通過startService()這種方式啟動的service,生命周期是這樣:調用startService() --> onCreate()--> onStartConmon()--> onDestroy()。這種方式啟動的話,需要注意一下幾個問題,第一:當我們通過startService被調用以后,多次在調用startService(),onCreate()方法也只會被調用一次,而onStartConmon()會被多次調用當我們調用stopService()的時候,onDestroy()就會被調用,從而銷毀服務。第二:當我們通過startService啟動時候,通過intent傳值,在onStartConmon()方法中獲取值的時候,一定要先判斷intent是否為null。
通過bindService()方式進行綁定,這種方式綁定service,生命周期走法:bindService-->onCreate()-->onBind()-->unBind()-->onDestroy()? bingservice 這種方式進行啟動service好處是更加便利activity中操作service,比如加入service中有幾個方法,a,b ,如果要在activity中調用,在需要在activity獲取ServiceConnection對象,通過ServiceConnection來獲取service中內部類的類對象,然后通過這個類對象就可以調用類中的方法,當然這個類需要繼承Binder對象
3、Activity的啟動過程(不要回答生命周期)app啟動的過程有兩種情況,第一種是從桌面launcher上點擊相應的應用圖標,第二種是在activity中通過調用startActivity來啟動一個新的activity。
我們創建一個新的項目,默認的根activity都是MainActivity,而所有的activity都是保存在堆棧中的,我們啟動一個新的activity就會放在上一個activity上面,而我們從桌面點擊應用圖標的時候,由于launcher本身也是一個應用,當我們點擊圖標的時候,系統就會調用startActivitySately(),一般情況下,我們所啟動的activity的相關信息都會保存在intent中,比如action,category等等。我們在安裝這個應用的時候,系統也會啟動一個PackaManagerService的管理服務,這個管理服務會對AndroidManifest.xml文件進行解析,從而得到應用程序中的相關信息,比如service,activity,Broadcast等等,然后獲得相關組件的信息。當我們點擊應用圖標的時候,就會調用startActivitySately()方法,而這個方法內部則是調用startActivty(),而startActivity()方法最終還是會調用startActivityForResult()這個方法。而在startActivityForResult()這個方法。因為startActivityForResult()方法是有返回結果的,所以系統就直接給一個-1,就表示不需要結果返回了。而startActivityForResult()這個方法實際是通過Instrumentation類中的execStartActivity()方法來啟動activity,Instrumentation這個類主要作用就是監控程序和系統之間的交互。而在這個execStartActivity()方法中會獲取ActivityManagerService的代理對象,通過這個代理對象進行啟動activity。啟動會就會調用一個checkStartActivityResult()方法,如果說沒有在配置清單中配置有這個組件,就會在這個方法中拋出異常了。當然最后是調用的是Application.scheduleLaunchActivity()進行啟動activity,而這個方法中通過獲取得到一個ActivityClientRecord對象,而這個ActivityClientRecord通過handler來進行消息的發送,系統內部會將每一個activity組件使用ActivityClientRecord對象來進行描述,而ActivityClientRecord對象中保存有一個LoaderApk對象,通過這個對象調用handleLaunchActivity來啟動activity組件,而頁面的生命周期方法也就是在這個方法中進行調用。
4、Broadcast注冊方式與區別?此處延伸:什么情況下用動態注冊
Broadcast廣播,注冊方式主要有兩種.
第一種是靜態注冊,也可成為常駐型廣播,這種廣播需要在Androidmanifest.xml中進行注冊,這中方式注冊的廣播,不受頁面生命周期的影響,即使退出了頁面,也可以收到廣播這種廣播一般用于想開機自啟動啊等等,由于這種注冊的方式的廣播是常駐型廣播,所以會占用CPU的資源。
第二種是動態注冊,而動態注冊的話,是在代碼中注冊的,這種注冊方式也叫非常駐型廣播,收到生命周期的影響,退出頁面后,就不會收到廣播,我們通常運用在更新UI方面。這種注冊方式優先級較高。最后需要解綁,否會會內存泄露
廣播是分為有序廣播和無序廣播。
5、HttpClient與HttpUrlConnection的區別?此處延伸:Volley里用的哪種請求方式(2.3前HttpClient,2.3后HttpUrlConnection)
首先HttpClient和HttpUrlConnection 這兩種方式都支持Https協議,都是以流的形式進行上傳或者下載數據,也可以說是以流的形式進行數據的傳輸,還有ipv6,以及連接池等功能。HttpClient這個擁有非常多的API,所以如果想要進行擴展的話,并且不破壞它的兼容性的話,很難進行擴展,也就是這個原因,Google在Android6.0的時候,直接就棄用了這個HttpClient.
而HttpUrlConnection相對來說就是比較輕量級了,API比較少,容易擴展,并且能夠滿足Android大部分的數據傳輸。比較經典的一個框架volley,在2.3版本以前都是使用HttpClient,在2.3以后就使用了HttpUrlConnection。
6、java虛擬機和Dalvik虛擬機的區別?Java虛擬機:
1、java虛擬機基于棧。?基于棧的機器必須使用指令來載入和操作棧上數據,所需指令更多更多。
2、java虛擬機運行的是java字節碼。(java類會被編譯成一個或多個字節碼.class文件)
Dalvik虛擬機:
1、dalvik虛擬機是基于寄存器的
2、Dalvik運行的是自定義的.dex字節碼格式。(java類被編譯成.class文件后,會通過一個dx工具將所有的.class文件轉換成一個.dex文件,然后dalvik虛擬機會從其中讀取指令和數據
3、常量池已被修改為只使用32位的索引,以 簡化解釋器。
4、一個應用,一個虛擬機實例,一個進程(所有android應用的線程都是對應一個linux線程,都運行在自己的沙盒中,不同的應用在不同的進程中運行。每個android dalvik應用程序都被賦予了一個獨立的linux PID(app_*))
7、進程保活(不死進程)此處延伸:進程的優先級是什么*
當前業界的Android進程保活手段主要分為 黑、白、灰 三種,其大致的實現思路如下:
黑色保活* :不同的app進程,用廣播相互喚醒(包括利用系統提供的廣播進行喚醒)
白色保活* :啟動前臺Service
灰色保活* :利用系統的漏洞啟動前臺Service
黑色保活*
所謂黑色保活,就是利用不同的app進程使用廣播來進行相互喚醒。舉個3個比較常見的場景:
場景1 :開機,網絡切換、拍照、拍視頻時候,利用系統產生的廣播喚醒app
場景2 :接入第三方SDK也會喚醒相應的app進程,如微信sdk會喚醒微信,支付寶sdk會喚醒支付寶。由此發散開去,就會直接觸發了下面的 場景3
場景3 :假如你手機里裝了支付寶、淘寶、天貓、UC等阿里系的app,那么你打開任意一個阿里系的app后,有可能就順便把其他阿里系的app給喚醒了。(只是拿阿里打個比方,其實BAT系都差不多)
白色保活
白色保活手段非常簡單,就是調用系統api啟動一個前臺的Service進程,這樣會在系統的通知欄生成一個Notification,用來讓用戶知道有這樣一個app在運行著,哪怕當前的app退到了后臺。如下方的LBE和QQ音樂這樣:
灰色保活
灰色保活,這種保活手段是應用范圍最廣泛。它是利用系統的漏洞來啟動一個前臺的Service進程,與普通的啟動方式區別在于,它不會在系統通知欄處出現一個Notification,看起來就如同運行著一個后臺Service進程一樣。這樣做帶來的好處就是,用戶無法察覺到你運行著一個前臺進程(因為看不到Notification),但你的進程優先級又是高于普通后臺進程的。那么如何利用系統的漏洞呢,大致的實現思路和代碼如下:
思路一:API < 18,啟動前臺Service時直接傳入new Notification();
思路二:API >= 18,同時啟動兩個id相同的前臺Service,然后再將后啟動的Service做stop處理
熟悉Android系統的童鞋都知道,系統出于體驗和性能上的考慮,app在退到后臺時系統并不會真正的kill掉這個進程,而是將其緩存起來。打開的應用越多,后臺緩存的進程也越多。在系統內存不足的情況下,系統開始依據自身的一套進程回收機制來判斷要kill掉哪些進程,以騰出內存來供給需要的app。這套殺進程回收內存的機制就叫 Low Memory Killer ,它是基于Linux內核的 OOM Killer(Out-Of-Memory killer)機制誕生。
進程的重要性,劃分5級:-
前臺進程 (Foreground process)
可見進程 (Visible process)
服務進程 (Service process)
后臺進程 (Background process)
空進程 (Empty process)
了解完 Low Memory Killer,再科普一下oom_adj。什么是oom_adj?它是linux內核分配給每個系統進程的一個值,代表進程的優先級,進程回收機制就是根據這個優先級來決定是否進行回收。對于oom_adj的作用,你只需要記住以下幾點即可:
進程的oom_adj越大,表示此進程優先級越低,越容易被殺回收;越小,表示進程優先級越高,越不容易被殺回收
普通app進程的oom_adj>=0,系統進程的oom_adj才可能<0
有些手機廠商把這些知名的app放入了自己的白名單中,保證了進程不死來提高用戶體驗(如微信、QQ、陌陌都在小米的白名單中)。如果從白名單中移除,他們終究還是和普通app一樣躲避不了被殺的命運,為了盡量避免被殺,還是老老實實去做好優化工作吧。
所以,進程保活的根本方案終究還是回到了性能優化上,進程永生不死終究是個徹頭徹尾的偽命題!
8、講解一下Context?Context是一個抽象基類。在翻譯為上下文,也可以理解為環境,是提供一些程序的運行環境基礎信息。Context下有兩個子類,ContextWrapper是上下文功能的封裝類,而ContextImpl則是上下文功能的實現類。而ContextWrapper又有三個直接的子類, ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一個帶主題的封裝類,而它有一個直接子類就是Activity,所以Activity和Service以及Application的Context是不一樣的,只有Activity需要主題,Service不需要主題。Context一共有三種類型,分別是Application、Activity和Service。這三個類雖然分別各種承擔著不同的作用,但它們都屬于Context的一種,而它們具體Context的功能則是由ContextImpl類去實現的,因此在絕大多數場景下,Activity、Service和Application這三種類型的Context都是可以通用的。不過有幾種場景比較特殊,比如啟動Activity,還有彈出Dialog。出于安全原因的考慮,Android是不允許Activity或Dialog憑空出現的,一個Activity的啟動必須要建立在另一個Activity的基礎之上,也就是以此形成的返回棧。而Dialog則必須在一個Activity上面彈出(除非是System Alert類型的Dialog),因此在這種場景下,我們只能使用Activity類型的Context,否則將會出錯。
getApplicationContext()和getApplication()方法得到的對象都是同一個application對象,只是對象的類型不一樣。
Context數量 = Activity數量 + Service數量 + 1 (1為Application)
9、理解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的事件監聽,是由WindowManagerService來接受消息,并且回調Activity函數。比如onClickListener,onKeyDown等。
10、四種LaunchMode及其使用場景此處延伸:棧(First In Last Out)與隊列(First In First Out)的區別
棧與隊列的區別:
1.?隊列先進先出,棧先進后出
2. 對插入和刪除操作的"限定"。 棧是限定只能在表的一端進行插入和刪除操作的線性表。 隊列是限定只能在表的一端進行插入和在另一端進行刪除操作的線性表。
3. 遍歷數據速度不同
standard 模式
這是默認模式,每次激活Activity時都會創建Activity實例,并放入任務棧中。使用場景:大多數Activity。
singleTop 模式
如果在任務的棧頂正好存在該Activity的實例,就重用該實例( 會調用實例的 onNewIntent() ),否則就會創建新的實例并放入棧頂,即使棧中已經存在該Activity的實例,只要不在棧頂,都會創建新的實例。使用場景如新聞類或者閱讀類App的內容頁面。
singleTask 模式
如果在棧中已經有該Activity的實例,就重用該實例(會調用實例的 onNewIntent() )。重用時,會讓該實例回到棧頂,因此在它上面的實例將會被移出棧。如果棧中不存在該實例,將會創建新的實例放入棧中。使用場景如瀏覽器的主界面。不管從多少個應用啟動瀏覽器,只會啟動主界面一次,其余情況都會走onNewIntent,并且會清空主界面上面的其他頁面。
singleInstance 模式
在一個新棧中創建該Activity的實例,并讓多個應用共享該棧中的該Activity實例。一旦該模式的Activity實例已經存在于某個棧中,任何應用再激活該Activity時都會重用該棧中的實例( 會調用實例的 onNewIntent() )。其效果相當于多個應用共享一個應用,不管誰激活該 Activity 都會進入同一個應用中。使用場景如鬧鈴提醒,將鬧鈴提醒與鬧鈴設置分離。singleInstance不要用于中間頁面,如果用于中間頁面,跳轉會有問題,比如:A -> B (singleInstance) -> C,完全退出后,在此啟動,首先打開的是B。
11、View的繪制流程自定義控件:
1、組合控件。這種自定義控件不需要我們自己繪制,而是使用原生控件組合成的新控件。如標題欄。
2、繼承原有的控件。這種自定義控件在原生控件提供的方法外,可以自己添加一些方法。如制作圓角,圓形圖片。
3、完全自定義控件:這個View上所展現的內容全部都是我們自己繪制出來的。比如說制作水波紋進度條。
View的繪制流程:OnMeasure()——>OnLayout()——>OnDraw()
第一步:OnMeasure():測量視圖大小。從頂層父View到子View遞歸調用measure方法,measure方法又回調OnMeasure。
第二步:OnLayout():確定View位置,進行頁面布局。從頂層父View向子View的遞歸調用view.layout方法的過程,即父View根據上一步measure子View所得到的布局大小和布局參數,將子View放在合適的位置上。
第三步:OnDraw():繪制視圖。ViewRoot創建一個Canvas對象,然后調用OnDraw()。六個步驟:①、繪制視圖的背景;②、保存畫布的圖層(Layer);③、繪制View的內容;④、繪制View子視圖,如果沒有就不用;
⑤、還原圖層(Layer);⑥、繪制滾動條。
12、View,ViewGroup事件分發1. Touch事件分發中只有兩個主角:ViewGroup和View。ViewGroup包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent三個相關事件。View包含dispatchTouchEvent、onTouchEvent兩個相關事件。其中ViewGroup又繼承于View。
2.ViewGroup和View組成了一個樹狀結構,根節點為Activity內部包含的一個ViwGroup。
3.觸摸事件由Action_Down、Action_Move、Aciton_UP組成,其中一次完整的觸摸事件中,Down和Up都只有一個,Move有若干個,可以為0個。
4.當Acitivty接收到Touch事件時,將遍歷子View進行Down事件的分發。ViewGroup的遍歷可以看成是遞歸的。分發的目的是為了找到真正要處理本次完整觸摸事件的View,這個View會在onTouchuEvent結果返回true。
5.當某個子View返回true時,會中止Down事件的分發,同時在ViewGroup中記錄該子View。接下去的Move和Up事件將由該子View直接進行處理。由于子View是保存在ViewGroup中的,多層ViewGroup的節點結構時,上級ViewGroup保存的會是真實處理事件的View所在的ViewGroup對象:如ViewGroup0-ViewGroup1-TextView的結構中,TextView返回了true,它將被保存在ViewGroup1中,而ViewGroup1也會返回true,被保存在ViewGroup0中。當Move和UP事件來時,會先從ViewGroup0傳遞至ViewGroup1,再由ViewGroup1傳遞至TextView。
6.當ViewGroup中所有子View都不捕獲Down事件時,將觸發ViewGroup自身的onTouch事件。觸發的方式是調用super.dispatchTouchEvent函數,即父類View的dispatchTouchEvent方法。在所有子View都不處理的情況下,觸發Acitivity的onTouchEvent方法。
7.onInterceptTouchEvent有兩個作用:1.攔截Down事件的分發。2.中止Up和Move事件向目標View傳遞,使得目標View所在的ViewGroup捕獲Up和Move事件。
13、保存Activity狀態onSaveInstanceState(Bundle)會在activity轉入后臺狀態之前被調用,也就是onStop()方法之前,onPause方法之后被調用;
14、Android中的幾種動畫幀動畫:指通過指定每一幀的圖片和播放時間,有序的進行播放而形成動畫效果,比如想聽的律動條。
補間動畫:指通過指定View的初始狀態、變化時間、方式,通過一系列的算法去進行圖形變換,從而形成動畫效果,主要有Alpha、Scale、Translate、Rotate四種效果。注意:只是在視圖層實現了動畫效果,并沒有真正改變View的屬性,比如滑動列表,改變標題欄的透明度。
屬性動畫:在Android3.0的時候才支持,通過不斷的改變View的屬性,不斷的重繪而形成動畫效果。相比于視圖動畫,View的屬性是真正改變了。比如view的旋轉,放大,縮小。
15、Android中跨進程通訊的幾種方式Android 跨進程通信,像intent,contentProvider,廣播,service都可以跨進程通信。
intent:這種跨進程方式并不是訪問內存的形式,它需要傳遞一個uri,比如說打電話。
contentProvider:這種形式,是使用數據共享的形式進行數據共享。
service:遠程服務,aidl
廣播
16、AIDL理解此處延伸:簡述Binder
AIDL: 每一個進程都有自己的Dalvik VM實例,都有自己的一塊獨立的內存,都在自己的內存上存儲自己的數據,執行著自己的操作,都在自己的那片狹小的空間里過完自己的一生。而aidl就類似與兩個進程之間的橋梁,使得兩個進程之間可以進行數據的傳輸,跨進程通信有多種選擇,比如 BroadcastReceiver , Messenger 等,但是 BroadcastReceiver 占用的系統資源比較多,如果是頻繁的跨進程通信的話顯然是不可取的;Messenger 進行跨進程通信時請求隊列是同步進行的,無法并發執行。
Binde機制簡單理解:
在Android系統的Binder機制中,是有Client,Service,ServiceManager,Binder驅動程序組成的,其中Client,service,Service Manager運行在用戶空間,Binder驅動程序是運行在內核空間的。而Binder就是把這4種組件粘合在一塊的粘合劑,其中核心的組件就是Binder驅動程序,Service Manager提供輔助管理的功能,而Client和Service正是在Binder驅動程序和Service Manager提供的基礎設施上實現C/S 之間的通信。其中Binder驅動程序提供設備文件/dev/binder與用戶控件進行交互,
Client、Service,Service Manager通過open和ioctl文件操作相應的方法與Binder驅動程序進行通信。而Client和Service之間的進程間通信是通過Binder驅動程序間接實現的。而Binder Manager是一個守護進程,用來管理Service,并向Client提供查詢Service接口的能力。
17、Handler的原理Android中主線程是不能進行耗時操作的,子線程是不能進行更新UI的。所以就有了handler,它的作用就是實現線程之間的通信。
handler整個流程中,主要有四個對象,handler,Message,MessageQueue,Looper。當應用創建的時候,就會在主線程中創建handler對象,
我們通過要傳送的消息保存到Message中,handler通過調用sendMessage方法將Message發送到MessageQueue中,Looper對象就會不斷的調用loop()方法
不斷的從MessageQueue中取出Message交給handler進行處理。從而實現線程之間的通信。
18、Binder機制原理在Android系統的Binder機制中,是有Client,Service,ServiceManager,Binder驅動程序組成的,其中Client,service,Service Manager運行在用戶空間,Binder驅動程序是運行在內核空間的。而Binder就是把這4種組件粘合在一塊的粘合劑,其中核心的組件就是Binder驅動程序,Service Manager提供輔助管理的功能,而Client和Service正是在Binder驅動程序和Service Manager提供的基礎設施上實現C/S 之間的通信。其中Binder驅動程序提供設備文件/dev/binder與用戶控件進行交互,Client、Service,Service Manager通過open和ioctl文件操作相應的方法與Binder驅動程序進行通信。而Client和Service之間的進程間通信是通過Binder驅動程序間接實現的。而Binder Manager是一個守護進程,用來管理Service,并向Client提供查詢Service接口的能力。
19、熱修復的原理我們知道Java虛擬機 —— JVM 是加載類的class文件的,而Android虛擬機——Dalvik/ART VM 是加載類的dex文件,
而他們加載類的時候都需要ClassLoader,ClassLoader有一個子類BaseDexClassLoader,而BaseDexClassLoader下有一個
數組——DexPathList,是用來存放dex文件,當BaseDexClassLoader通過調用findClass方法時,實際上就是遍歷數組,
找到相應的dex文件,找到,則直接將它return。而熱修復的解決方法就是將新的dex添加到該集合中,并且是在舊的dex的前面,
所以就會優先被取出來并且return返回。
20、Android內存泄露及管理(1)內存溢出(OOM)和內存泄露(對象無法被回收)的區別。?
(2)引起內存泄露的原因
(3) 內存泄露檢測工具 ------>LeakCanary
內存溢出 out of memory:是指程序在申請內存時,沒有足夠的內存空間供其使用,出現out of memory;比如申請了一個integer,但給它存了long才能存下的數,那就是內存溢出。內存溢出通俗的講就是內存不夠用。
內存泄露 memory leak:是指程序在申請內存后,無法釋放已申請的內存空間,一次內存泄露危害可以忽略,但內存泄露堆積后果很嚴重,無論多少內存,遲早會被占光
內存泄露原因: 一、Handler 引起的內存泄漏。解決:將Handler聲明為靜態內部類,就不會持有外部類SecondActivity的引用,其生命周期就和外部類無關,
如果Handler里面需要context的話,可以通過弱引用方式引用外部類
二、單例模式引起的內存泄漏。解決:Context是ApplicationContext,由于ApplicationContext的生命周期是和app一致的,不會導致內存泄漏
三、非靜態內部類創建靜態實例引起的內存泄漏。解決:把內部類修改為靜態的就可以避免內存泄漏了
四、非靜態匿名內部類引起的內存泄漏。解決:將匿名內部類設置為靜態的。
五、注冊/反注冊未成對使用引起的內存泄漏。注冊廣播接受器、EventBus等,記得解綁。
六、資源對象沒有關閉引起的內存泄漏。在這些資源不使用的時候,記得調用相應的類似close()、destroy()、recycler()、release()等方法釋放。
七、集合對象沒有及時清理引起的內存泄漏。通常會把一些對象裝入到集合中,當不使用的時候一定要記得及時清理集合,讓相關對象不再被引用。
21、Fragment與Fragment、Activity通信的方式1.直接在一個Fragment中調用另外一個Fragment中的方法
2.使用接口回調
3.使用廣播
4.Fragment直接調用Activity中的public方法
22、Android UI適配字體使用sp,使用dp,多使用match_parent,wrap_content,weight
圖片資源,不同圖片的的分辨率,放在相應的文件夾下可使用百分比代替。
23、app優化app優化:(工具:Hierarchy Viewer 分析布局? 工具:TraceView 測試分析耗時的)
App啟動優化
布局優化
響應優化
內存優化
電池使用優化
網絡優化
App啟動優化(針對冷啟動)
App啟動的方式有三種:
冷啟動:App沒有啟動過或App進程被killed, 系統中不存在該App進程, 此時啟動App即為冷啟動。
熱啟動:熱啟動意味著你的App進程只是處于后臺, 系統只是將其從后臺帶到前臺, 展示給用戶。
介于冷啟動和熱啟動之間, 一般來說在以下兩種情況下發生:
(1)用戶back退出了App, 然后又啟動. App進程可能還在運行, 但是activity需要重建。
(2)用戶退出App后, 系統可能由于內存原因將App殺死, 進程和activity都需要重啟, 但是可以在onCreate中將被動殺死鎖保存的狀態(saved instance state)恢復。
優化:
Application的onCreate(特別是第三方SDK初始化),首屏Activity的渲染都不要進行耗時操作,如果有,就可以放到子線程或者IntentService中
布局優化
盡量不要過于復雜的嵌套。可以使用
響應優化
Android系統每隔16ms會發出VSYNC信號重繪我們的界面(Activity)。
頁面卡頓的原因:
(1)過于復雜的布局.
(2)UI線程的復雜運算
(3)頻繁的GC,導致頻繁GC有兩個原因:1、內存抖動, 即大量的對象被創建又在短時間內馬上被釋放.2、瞬間產生大量的對象會嚴重占用內存區域。
內存優化:參考內存泄露和內存溢出部分
電池使用優化(使用工具:Batterystats & bugreport)
(1)優化網絡請求
(2)定位中使用GPS, 請記得及時關閉
網絡優化(網絡連接對用戶的影響:流量,電量,用戶等待)可在Android studio下方logcat旁邊那個工具Network Monitor檢測
API設計:App與Server之間的API設計要考慮網絡請求的頻次, 資源的狀態等. 以便App可以以較少的請求來完成業務需求和界面的展示.
Gzip壓縮:使用Gzip來壓縮request和response, 減少傳輸數據量, 從而減少流量消耗.
圖片的Size:可以在獲取圖片時告知服務器需要的圖片的寬高, 以便服務器給出合適的圖片, 避免浪費.
網絡緩存:適當的緩存, 既可以讓我們的應用看起來更快, 也能避免一些不必要的流量消耗.
24、圖片優化(1)對圖片本身進行操作。盡量不要使用setImageBitmap、setImageResource、BitmapFactory.decodeResource來設置一張大圖,因為這些方法在完成decode后,
最終都是通過java層的createBitmap來完成的,需要消耗更多內存.
(2)圖片進行縮放的比例,SDK中建議其值是2的指數值,值越大會導致圖片不清晰。
(3)不用的圖片記得調用圖片的recycle()方法
25、HybridApp WebView和JS交互Android與JS通過WebView互相調用方法,實際上是:
Android去調用JS的代碼
1. 通過WebView的loadUrl(),使用該方法比較簡潔,方便。但是效率比較低,獲取返回值比較困難。
2. 通過WebView的evaluateJavascript(),該方法效率高,但是4.4以上的版本才支持,4.4以下版本不支持。所以建議兩者混合使用。
JS去調用Android的代碼
1. 通過WebView的addJavascriptInterface()進行對象映射 ,該方法使用簡單,僅將Android對象和JS對象映射即可,但是存在比較大的漏洞。
漏洞產生原因是:當JS拿到Android這個對象后,就可以調用這個Android對象中所有的方法,包括系統類(java.lang.Runtime 類),從而進行任意代碼執行。
解決方式:
(1)Google 在Android 4.2 版本中規定對被調用的函數以 @JavascriptInterface進行注解從而避免漏洞攻擊。
(2)在Android 4.2版本之前采用攔截prompt()進行漏洞修復。
2. 通過 WebViewClient 的shouldOverrideUrlLoading ()方法回調攔截 url 。這種方式的優點:不存在方式1的漏洞;缺點:JS獲取Android方法的返回值復雜。(ios主要用的是這個方式)
(1)Android通過 WebViewClient 的回調方法shouldOverrideUrlLoading ()攔截 url
(2)解析該 url 的協議
(3)如果檢測到是預先約定好的協議,就調用相應方法
3. 通過 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回調攔截JS對話框alert()、confirm()、prompt() 消息
這種方式的優點:不存在方式1的漏洞;缺點:JS獲取Android方法的返回值復雜。
26、JAVA GC原理垃圾收集算法的核心思想是:對虛擬機可用內存空間,即堆空間中的對象進行識別,如果對象正在被引用,那么稱其為存活對象
,反之,如果對象不再被引用,則為垃圾對象,可以回收其占據的空間,用于再分配。垃圾收集算法的選擇和垃圾收集系統參數的合理調節直接影響著系統性能。
27、ANRANR全名Application Not Responding, 也就是"應用無響應". 當操作在一段時間內系統無法處理時, 系統層面會彈出上圖那樣的ANR對話框.
產生原因:
(1)5s內無法響應用戶輸入事件(例如鍵盤輸入, 觸摸屏幕等).
(2)BroadcastReceiver在10s內無法結束
(3)Service 20s內無法結束(低概率)
解決方式:(1)不要在主線程中做耗時的操作,而應放在子線程中來實現。如onCreate()和onResume()里盡可能少的去做創建操作。
(2)應用程序應該避免在BroadcastReceiver里做耗時的操作或計算。
(3)避免在Intent Receiver里啟動一個Activity,因為它會創建一個新的畫面,并從當前用戶正在運行的程序上搶奪焦點。
(4)service是運行在主線程的,所以在service中做耗時操作,必須要放在子線程中。
28、設計模式此處延伸:Double Check的寫法被要求寫出來。
單例模式:分為惡漢式和懶漢式
餓漢式:
public class Singleton? {? ??? private static Singleton instance = new Singleton();? ??? public static Singleton getInstance()? ??? {? ??????? return instance ;? ??? }? }
懶漢式:
public class Singleton02? {? ??? private static Singleton02 instance;? ??? public static Singleton02 getInstance()? ??? {? ??????? if (instance == null)? ??????? {? ??????????? synchronized (Singleton02.class)? ??????????? {? ??????????????? if (instance == null)? ???????? ???????{? ??????????????????? instance = new Singleton02();? ??????????????? }? ??????????? }? ??????? }? ??????? return instance;? ??? }? }29、RxJava 30、MVP,MVC,MVVM
此處延伸:手寫mvp例子,與mvc之間的區別,mvp的優勢
MVP模式,對應著Model--業務邏輯和實體模型,view--對應著activity,負責View的繪制以及與用戶交互,Presenter--負責View和Model之間的交互,MVP模式是在MVC模式的基礎上,將Model與View徹底分離使得項目的耦合性更低,在Mvc中項目中的activity對應著mvc中的C--Controllor,而項目中的邏輯處理都是在這個C中處理,同時View與Model之間的交互,也是也就是說,mvc中所有的邏輯交互和用戶交互,都是放在Controllor中,也就是activity中。View和model是可以直接通信的。而MVP模式則是分離的更加徹底,分工更加明確Model--業務邏輯和實體模型,view--負責與用戶交互,Presenter 負責完成View于Model間的交互,MVP和MVC最大的區別是MVC中是允許Model和View進行交互的,而MVP中很明顯,Model與View之間的交互由Presenter完成。還有一點就是Presenter與View之間的交互是通過接口的
31、手寫算法(選擇冒泡必須要會) 32、JNI?(1)安裝和下載Cygwin,下載 Android NDK
(2)在ndk項目中JNI接口的設計
(3)使用C/C++實現本地方法
(4)JNI生成動態鏈接庫.so文件
(5)將動態鏈接庫復制到java工程,在java工程中調用,運行java工程即可
33、RecyclerView和ListView的區別RecyclerView可以完成ListView,GridView的效果,還可以完成瀑布流的效果。同時還可以設置列表的滾動方向(垂直或者水平);
RecyclerView中view的復用不需要開發者自己寫代碼,系統已經幫封裝完成了。
RecyclerView可以進行局部刷新。
RecyclerView提供了API來實現item的動畫效果。
在性能上:
如果需要頻繁的刷新數據,需要添加動畫,則RecyclerView有較大的優勢。
如果只是作為列表展示,則兩者區別并不是很大。
34、Universal-ImageLoader,Picasso,Fresco,Glide對比Fresco 是 Facebook 推出的開源圖片緩存工具,主要特點包括:兩個內存緩存加上 Native 緩存構成了三級緩存,
優點:
1. 圖片存儲在安卓系統的匿名共享內存, 而不是虛擬機的堆內存中, 圖片的中間緩沖數據也存放在本地堆內存, 所以, 應用程序有更多的內存使用, 不會因為圖片加載而導致oom, 同時也減少垃圾回收器頻繁調用回收 Bitmap 導致的界面卡頓, 性能更高。
2. 漸進式加載 JPEG 圖片, 支持圖片從模糊到清晰加載。
3. 圖片可以以任意的中心點顯示在 ImageView, 而不僅僅是圖片的中心。
4. JPEG 圖片改變大小也是在 native 進行的, 不是在虛擬機的堆內存, 同樣減少 OOM。
5. 很好的支持 GIF 圖片的顯示。
缺點:
1. 框架較大, 影響 Apk 體積
2. 使用較繁瑣
Universal-ImageLoader:(估計由于HttpClient被Google放棄,作者就放棄維護這個框架)
優點:
1.支持下載進度監聽
2.可以在 View 滾動中暫停圖片加載,通過 PauseOnScrollListener 接口可以在 View 滾動中暫停圖片加載。
3.默認實現多種內存緩存算法 這幾個圖片緩存都可以配置緩存算法,不過 ImageLoader 默認實現了較多緩存算法,如 Size 最大先刪除、使用最少先刪除、最近最少使用、先進先刪除、時間最長先刪除等。
4.支持本地緩存文件名規則定義
Picasso 優點1. 自帶統計監控功能。支持圖片緩存使用的監控,包括緩存命中率、已使用內存大小、節省的流量等。
2.支持優先級處理。每次任務調度前會選擇優先級高的任務,比如 App 頁面中 Banner 的優先級高于 Icon 時就很適用。
3.支持延遲到圖片尺寸計算完成加載
4.支持飛行模式、并發線程數根據網絡類型而變。 手機切換到飛行模式或網絡類型變換時會自動調整線程池最大并發數,比如 wifi 最大并發為 4,4g 為 3,3g 為 2。? 這里 Picasso 根據網絡類型來決定最大并發數,而不是 CPU 核數。
5.“無”本地緩存。無”本地緩存,不是說沒有本地緩存,而是 Picasso 自己沒有實現,交給了 Square 的另外一個網絡庫 okhttp 去實現,這樣的好處是可以通過請求 Response Header 中的 Cache-Control 及 Expired 控制圖片的過期時間。
?Glide 優點1. 不僅僅可以進行圖片緩存還可以緩存媒體文件。Glide 不僅是一個圖片緩存,它支持 Gif、WebP、縮略圖。甚至是 Video,所以更該當做一個媒體緩存。
2. 支持優先級處理。
3. 與 Activity/Fragment 生命周期一致,支持 trimMemory。Glide 對每個 context 都保持一個 RequestManager,通過 FragmentTransaction 保持與 Activity/Fragment 生命周期一致,并且有對應的 trimMemory 接口實現可供調用。
4. 支持 okhttp、Volley。Glide 默認通過 UrlConnection 獲取數據,可以配合 okhttp 或是 Volley 使用。實際 ImageLoader、Picasso 也都支持 okhttp、Volley。
5. 內存友好。Glide 的內存緩存有個 active 的設計,從內存緩存中取數據時,不像一般的實現用 get,而是用 remove,再將這個緩存數據放到一個 value 為軟引用的 activeResources map 中,并計數引用數,在圖片加載完成后進行判斷,如果引用計數為空則回收掉。內存緩存更小圖片,Glide 以 url、view_width、view_height、屏幕的分辨率等做為聯合 key,將處理后的圖片緩存在內存緩存中,而不是原始圖片以節省大小與 Activity/Fragment 生命周期一致,支持 trimMemory。圖片默認使用默認 RGB_565 而不是 ARGB_888,雖然清晰度差些,但圖片更小,也可配置到 ARGB_888。
6.Glide 可以通過 signature 或不使用本地緩存支持 url 過期
42、Xutils, OKhttp, Volley, Retrofit對比Xutils這個框架非常全面,可以進行網絡請求,可以進行圖片加載處理,可以數據儲存,還可以對view進行注解,使用這個框架非常方便,但是缺點也是非常明顯的,使用這個項目,會導致項目對這個框架依賴非常的嚴重,一旦這個框架出現問題,那么對項目來說影響非常大的。、
OKhttp:Android開發中是可以直接使用現成的api進行網絡請求的。就是使用HttpClient,HttpUrlConnection進行操作。okhttp針對Java和Android程序,封裝的一個高性能的http請求庫,支持同步,異步,而且okhttp又封裝了線程池,封裝了數據轉換,封裝了參數的使用,錯誤處理等。API使用起來更加的方便。但是我們在項目中使用的時候仍然需要自己在做一層封裝,這樣才能使用的更加的順手。
Volley:Volley是Google官方出的一套小而巧的異步請求庫,該框架封裝的擴展性很強,支持HttpClient、HttpUrlConnection, 甚至支持OkHttp,而且Volley里面也封裝了ImageLoader,所以如果你愿意你甚至不需要使用圖片加載框架,不過這塊功能沒有一些專門的圖片加載框架強大,對于簡單的需求可以使用,稍復雜點的需求還是需要用到專門的圖片加載框架。Volley也有缺陷,比如不支持post大數據,所以不適合上傳文件。不過Volley設計的初衷本身也就是為頻繁的、數據量小的網絡請求而生。
Retrofit:Retrofit是Square公司出品的默認基于OkHttp封裝的一套RESTful網絡請求框架,RESTful是目前流行的一套api設計的風格, 并不是標準。Retrofit的封裝可以說是很強大,里面涉及到一堆的設計模式,可以通過注解直接配置請求,可以使用不同的http客戶端,雖然默認是用http ,可以使用不同Json Converter 來序列化數據,同時提供對RxJava的支持,使用Retrofit + OkHttp + RxJava + Dagger2 可以說是目前比較潮的一套框架,但是需要有比較高的門檻。
Volley VS OkHttp
Volley的優勢在于封裝的更好,而使用OkHttp你需要有足夠的能力再進行一次封裝。而OkHttp的優勢在于性能更高,因為 OkHttp基于NIO和Okio ,所以性能上要比 Volley更快。IO 和 NIO這兩個都是Java中的概念,如果我從硬盤讀取數據,第一種方式就是程序一直等,數據讀完后才能繼續操作這種是最簡單的也叫阻塞式IO,還有一種是你讀你的,程序接著往下執行,等數據處理完你再來通知我,然后再處理回調。而第二種就是 NIO 的方式,非阻塞式, 所以NIO當然要比IO的性能要好了,而 Okio是 Square 公司基于IO和NIO基礎上做的一個更簡單、高效處理數據流的一個庫。理論上如果Volley和OkHttp對比的話,更傾向于使用 Volley,因為Volley內部同樣支持使用OkHttp,這點OkHttp的性能優勢就沒了,? 而且 Volley 本身封裝的也更易用,擴展性更好些。
OkHttp VS Retrofit
毫無疑問,Retrofit 默認是基于 OkHttp 而做的封裝,這點來說沒有可比性,肯定首選 Retrofit。
Volley VS Retrofit
這兩個庫都做了不錯的封裝,但Retrofit解耦的更徹底,尤其Retrofit2.0出來,Jake對之前1.0設計不合理的地方做了大量重構, 職責更細分,而且Retrofit默認使用OkHttp,性能上也要比Volley占優勢,再有如果你的項目如果采用了RxJava ,那更該使用? Retrofit 。所以這兩個庫相比,Retrofit更有優勢,在能掌握兩個框架的前提下該優先使用 Retrofit。但是Retrofit門檻要比Volley稍高些,要理解他的原理,各種用法,想徹底搞明白還是需要花些功夫的,如果你對它一知半解,那還是建議在商業項目使用Volley吧。
Java 1、線程中sleep和wait的區別(1)這兩個方法來自不同的類,sleep是來自Thread,wait是來自Object;
(2)sleep方法沒有釋放鎖,而wait方法釋放了鎖。
(3)wait,notify,notifyAll只能在同步控制方法或者同步控制塊里面使用,而sleep可以在任何地方使用。
2、Thread中的start()和run()方法有什么區別start()方法是用來啟動新創建的線程,而start()內部調用了run()方法,這和直接調用run()方法是不一樣的,如果直接調用run()方法,
則和普通的方法沒有什么區別。
3、關鍵字final和static是怎么使用的。1、final變量即為常量,只能賦值一次。
2、final方法不能被子類重寫。
3、final類不能被繼承。
1、static變量:對于靜態變量在內存中只有一個拷貝(節省內存),JVM只為靜態分配一次內存,
在加載類的過程中完成靜態變量的內存分配,可用類名直接訪問(方便),當然也可以通過對象來訪問(但是這是不推薦的)。
2、static代碼塊
?static代碼塊是類加載時,初始化自動執行的。
3、static方法
static方法可以直接通過類名調用,任何的實例也都可以調用,因此static方法中不能用this和super關鍵字,
不能直接訪問所屬類的實例變量和實例方法(就是不帶static的成員變量和成員成員方法),只能訪問所屬類的靜態成員變量和成員方法。
4、String,StringBuffer,StringBuilder區別
1、三者在執行速度上:StringBuilder > StringBuffer > String (由于String是常量,不可改變,拼接時會重新創建新的對象)。
2、StringBuffer是線程安全的,StringBuilder是線程不安全的。(由于StringBuffer有緩沖區)
5、Java中重載和重寫的區別:1、重載:一個類中可以有多個相同方法名的,但是參數類型和個數都不一樣。這是重載。
2、重寫:子類繼承父類,則子類可以通過實現父類中的方法,從而新的方法把父類舊的方法覆蓋。
6、Http https區別此處延伸:https的實現原理
1、https協議需要到ca申請證書,一般免費證書較少,因而需要一定費用。
2、http是超文本傳輸協議,信息是明文傳輸,https則是具有安全性的ssl加密傳輸協議。
3、http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,后者是443。
4、http的連接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。
https實現原理:
(1)客戶使用https的URL訪問Web服務器,要求與Web服務器建立SSL連接。
(2)Web服務器收到客戶端請求后,會將網站的證書信息(證書中包含公鑰)傳送一份給客戶端。
(3)客戶端的瀏覽器與Web服務器開始協商SSL連接的安全等級,也就是信息加密的等級。
(4)客戶端的瀏覽器根據雙方同意的安全等級,建立會話密鑰,然后利用網站的公鑰將會話密鑰加密,并傳送給網站。
(5)Web服務器利用自己的私鑰解密出會話密鑰。
(6)Web服務器利用會話密鑰加密與客戶端之間的通信。
7、Http位于TCP/IP模型中的第幾層?為什么說Http是可靠的數據傳輸協議?tcp/ip的五層模型:
從下到上:物理層->數據鏈路層->網絡層->傳輸層->應用層
其中tcp/ip位于模型中的網絡層,處于同一層的還有ICMP(網絡控制信息協議)。http位于模型中的應用層
由于tcp/ip是面向連接的可靠協議,而http是在傳輸層基于tcp/ip協議的,所以說http是可靠的數據傳輸協議。
8、HTTP鏈接的特點HTTP連接最顯著的特點是客戶端發送的每次請求都需要服務器回送響應,在請求結束后,會主動釋放連接。
從建立連接到關閉連接的過程稱為“一次連接”。
9、TCP和UDP的區別tcp是面向連接的,由于tcp連接需要三次握手,所以能夠最低限度的降低風險,保證連接的可靠性。
udp 不是面向連接的,udp建立連接前不需要與對象建立連接,無論是發送還是接收,都沒有發送確認信號。所以說udp是不可靠的。
由于udp不需要進行確認連接,使得UDP的開銷更小,傳輸速率更高,所以實時行更好。
10、Socket建立網絡連接的步驟建立Socket連接至少需要一對套接字,其中一個運行與客戶端--ClientSocket,一個運行于服務端--ServiceSocket
1、服務器監聽:服務器端套接字并不定位具體的客戶端套接字,而是處于等待連接的狀態,實時監控網絡狀態,等待客戶端的連接請求。
2、客戶端請求:指客戶端的套接字提出連接請求,要連接的目標是服務器端的套接字。注意:客戶端的套接字必須描述他要連接的服務器的套接字,
指出服務器套接字的地址和端口號,然后就像服務器端套接字提出連接請求。
3、連接確認:當服務器端套接字監聽到客戶端套接字的連接請求時,就響應客戶端套接字的請求,建立一個新的線程,把服務器端套接字的描述
發給客戶端,一旦客戶端確認了此描述,雙方就正式建立連接。而服務端套接字則繼續處于監聽狀態,繼續接收其他客戶端套接字的連接請求。
11、Tcp/IP三次握手,四次揮手【問題1】為什么連接的時候是三次握手,關閉的時候卻是四次握手?
答:因為當Server端收到Client端的SYN連接請求報文后,可以直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連接時,當Server端收到FIN報文時,很可能并不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端所有的報文都發送完了,我才能發送FIN報文,因此不能一起發送。故需要四步握手。
【問題2】為什么TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?
答:雖然按道理,四個報文都發送完畢,我們可以直接進入CLOSE狀態了,但是我們必須假象網絡是不可靠的,有可以最后一個ACK丟失。所以TIME_WAIT狀態就是用來重發可能丟失的ACK報文。在Client發送出最后的ACK回復,但該ACK可能丟失。Server如果沒有收到ACK,將不斷重復發送FIN片段。所以Client不能立即關閉,它必須確認Server接收到了該ACK。Client會在發送出ACK之后進入到TIME_WAIT狀態。Client會設置一個計時器,等待2MSL的時間。如果在該時間內再次收到FIN,那么Client會重發ACK并再次等待2MSL。所謂的2MSL是兩倍的MSL(Maximum Segment Lifetime)。MSL指一個片段在網絡中最大的存活時間,2MSL就是一個發送和一個回復所需的最大時間。如果直到2MSL,Client都沒有再次收到FIN,那么Client推斷ACK已經被成功接收,則結束TCP連接。
【問題3】為什么不能用兩次握手進行連接?
答:3次握手完成兩個重要的功能,既要雙方做好發送數據的準備工作(雙方都知道彼此已準備好),也要允許雙方就初始序列號進行協商,這個序列號在握手過程中被發送和確認。
現在把三次握手改成僅需要兩次握手,死鎖是可能發生的。作為例子,考慮計算機S和C之間的通信,假定C給S發送一個連接請求分組,S收到了這個分組,并發 送了確認應答分組。按照兩次握手的協定,S認為連接已經成功地建立了,可以開始發送數據分組。可是,C在S的應答分組在傳輸中被丟失的情況下,將不知道S 是否已準備好,不知道S建立什么樣的序列號,C甚至懷疑S是否收到自己的連接請求分組。在這種情況下,C認為連接還未建立成功,將忽略S發來的任何數據分 組,只等待連接確認應答分組。而S在發出的分組超時后,重復發送同樣的分組。這樣就形成了死鎖。
【問題4】如果已經建立了連接,但是客戶端突然出現故障了怎么辦?
TCP還設有一個保活計時器,顯然,客戶端如果出現故障,服務器不能一直等下去,白白浪費資源。服務器每收到一次客戶端的請求后都會重新復位這個計時器,時間通常是設置為2小時,若兩小時還沒有收到客戶端的任何數據,服務器就會發送一個探測報文段,以后每隔75分鐘發送一次。若一連發送10個探測報文仍然沒反應,服務器就認為客戶端出了故障,接著就關閉連接。
原文地址: https://www.cnblogs.com/huang...,轉載請注明原創
閱讀更多
近3年BAT面試真題整理合集
?一招教你讀懂JVM和Dalvik之間的區別
NDK項目實戰—高仿360手機助手之卸載監聽
kotlin學習筆記-異常好玩的list集合總結
相信自己,沒有做不到的,只有想不到的在這里獲得的不僅僅是技術!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71648.html
摘要:線程池可以用來解決處理一個特定請求最大線程數量限制問題。安撫多歲的發發發線程池的作用線程池作用就是限制系統中執行線程的數量。若隊列中沒有等待進程,線程池的這一資源處于等待。此線程池支持定時以及周期性執行任務的需求。 前言 面試中我們經常會遇到多線程和線程池的問題,究竟如何回答呢?今天關于Java中的線程池,我們就來學習一下。 什么是線程池 線程池是指在初始化一個多線程應用程序過程中創建...
摘要:線程池可以用來解決處理一個特定請求最大線程數量限制問題。安撫多歲的發發發線程池的作用線程池作用就是限制系統中執行線程的數量。若隊列中沒有等待進程,線程池的這一資源處于等待。此線程池支持定時以及周期性執行任務的需求。 前言 面試中我們經常會遇到多線程和線程池的問題,究竟如何回答呢?今天關于Java中的線程池,我們就來學習一下。 什么是線程池 線程池是指在初始化一個多線程應用程序過程中創建...
閱讀 2102·2021-11-19 09:58
閱讀 1701·2021-11-15 11:36
閱讀 2867·2019-08-30 15:54
閱讀 3386·2019-08-29 15:07
閱讀 2759·2019-08-26 11:47
閱讀 2805·2019-08-26 10:11
閱讀 2496·2019-08-23 18:22
閱讀 2744·2019-08-23 17:58