最近遇到1些比較有代表性,有點(diǎn)挑戰(zhàn)性的面試題,
大概集中這幾個(gè)方面:
關(guān)于這些問題,覺得下面幾篇不管是文章的邏輯,文章的深度都是寫得比較好的,希望對(duì)1些應(yīng)聘者有所幫助.
思路:
在 Java 中聲明1個(gè) native 方法,然后生本錢地接口的函數(shù)原型聲明,再用 C/C++ 實(shí)現(xiàn)這些函數(shù),并生成對(duì)應(yīng)平臺(tái)的動(dòng)態(tài)同享庫(kù)放到 Java 程序的類路徑下,最后在 Java 程序中調(diào)用聲明的 native 方法就間接的調(diào)用到了 C/C++ 編寫的函數(shù)了,在 C/C++ 中寫的程序可以避開 JVM 的內(nèi)存開消過(guò)大的限制、處理高性能的計(jì)算、調(diào)用系統(tǒng)服務(wù)等功能.
遇到的問題:
其實(shí)在JNI中,與java最常接觸的不過(guò)就是查找 class 和 ID (屬性和方法 ID),但是這個(gè)查找的進(jìn)程是10分消耗時(shí)間的.
解決方法:
因此在 native 里保存 class 和 member id 是很有必要的,但是class 和 member id 在1定范圍內(nèi)是穩(wěn)定的,但在動(dòng)態(tài)加載的 class loader 下,保存全局的 class 要末可能失效,要末可能造成沒法卸載classloader,在諸如 OSGI(j2e的東西,自己百度) 框架下的 JNI 利用還要特別注意這方面的問題.
總結(jié):
所以在 JNI 開發(fā)中,公道的使用緩存技術(shù)能給程序提高極大的性能。緩存有兩種,分別為使用時(shí)緩存和類靜態(tài)初始化時(shí)緩存,區(qū)分主要在于緩存產(chǎn)生的時(shí)刻。
使用時(shí)緩存:
字段 ID、方法 ID 和 Class 援用在函數(shù)當(dāng)中使用的同時(shí)就緩存起來(lái).
判斷字段 ID 是不是已緩存,如果沒有先取出來(lái)存到fid_str中,下次再調(diào)用的時(shí)候該變量已有值了,不用再去JVM中獲得,起到了緩存的作用。
遇到的坑:
但是請(qǐng)注意:cls_string是1個(gè)局部援用,與方法和字段 ID 不1樣,局部援用在函數(shù)結(jié)束后會(huì)被 JVM 自動(dòng)釋放掉,這時(shí)候cls_string成了1個(gè)野針對(duì)(指向的內(nèi)存空間已被釋放,但變量的值依然是被釋放后的內(nèi)存地址,不為 NULL),當(dāng)下次再調(diào)用 Java_com_xxxx_newString 這個(gè)函數(shù)的時(shí)候,會(huì)試圖訪問1個(gè)無(wú)效的局部援用,從而致使非法的內(nèi)存訪問造成程序崩潰。所以在函數(shù)內(nèi)用 static 緩存局部援用這類方式是毛病的。
類靜態(tài)初始化時(shí)緩存:
在調(diào)用1個(gè)類的方法或?qū)傩灾埃琂ava 虛擬機(jī)會(huì)先檢查該類是不是已加載到內(nèi)存當(dāng)中,如果沒有則會(huì)先加載,然后緊接著會(huì)調(diào)用該類的靜態(tài)初始化代碼塊,所以在靜態(tài)初始化該類的進(jìn)程當(dāng)中計(jì)算并緩存該類當(dāng)中的字段 ID 和方法 ID 也是個(gè)不錯(cuò)的選擇。
如果在寫 JNI 接口時(shí),不能控制方法和字段所在類的源碼的話,用使用時(shí)緩存比較公道。但比起類靜態(tài)初始化時(shí)緩存來(lái)講,用使用時(shí)緩存有1些缺點(diǎn):
使用前,每次都需要檢查是不是已緩存該 ID 或 Class 援用
如果在用使用時(shí)緩存的 ID,要注意只要本地代碼依賴于這個(gè) ID 的值,那末這個(gè)類就不會(huì)被 unload。另外1方面,如果緩存產(chǎn)生在靜態(tài)初始化時(shí),當(dāng)類被 unload 或 reload 時(shí),ID 會(huì)被重新計(jì)算。由于,盡可能在類靜態(tài)初始化時(shí)就緩存字段 ID、方法 ID 和類的 Class 援用。
點(diǎn)擊詳情
自定義控件的流程大致分為以下幾步
OnDraw
對(duì)自定義View,我們通常會(huì)重寫這3個(gè)方法,重寫那些,取決于我們的自定義View從哪里繼承,然后要實(shí)現(xiàn)甚么樣的功能。大致歸納有以下幾點(diǎn)。
繼承View
實(shí)現(xiàn)1些不規(guī)則的圖形,需要重寫onDraw方法進(jìn)行繪制
通過(guò)反編譯的結(jié)果, 普通的非static內(nèi)部類比static內(nèi)部類多了1個(gè)field: final com.qihoo.browser.OuterClass this$0
;在默許的構(gòu)造方法中,用外部類的對(duì)象對(duì)這個(gè)filed賦值.
用intellijidea打開OuterClass$NormallInnerClass.class
, 可以看到內(nèi)部類調(diào)用外部類的方法就是通過(guò)這個(gè)filed實(shí)現(xiàn)的. 這也就是static 內(nèi)部類沒法調(diào)用外部類普通方法的緣由,由于static內(nèi)部類中沒有這個(gè)field: final com.qihoo.browser.OuterClass this$0
;
解決方法
publicclass MainActivity extends Activity {
privateMyThread mThread;
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
exampleThree();
}
privatevoid exampleThree() {
mThread = new MyThread();
mThread.start();
}
//static內(nèi)部類可以免,持有外部類的援用.
private static class MyThread extends Thread {
private boolean mRunning = false;
@Override
public void run() {
//對(duì)1些死循環(huán)的耗時(shí)操作,需要設(shè)置退出線程的標(biāo)識(shí) flag
mRunning = true;
while(mRunning) {
SystemClock.sleep(1000);
}
}
//定義1個(gè)flag 來(lái)停止線程的運(yùn)行.
public void close() {
mRunning = false;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//activity被燒毀的時(shí)候關(guān)閉線程
mThread.close();
}
}
點(diǎn)擊詳情1
點(diǎn)擊詳情2
非靜態(tài)方法 按重寫規(guī)則調(diào)用相應(yīng)的類實(shí)現(xiàn)方法,而靜態(tài)方法只與類相干。
所謂靜態(tài),就是在運(yùn)行時(shí),虛擬機(jī)已認(rèn)定此方法屬于哪一個(gè)類。
專業(yè)術(shù)語(yǔ)有嚴(yán)格的含義,用語(yǔ)要準(zhǔn)確.”重寫”只能適用于實(shí)例方法.不能用于靜態(tài)方法.對(duì)靜態(tài)方法,只能隱藏(可以重寫那只是情勢(shì)上的 ,其實(shí)不滿足多態(tài)的特點(diǎn),所以嚴(yán)格說(shuō)不是重寫)。
靜態(tài)方法的調(diào)用不需要實(shí)例化吧.. 不實(shí)例化也就不能用多態(tài)了,也就沒有所謂的父類援用指向子類實(shí)例.由于不能實(shí)例化 也就沒有機(jī)會(huì)去指向子類的實(shí)例。所以也就不存在多態(tài)了。
靜態(tài)方法不依賴類就能夠訪問。這就是它的用處啊,沒有new對(duì)象可調(diào)用的方法。但是,重寫是依賴對(duì)象的。重寫父類的某1方法,而static不依賴類。
善用自定義 View,自定義 View 可以有效的減小 Layout 的層級(jí)。
包括利用好 ConvertView、利用好 ViewType、Layout 層次結(jié)構(gòu)、ViewHolder、使用自定義布局、保證 Adapter 的 hasStableIds() 返回 true、Item 不能太高、getView() 中要做盡可能少的事情、ListView 中元素避免半透明、盡可能開啟硬件加速、 AnimationCache、 ScrollingCache 和 SmoothScrollbar。
個(gè)人收獲:
比viewHolder更有效的方式是使用自定義布局,
自定義布局有個(gè)好處就是可以省略 ViewHolder。說(shuō)出來(lái)可能你不會(huì)信, ViewHolder 首先會(huì)占用 setTag() ,其次每次取出后都需要轉(zhuǎn)換1下類的類型。如果是自定義布局的話,findViewById() 這個(gè)進(jìn)程可以在構(gòu)造函數(shù)中進(jìn)行.
點(diǎn)擊詳情
Android游戲開發(fā)中主要的類除控制類就是顯示類,比較重要也很復(fù)雜的就是顯示和游戲邏輯的處理。在J2ME中可以通過(guò)Display和Canvas來(lái)實(shí)現(xiàn)顯示,而Android中處理顯示的是View類。下面為大家簡(jiǎn)單介紹android.view.View
和android.view.SurfaceView
。
SurfaceView是從View基類中派生出來(lái)的顯示類,直接子類有GLSurfaceView和VideoView,可以看出GL和視頻播放和Camera攝像頭1般均使用SurfaceView,到底有哪些優(yōu)勢(shì)呢? SurfaceView可以控制表面的格式,比如大小,顯示在屏幕中的位置,最關(guān)鍵是的提供了SurfaceHolder類,使用getHolder方法獲得,相干的有Canvas lockCanvas()、 Canvas lockCanvas(Rect dirty) 、void removeCallback(SurfaceHolder.Callback callback)、void unlockCanvasAndPost(Canvas canvas)
控制圖形和繪制,而在SurfaceHolder.Callback
接口回調(diào)中可以通過(guò)下面3個(gè)抽象類可以自己定義具體的實(shí)現(xiàn)(比如第1個(gè)更改格式和顯示畫面):
java
abstract void surfaceChanged(SurfaceHolder holder, int format, int width, int height) ;
abstract void surfaceCreated(SurfaceHolder holder) ;
abstract void surfaceDestroyed(SurfaceHolder holder) ;
對(duì)Surface相干的,Android底層還提供了GPU加速功能,所以1般實(shí)時(shí)性很強(qiáng)的利用中主要使用SurfaceView而不是直接從View構(gòu)建,同時(shí)后面會(huì)講到的OpenGL中的GLSurfaceView也是從該類實(shí)現(xiàn)。
點(diǎn)擊詳情
OkHttp + volley
OkHttp還處理了代理服務(wù)器問題和SSL握手失敗問題。
*目前,該封裝庫(kù)志支持:
1般的get要求
1般的post要求
基于Http的文件上傳
文件下載
上傳下載的進(jìn)度回調(diào)
加載圖片
支持要求回調(diào),直接返回對(duì)象、對(duì)象集合
支持session的保持
支持自簽名網(wǎng)站https的訪問,提供方法設(shè)置下證書就行
支持取消某個(gè)要求
點(diǎn)擊詳情
1個(gè)Handler的創(chuàng)建它就會(huì)被綁定到這個(gè)線程的消息隊(duì)列中,如果是在主線程創(chuàng)建的,那就不需要寫代碼來(lái)創(chuàng)建消息隊(duì)列了,默許的消息隊(duì)列會(huì)在主線程被創(chuàng)建。但是如果是在子線程的話,就必須在創(chuàng)建Handler之前先初始化線程的消息隊(duì)列。
點(diǎn)擊詳情
transaction.replace()
使用另外一個(gè)Fragment替換當(dāng)前的,實(shí)際上就是remove()然后add()的合體
點(diǎn)擊詳情