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