先簡單說說我這四年期間的面試經歷吧。面試的公司不少,其中有讓我心血沸騰的經歷,也有讓我感到失望到無助的經歷,我將這些體會都記錄下來,細想以後很值得,面了這麼多公司,要是最後什麼也沒有留下來,那就太浪費了。至少對於我來講有些東西在整理總結以後才能獲得一個確定的答案。但願這些能對即將換工做或者打算看看機會的你有一些幫助。文末有面試和必備的技能點總結以及面試期間資料分享哦。html
如下問題的答案均是我的四年來屢次面試實踐中整理的,若有不一樣意見,歡迎斧正。java
答案:android
通常非靜態內部類持有外部類的引用的狀況下,形成外部類在使用完成後不能被系統回收內存,從而形成內存泄漏。爲了不這個問題,咱們能夠自定義的Handler聲明爲靜態內部類形式,而後經過弱引用的方式,讓Handler持有外部類的引用,從而可避免內存泄漏問題。c++
如下是代碼實現程序員
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private TextView mTextView;
private WeakReference<MainActivity> activityWeakReference;
private MyHandler myHandler;
static class MyHandler extends Handler {
private MainActivity activity;
MyHandler(WeakReference<MainActivity> ref) {
this.activity = ref.get();
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
//須要作判空操做
if (activity != null) {
activity.mTextView.setText("new Value");
}
break;
default:
Log.i(TAG, "handleMessage: default ");
break;
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//在onCreate中初始化
activityWeakReference = new WeakReference<MainActivity>(this);
myHandler = new MyHandler(activityWeakReference);
myHandler.sendEmptyMessage(1);
mTextView = (TextView) findViewById(R.id.tv_test);
}
}
複製代碼
參考博文blog.csdn.net/ucxiii/arti…web
解析:面試
在Android應用程序開發的時候,從一個Activity啓動另外一個Activity並傳遞一些數據到新的Activity上很是簡單,可是當您須要讓後臺運行的Activity回到前臺並傳遞一些數據可能就會存在一點點小問題。算法
首先,在默認狀況下,當您經過Intent啓到一個Activity的時候,就算已經存在一個相同的正在運行的Activity,系統都會建立一個新的Activity實例並顯示出來。爲了避免讓Activity實例化屢次,咱們須要經過在AndroidManifest.xml配置activity的加載方式(launchMode)以實現單任務模式,以下所示:sql
<activity
android:label="@string/app_name"
android:launchmode="singleTask"
android:name="Activity1">
</activity>
複製代碼
launchMode爲singleTask的時候,經過Intent啓到一個Activity,若是系統已經存在一個實例,系統就會將請求發送到這個實例上,但這個時候,系統就不會再調用一般狀況下咱們處理請求數據的onCreate方法,而是調用onNewIntent方法數據庫
答案:
前提:ActivityA已經啓動過,處於當前應用的Activity堆棧中; 當ActivityA的LaunchMode爲SingleTop時,若是ActivityA在棧頂,且如今要再啓動ActivityA,這時會調用onNewIntent()方法 當ActivityA的LaunchMode爲SingleInstance,SingleTask時,若是已經ActivityA已經在堆棧中,那麼此時會調用onNewIntent()方法
當ActivityA的LaunchMode爲Standard時,因爲每次啓動ActivityA都是啓動新的實例,和原來啓動的不要緊,因此不會調用原來ActivityA的onNewIntent方法,仍然調用的是onCreate方法
如下是代碼實例
1.設置MainActivity的啓動模式爲SingleTask(棧內複用)
<activity
android:name=".MainActivity"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
複製代碼
2.MainActivity中重寫onNewIntent方法
package code.xzy.com.handlerdemo;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton = (Button) findViewById(R.id.forward_btn);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(MainActivity.this, Main2Activity.class));
}
});
}
@Override
protected void onNewIntent(Intent intent) {
Toast.makeText(this, "onnewIntent", Toast.LENGTH_SHORT).show();
Log.i(TAG, "onNewIntent: i done....");
}
}
複製代碼
3.Main2Actvity執行點擊跳轉,MainActivity被複用,執行onNewIntent方法
package code.xzy.com.handlerdemo;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class Main2Activity extends AppCompatActivity {
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
mButton = (Button)findViewById(R.id.btn);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(Main2Activity.this,MainActivity.class));
finish();
}
});
}
}
複製代碼
打印截圖
**這裏分享一份全套體系化高級架構視頻;**七大主流技術模塊,視頻+源碼+筆記(文末有詳細面試資料專題整理包分享)
解析:
首先須要解釋下RecyclerView的這個名字了,從它類名上看,RecyclerView表明的意義是,我只管Recycler View,也就是說RecyclerView只管回收與複用View,其餘的你能夠本身去設置。能夠看出其高度的解耦,給予你充分的定製自由(因此你才能夠輕鬆的經過這個控件實現ListView,GirdView,瀑布流等效果)
其次RecyclerView提供了添加、刪除item的動畫 效果,並且能夠自定義
RecyclerView相比ListView優點在於能夠輕鬆實現:
不過一個挺鬱悶的地方就是,系統沒有提供ClickListener和LongClickListener。 不過咱們也能夠本身去添加,只是會多了些代碼而已。 實現的方式比較多,你能夠經過mRecyclerView.addOnItemTouchListener去監聽而後去判斷手勢,
固然你也能夠經過adapter中本身去提供回調
參考
jcodecraeer.com/a/anzhuokai… blog.csdn.net/lmj62356579… www.360doc.com/content/16/…
答案:
Proguard技術有以下功能:
壓縮 --檢查並移除代碼中無用的類 優化--對字節碼的優化,移除無用的字節碼 混淆--混淆定義的名稱,避免反編譯
預監測--在java平臺對處理後的代碼再次進行檢測
代碼混淆只在上線時纔會用到,debug模式下會關閉,是一種可選的技術。
那麼爲何要使用代碼混淆呢?
由於Java是一種跨平臺的解釋性開發語言,而java的源代碼會被編譯成字節碼文件,存儲在.class文件中,因爲跨平臺的須要,java的字節碼中包含了不少源代碼信息,諸如變量名、方法名等等。而且經過這些名稱來訪問變量和方法,這些變量不少是無心義的,可是又很容易反編譯成java源代碼,爲了防止這種現象,咱們就須要經過proguard來對java的字節碼進行混淆,混淆就是對發佈的程序進行從新組織和處理,使得處理後的代碼與處理前的代碼有相同的功能,和不一樣的代碼展現,即便被反編譯也很難讀懂代碼的含義,哪些混淆過的代碼仍能按照以前的邏輯執行獲得同樣的結果。
可是,某些java類是不能被混淆的,好比實現了序列化的java類是不能被混淆的,不然反序列化時會出問題。
下面這類代碼混淆的時候要注意保留,不能混淆。
其餘Anroid 官方建議 不混淆的,如
在Android中,應用的響應性被活動管理器(Activity Manager)和窗口管理器(Window Manager)這兩個系統服務所監視。當用戶觸發了輸入事件(如鍵盤輸入,點擊按鈕等),若是應用5秒內沒有響應用戶的輸入事件,那麼,Android會認爲該應用無響應,便彈出ANR對話框。而彈出ANR異常,也主要是爲了提高用戶體驗。
解決方案是對於耗時的操做,好比訪問網絡、訪問數據庫等操做,須要開闢子線程,在子線程處理耗時的操做,主線程主要實現UI的操做
主線程使用Handler的過程
首先在主線程建立一個Handler對象 ,並重寫handleMessage()方法。而後當在子線程中須要進行更新UI的操做,咱們就建立一個Message對象,並經過handler發送這條消息出去。以後這條消息被加入到MessageQueue隊列中等待被處理,經過Looper對象會一直嘗試從Message Queue中取出待處理的消息,最後分發會Handler的handler Message()方法中。
答案:
我的的理解是,Android視圖渲染必須通過measure、layout、draw三個步驟,measure過程是在一個樹形結構中不斷遍歷的,若是UI層級嵌套很深,必將花費大量的時間,因此應該儘可能減小層級嵌套,保證樹的結構扁平,並移除不須要渲染的views
自定義view步驟:
Android自定義View的通常步驟
Volley教程 blog.csdn.net/jdfkldjlkjd…
TCP與UDP基本區別
UDP應用場景:
單例模式:單例模式是一種對象建立模式,它用於產生一個對象的具體實例,它能夠確保系統中一個類只產生一個實例。
適配器模式:將一個接口轉換成客戶但願的另外一個接口,適配器模式使接口不兼容的那些類能夠一塊兒工做,其別名爲包裝器(Wrapper)
裝飾模式:動態地給一個對象增長一些額外的職責,就增長對象功能來講,裝飾模式比生成子類實現更爲靈活。裝飾模式是一種對象結構型模式。
使用場景:
優勢:
對於擴展一個對象的功能,裝飾模式比繼承更加靈活,不會致使類的個數急劇增長。
能夠經過一種動態地方式來擴展一個對象的功能。
能夠對一個對象進行屢次裝飾,經過使用不一樣的具體裝飾類以及這些裝飾類的排列組合。
實際運用:
Android中Context類的實現
外觀模式:主要目的在於讓外部減小與子系統內部多個模塊的交互,從而讓外部可以更簡單得使用子系統。它負責把客戶端的請求轉發給子系統內部的各個模塊進行處理。
使用場景:
**組合模式:**將對象以樹形結構組織起來,以達成」部分--總體」的層次結構,使得客戶端對單個對象和組合對象的使用具備一致性。
使用場景:
優勢:
1.高層模塊調用簡單 2.節點自由增長
**模板方法:**是經過一個算法骨架,而將算法中的步驟延遲到子類,這樣子類就能夠複寫這些步驟的實現來實現特定的算法。
它的使用場景:
觀察者模式:定義對象之間一種一對多依賴關係,使得每當一個對象狀態發生改變時,其相關依賴對象皆獲得通知並被自動更新。
其使用場景:
具體應用:
好比回調模式中,實現了抽象類/接口的實例實現了父類提供的抽象方法後,將該方法交還給父類來處理
Listview中的notifyDataSetChanged
RxJava中的觀察者模式
**責任鏈模式:**是一個請求有多個對象來處理,這些對象是一條鏈,但具體由哪一個對象來處理,根據條件判斷來肯定,若是不能處理會傳遞給該鏈條中的下一個對象,直到有對象處理它爲止。
使用場景: 1.有多個對象能夠處理同一個請求,具體哪一個對象處理該請求待運行時再肯定 2.在不明確指定接收者的狀況下,向多個對象中的一個提交一個請求。
實際運用: Try...catch語句 OrderedBroadcast MotionEvent:actionDwon actionMove actionUp 事件分發機制三個重要方法:dispatchTouchEvent. onInterceptTouchEvent. onTouchEvent
**策略模式:**定義一系列的算法,把它們一個個封裝起來,而且使他們可互相替換。本模式使得算法可獨立於使用它的客戶而變化。策略模式的使用場景:一個類定義了多種行爲,而且這些行爲在這個類的方法中以多個條件語句的形式出現,那麼可使用策略模式避免在類中使用大量的條件語句。
使用場景: 一個類定義了多種行爲,而且這些行爲在這個類的方法中以多個條件語句的形式出現,那麼可使用策略模式避免在類中使用大量的條件語句。
優勢: 1.上下文Context和具體策略ConcreateStrategy是鬆耦合關係 2.策略模式知足 開-閉原則
具體應用:
字節流操做的基本單元爲字節;字符流操做的基本單元爲Unicode碼元(2個字節)。 字節流默認不使用緩衝區;字符流使用緩衝區。
字節流一般用於處理二進制數據,實際上它能夠處理任意類型的數據,但它不支持直接寫入或讀取Unicode碼元;字符流一般處理文本數據,它支持寫入及讀取Unicode碼元。
參考 理解Java中字符流與字節流的區別
View和ViewGroup的基本繪製流程
只有在一種狀況下,這樣作是可行的:在try語句中聲明瞭很大的對象,致使OOM,而且能夠確認OOM是由try語句中的對象聲明致使的,那麼在catch語句中,能夠釋放掉這些對象,解決OOM的問題,繼續執行剩餘語句。
可是這一般不是合適的作法。Java中管理內存除了顯式地catch OOM以外還有更多有效的方法:好比SoftReference, WeakReference, 硬盤緩存等。在JVM用光內存以前,會屢次觸發GC,這些GC會下降程序運行的效率。若是OOM的緣由不是try語句中的對象(好比內存泄漏),那麼在catch語句中會繼續拋出OOM
Java的StrongReference, SoftReference, WeakReference, PhantomReference的區別
答:
每當你須要使用數據庫時,你須要使用DatabaseManager的openDatabase()方法來取得數據庫,這個方法裏面使用了單例模式,保證了數據庫對象的惟一性,也就是每次操做數據庫時所使用的sqlite對象都是一致獲得。其次,咱們會使用一個引用計數來判斷是否要建立數據庫對象。若是引用計數爲1,則須要建立一個數據庫,若是不爲1,說明咱們已經建立過了。 在closeDatabase()方法中咱們一樣經過判斷引用計數的值,若是引用計數降爲0,則說明咱們須要close數據庫。
大體的作法就是在多線程訪問的狀況下須要本身來封裝一個DatabaseManager來管理Sqlite數據庫的讀寫,須要同步的同步,須要異步的異步,不要直接操做數據庫,這樣很容易出現由於鎖的問題致使加鎖後的操做失敗。
該答案參考了這篇文章blog.csdn.net/rockcode_li…
解析:leetcode 兩個鏈表的交集點 www.360doc.com/content/16/…
有如下幾種思路:
(1) 暴力破解 ,遍歷鏈表A的全部節點,而且對於每一個節點,都與鏈表B中的全部節點比較,退出條件是在B中找到第一個相等的節點。時間複雜度O(lengthA*lengthB),空間複雜度O(1)。
(2) 哈希表 。遍歷鏈表A,而且將節點存儲到哈希表中。接着遍歷鏈表B,對於B中的每一個節點,查找哈希表,若是在哈希表中找到了,說明是交集開始的那個節點。時間複雜度O(lengthA+lengthB),空間複雜度O(lengthA)或O(lengthB)。
(3) 雙指針法 ,指針pa、pb分別指向鏈表A和B的首節點。
遍歷鏈表A,記錄其長度lengthA,遍歷鏈表B,記錄其長度lengthB。
由於兩個鏈表的長度可能不相同,好比題目所給的case,lengthA=5,lengthB=6,則做差獲得 lengthB- lengthA=1,將指針pb從鏈表B的首節點開始走1步,即指向了第二個節點,pa指向鏈表A首節點,而後它們同時走,每次都走一步,當它們相等時,就是交集的節點。
現在安卓開發不像前幾年那麼熱門,可是高級人才依然緊缺,你們看着這句話是否是很熟悉,由於 web 高級人才也緊缺,c++ 高級人才同樣緊缺,那麼到了人工智能時代,人工智能時代的高級人才也一樣會緊缺!彷佛是高級人才的人在其餘領域也是高級人才,而不是由於選擇了熱門纔會一路順風。
網上高級工程師面試相關文章魚龍混雜,要麼一堆內容,要麼內容質量太淺, 鑑於此我整理了以下安卓開發高級工程師面試題以及答案幫助你們順利進階爲高級工程師,目前我就任於某大廠安卓高級工程師職位,在當下大環境下也想爲安卓工程師出一份力,這些問題都是我認真看過而且以爲不錯才整理出來,你們知道高級工程師不會像剛入門那樣被問的問題一句話兩句話就能表述清楚,因此我經過過濾好文章來幫助你們理解,但願對你們有所幫助。
針對於上面的面試題,我總結出了互聯網公司Android程序員面試涉及到的絕大部分面試題及答案,並整理作成了文檔,以及系統的進階學習視頻資料,免費分享給你們。
好了,今天的分享就到這裏,若是你對在面試中遇到的問題不知道怎麼解決或者想要只帶一些面試中的小技巧,能夠關注我獲取傳資料送門。來看看同行們在面試中有哪些小技巧幫助面試經過,以及更多面試資料分享。
部分資料截圖