很不幸,今年是一個非常不平平凡的年,由於種種原因,現在加入找工作的行列中,記錄面試中所問到的基礎與技術問題。
1、內存泄露如何查看和解決
概念:有些對象只有有限的生命週期,當他們的任務完成之後,它們將被垃圾回收,如果在對象的生命週期本該結束的時候,這個對象還被一系列的引用,着就會導致內存泄露。
解決方法:使用開源框架LeakCanary檢測針對性解決
常見的內存泄露有:
單例造成的內存泄露,例如單例中的Context生命週期大於本身Context生命週期
線程使用Hander造成的內存卸扣,當activity已經結束,線程依然在運行更新UI
非靜態類使用靜態變量導致無法回收釋放造成泄露
WebView網頁過多造成內存泄露
資源未關閉造成泄露,例如數據庫使用完之後關閉連接
2、Service啓動方式
1.startService
①.定義一個類繼承service
②.在manifest.xml文件中配置該service
③.使用context的startService(intent)啓動該service
④.不再使用時,調用stopService(Intent)停止該服務
2.bindService
①.創建bindService服務段,繼承自service並在類中,創建一個實現binder接口的實例對象並提供公共方法給客戶端調用
②.從onbind()回調方法返回此binder實例
③.在客戶端中,從onserviceconnected()回調方法接收binder,並使用提供的方法調用綁定服務
3,談MVC ,MVP,MVVM
MVC:View是可以直接訪問Model的!從而,View裏會包含Model信息,不可避免的還要包括一些 業務邏輯。 在MVC模型裏,更關注的Model的不變,而同時有多個對Model的不同顯示,及View。所以,在MVC模型裏,Model不依賴於View,但是 View是依賴於Model的。不僅如此,因爲有一些業務邏輯在View裏實現了,導致要更改View也是比較困難的,至少那些業務邏輯是無法重用的。
MVP:MVP 是從經典的模式MVC演變而來,它們的基本思想有相通的地方:Controller/Presenter負責邏輯的處理,Model提供數據,View負 責顯示。作爲一種新的模式,MVP與MVC有着一個重大的區別:在MVP中View並不直接使用Model,它們之間的通信是通過Presenter (MVC中的Controller)來進行的,所有的交互都發生在Presenter內部,而在MVC中View會從直接Model中讀取數據而不是通過 Controller。
MVVM:數據雙向綁定,通過數據驅動UI,M提供數據,V視圖,VM即數據驅動層
4、Hander原理
Handler,loop輪詢檢測發送消息到MessagerQuery,MessageQuery對Message入列,Handler回調方法處理消息,重寫handMessage方法刷新ui
5、重載(Overloading)與重寫(Overriding)
重載:
重載發生在本類,方法名相同,參數列表不同,與返回值無關,只和方法名,參數列表,參數的類型有關.
重載(Overload):首先是位於一個類之中或者其子類中,具有相同的方法名,但是方法的參數不同,返回值類型可以相同也可以不同。
(1):方法名必須相同
(2):方法的參數列表一定不一樣。
(3):訪問修飾符和返回值類型可以相同也可以不同。
例:
public class Test {
public void out(){
System.out.println("參數"+null);
}
//參數數目不同
public void out(Integer n){
System.out.println("參數"+n.getClass().getName());
}
//參數類型不同
public void out(String string){
System.out.println("參數"+string.getClass().getName());
}
public void out(Integer n ,String string){
System.out.println("參數"+n.getClass().getName()+","+string.getClass().getName());
}
//參數順序不同
public void out(String string,Integer n){
System.out.println("參數"+string.getClass().getName()+","+n.getClass().getName());
}
public static void main(String[] args) {
Test test = new Test();
test.out();
test.out(1);
test.out("string");
test.out(1,"string");
test.out("string",1);
}
}
重寫
重寫發生在父類子類之間,比如所有類都是繼承與Object類的,Object類中本身就有equals,hashcode,toString方法等.在任意子類中定義了重名和同樣的參數列表就構成方法重寫.
重寫(override):一般都是表示子類和父類之間的關係,其主要的特徵是:方法名相同,參數相同,但是具體的實現不同。
重寫的特徵:
(1):方法名必須相同,返回值類型必須相同
(2):參數列表必須相同
(3):訪問權限不能比父類中被重寫的方法的訪問權限更低。例如:如果父類的一個方法被聲明爲public,那麼在子類中重寫該方法就不能聲明爲protected。
(4):子類和父類在同一個包中,那麼子類可以重寫父類所有方法,除了聲明爲private和final的方法。
(5):構造方法不能被重寫,
例:
class Test{
public void out(){
System.out.println("我是父類方法");
}
}
public class Test1 extends Test{
@Override
//方法簽名完全一致
public void out() {
System.out.println("我是重寫後的子類方法");
}
public static void main(String[] args) {
Test test = new Test();
test.out();
test = new Test1();
test.out();
}
6、內存泄漏與內存溢出
1、內存泄漏memory leak :是指程序在申請內存後,無法釋放已申請的內存空間,一次內存泄漏似乎不會有大的影響,但內存泄漏堆積後的後果就是內存溢出。
2、內存溢出 out of memory :指程序申請內存時,沒有足夠的內存供申請者使用,或者說,給了你一塊存儲int類型數據的存儲空間,但是你卻存儲long類型的數據,那麼結果就是內存不夠用,此時就會報錯OOM,即所謂的內存溢出
內存溢出的原因及解決方法:
內存泄漏:
也許是因爲活動已經被使用完畢,但是仍然在其他地方被引用,導致無法對其進行回收。我們只需要給對活動進行引用的類獨立出來或者將其變爲靜態類,該類隨着活動的結束而結束,也就沒有了當活動結束但仍然還被其他類引用的情況。
資源性對象在不使用的時候,應該調用它的close()函數將其關閉掉。。
集合容器中的內存泄露 ,我們通常把一些對象的引用加入到了集合容器(比如ArrayList)中,當我們不需要該對象時,並沒有把它的引用從集合中清理掉,這樣這個集合就會越來越大。如果這個集合是static的話,那情況就更嚴重了。
需要在退出程序之前,將集合裏的東西clear,然後置爲null,再退出程序。
WebView造成的泄露,當我們不使用WebView對象時,應該調用它的destory()函數來銷燬它,並釋放其佔用的內存,否則其長期佔用的內存也不能被回收,從而造成內存泄露。
我們應該爲WebView另外開啓一個進程,通過AIDL與主線程進行通信,WebView所在的進程可以根據業務的需要選擇合適的時機進行銷燬,從而達到內存的完整釋放。
內存溢出原因:
1.內存中加載的數據量過於龐大,如一次從數據庫取出過多數據;
2.集合類中有對對象的引用,使用完後未清空,使得JVM不能回收;
3.代碼中存在死循環或循環產生過多重複的對象實體;
4.使用的第三方軟件中的BUG;
5.啓動參數內存值設定的過小
內存溢出的解決方案:
第一步,修改JVM啓動參數,直接增加內存。(-Xms,-Xmx參數一定不要忘記加。)
第二步,檢查錯誤日誌,查看“OutOfMemory”錯誤前是否有其 它異常或錯誤。
第三步,對代碼進行走查和分析,找出可能發生內存溢出的位置。
重點排查以下幾點:
1.檢查對數據庫查詢中,是否有一次獲得全部數據的查詢。一般來說,如果一次取十萬條記錄到內存,就可能引起內存溢出。這個問題比較隱蔽,在上線前,數據庫中數據較少,不容易出問題,上線後,數據庫中數據多了,一次查詢就有可能引起內存溢出。因此對於數據庫查詢儘量採用分頁的方式查詢。
2.檢查代碼中是否有死循環或遞歸調用。
3.檢查是否有大循環重複產生新對象實體。
4.檢查對數據庫查詢中,是否有一次獲得全部數據的查詢。一般來說,如果一次取十萬條記錄到內存,就可能引起內存溢出。這個問題比較隱蔽,在上線前,數據庫中數據較少,不容易出問題,上線後,數據庫中數據多了,一次查詢就有可能引起內存溢出。因此對於數據庫查詢儘量採用分頁的方式查詢。
5.檢查List、MAP等集合對象是否有使用完後,未清除的問題。List、MAP等集合對象會始終存有對對象的引用,使得這些對象不能被GC回收。
第四步,使用內存查看工具動態查看內存使用情況
7、、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);⑥、繪製滾動條。
8、Android中跨進程通訊的幾種方式
Android 跨進程通信,像intent,contentProvider,廣播,service都可以跨進程通信。
intent:這種跨進程方式並不是訪問內存的形式,它需要傳遞一個uri,比如說打電話。
contentProvider:這種形式,是使用數據共享的形式進行數據共享。
service:遠程服務,aidl
9、AsycTask與一般線程異步之間的差別
1)是因爲AsyncTask使用了線程池技術,而且其中的方法很容易實現調用
2)是因爲AsyncTask可以調用相關的方法,在開啓子線程前和後,進行界面的更新
3)是因爲一旦任務多了,不用每次都new新的線程,可以直接使用
10、線程與進程
線程:線程是操作系統調度的最小單元,也叫輕量級進程。它被包含在進程之中,是進程中的實際運作單位。同一進程可以創建多個線程,每個進程都有自己獨立的一塊內存空間。並且能夠訪問共享的內存變量。”
進程:進程是併發執行程序在執行過程中資源分配和管理的基本單位(資源分配的最小單位)。進程可以理解爲一個應用程序的執行過程,應用程序一旦執行,就是一個進程。每個進程都有自己獨立的地址空間,每啓動一個進程,系統就會爲它分配地址空間,建立數據表來維護代碼段、堆棧段和數據段。
11、網絡請求框架庫
12、Android長連接怎麼處理心跳機制?
維護任何一個長連接都需要心跳機制,客戶端發送一個心跳給服務器,服務器給客戶端一個心跳應答,這樣就形成客戶端服務器的一次完整的握手。