Android面試大全(四大組件篇)
Android面試大全(性能優(yōu)化篇)
Android面試大全(異常處理篇)
Android面試大全(開源框架篇)
Android面試大全(網(wǎng)絡(luò)篇)
Android面試大全(java篇)
開發(fā)中常見Exception
- 空指針問題
這種問題通過查看Log日志帶有NullpointerException
江锨,定位到出錯(cuò)位置解決就好了,比如:控件或集合未初始化或者服務(wù)端數(shù)據(jù)格式問題取值前未做判斷 - IndexOutOfBoundsException 異常
數(shù)組越界,解決辦法:取值前先判斷index與數(shù)組或集合的大小直晨,避免循環(huán)刪除集合數(shù)據(jù)(remove)等; - ResourceNotFoundException
原因一:要查找的資源本地資源找不到(本地確實(shí)不存在|編譯出錯(cuò)|未入導(dǎo)包)
原因二:setText(4);當(dāng)給TextView設(shè)置文字時(shí)直接設(shè)置整形數(shù)(textview設(shè)置整形數(shù)時(shí)會(huì)根據(jù)int索引去查找本地資源文件) - 權(quán)限問題
這類問題通常log日志中會(huì)帶有Permission
關(guān)鍵字杀饵,同時(shí)系統(tǒng)會(huì)提示缺少具體哪種權(quán)限洋腮,解決就是在AndroidManifest.xml
清單文件中聲明一下 - 說明
Android四大組件都需要進(jìn)行注冊(cè)才能正常使用锈麸,其中Activity、Service苍碟、Content Provider內(nèi)容提供者都需要在AndroidManifest
清單文件中注冊(cè)申明酒觅,BroadCastReceiver廣播有兩種動(dòng)態(tài)注冊(cè)方式:靜態(tài)注冊(cè)(即在AndroidManifest.xml文件中注冊(cè))或動(dòng)態(tài)注冊(cè)(通過java代碼注冊(cè))
private final String action ="com.activity.send";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//注冊(cè)廣播,
// 面試過程中有面試到動(dòng)態(tài)注冊(cè)廣播時(shí)微峰,需要幾個(gè)參數(shù)舷丹,分別是什么
IntentFilter filter = new IntentFilter();
filter.addAction(action);
/**
* 兩個(gè)參數(shù) BroadCastreceiver實(shí)例,IntentFilter,通常使用的也是這種
*/
registerReceiver(receiver,filter);
/**
* 四個(gè)參數(shù):廣播接收器實(shí)例,IntentFilter,廣播權(quán)限县忌,Handler
*/
// registerReceiver(receiver,filter,"android.permission",Handler);
Button button = new Button(this);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//發(fā)送廣播
sendBroadcast(new Intent(action));
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
//銷毀前需要取消廣播注冊(cè)
unregisterReceiver(receiver);
}
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(action)){
//TODO 接收到廣播掂榔,做出相應(yīng)處理
//在此方法中不能創(chuàng)建線程,也不能做太過耗時(shí)的操作
//廣播接收器超過10s的操作會(huì)ANR(Application Not Response)
}
}
};
找不到activity類
log日志類型ActivityNotFoundException
症杏,這種原因是自己創(chuàng)建一個(gè)類繼承自activity装获,未在AndroidManifest.xml
清單文件中注冊(cè),聲明如下
<activity android:name=".CustomActivity" ></activity>
數(shù)組越界
在操作集合時(shí),索引(position超出范圍)出錯(cuò)
網(wǎng)絡(luò)請(qǐng)求 出錯(cuò)
- java.lang.IllegalArgumentException: rawResponse must be successful response
- 可檢查下網(wǎng)絡(luò)請(qǐng)求方式是否正確厉颤,如:post請(qǐng)求使用了get方式
- url地址出錯(cuò)
- 參數(shù)出錯(cuò)
ANR
Application Not Response,在手機(jī)上我們不時(shí)會(huì)看到程序無響應(yīng)
等字樣穴豫,這就是在一定時(shí)間內(nèi)為做完某項(xiàng)操作導(dǎo)致程序發(fā)生ANR異常
- 程序主線程(UI線程)是不能做耗時(shí)操作的
- Activity最長(zhǎng)響應(yīng)時(shí)間為5s
- BroadCastReceiver最長(zhǎng)響應(yīng)時(shí)間為10s
- Service最長(zhǎng)響應(yīng)時(shí)間為20s
超時(shí)即會(huì)發(fā)生ANR異常,太過耗時(shí)的操作可以創(chuàng)建子線程去完成逼友,我們也知道Service是運(yùn)行在后臺(tái)的服務(wù)精肃,用戶看不見,也能做一些耗時(shí)操作帜乞,長(zhǎng)時(shí)間的耗時(shí)操作可考慮使用IntentService(extends Service
),是Service的子類;
Service
與BroadcastReceiver
都運(yùn)行在主線程中
OOM
OutOfMemory
,Android的虛擬機(jī)是基于寄存器的Dalvik司抱,最大堆大小一般是16M,有的機(jī)器為24M黎烈。OutOfMemory的錯(cuò)誤习柠,通常 是堆內(nèi)存溢出。對(duì)一般手機(jī)應(yīng)用照棋,手機(jī)資源是相當(dāng)有限的资溃,堆內(nèi)存的上限值只有16M(有的24M)Android的缺 省值是16M(某些機(jī)型是24M),而對(duì)于普通應(yīng)用這是不能改的烈炭,當(dāng)應(yīng)用程序處理大資源的資源溶锭,如圖片或視頻等媒體資源時(shí),數(shù)量一多符隙,時(shí)間一長(zhǎng)趴捅,16M的資源很容易耗盡垫毙,所以O(shè)OM很容易出現(xiàn)。
雖然Java
有垃圾回收機(jī)制驻售,但也存在內(nèi)存泄露露久。如果我們一個(gè)程序中,已經(jīng)不再使用某個(gè)對(duì)象欺栗,但是因?yàn)槿匀挥幸弥赶蛩厥掌骶蜔o法回收它征峦,當(dāng)然該對(duì)象占用的內(nèi)存就無法被使用迟几,這就造成了內(nèi)存泄露。如果我們的java運(yùn)行很久,而這種內(nèi)存泄露不斷的發(fā)生栏笆,最后就沒內(nèi)存可用了类腮。當(dāng)然java的,內(nèi)存泄漏和C/C++是不一樣的蛉加。如果java程序完全結(jié)束后蚜枢,它所有的對(duì)象就都不可達(dá)了,系統(tǒng)就可以對(duì)他們進(jìn)行垃圾回收针饥,它的內(nèi)存泄露僅僅限于它本身厂抽,而不會(huì)影響整個(gè)系統(tǒng)的。
C/C++的內(nèi)存泄露就比較糟糕了丁眼,它的內(nèi)存泄露是系統(tǒng)級(jí)筷凤,即使C/C++程序退出,它的泄露的內(nèi)存也無法被系統(tǒng)回收苞七,永遠(yuǎn)不可用 了藐守,除非重啟機(jī)器。
Android的一個(gè)應(yīng)用程序的內(nèi)存泄露對(duì)別的應(yīng)用程序影響不大蹂风。為了能夠使得Android應(yīng)用程序安全且快速的運(yùn)行卢厂,Android的每個(gè)應(yīng)用程序都會(huì)使用一個(gè)專有的Dalvik虛擬機(jī)實(shí)例來運(yùn)行,它是由Zygote服務(wù)進(jìn)程孵化出的惠啄,也就是說每個(gè)應(yīng)用程序都是在屬于自己的進(jìn)程中運(yùn)行的慎恒。 Android為不同類型的進(jìn)程分配了不同的內(nèi)存使用上限,如果程序在運(yùn)行過程中出現(xiàn)了內(nèi)存泄漏的而造成應(yīng)用進(jìn)程使用的內(nèi)存超過了這個(gè)上限礁阁,則會(huì)被系統(tǒng)視為內(nèi)存泄漏巧号,從而被kill掉,這使得僅僅自己的進(jìn)程被kill掉姥闭,而不會(huì)影響其他進(jìn)程(如果是system_process等系統(tǒng)進(jìn)程出問題的話丹鸿,則會(huì)引起系統(tǒng)重啟),這是棚品,我們的應(yīng)用程序就會(huì)崩潰靠欢,我們就會(huì)看到OOM廊敌。
引發(fā)OOM的原因
- 資源文件未及時(shí)關(guān)閉:File(未關(guān)閉
InputStream
/OutputStream
)、數(shù)據(jù)庫Cursor
未關(guān)閉 - 構(gòu)造adapter未緩存convertView
- 未反注冊(cè)引起(比如廣播)
- Bitmap未使用時(shí)未及時(shí)recycle()釋放
- Context引起的泄漏
- static關(guān)鍵字的不當(dāng)使用
解決辦法
-
static
關(guān)鍵字的使用
static是Java中的一個(gè)關(guān)鍵字门怪,當(dāng)用它來修飾成員變量時(shí)骡澈,那么該變量就屬于該類,而不是該類的實(shí)例掷空。用static這個(gè)關(guān)鍵字修飾變量肋殴,使得該變量的生命周期大大延長(zhǎng),并且訪問也極其方便坦弟,用類名就能直接訪問护锤,各個(gè)資源間 傳值也極其方便,所以它經(jīng)常被我們使用酿傍。但如果用它來引用一些資源耗費(fèi)過多的實(shí)例(Context的情況最多)烙懦,這時(shí)就要謹(jǐn)慎對(duì)待了。- ①:應(yīng)該盡量避免static成員變量引用資源耗費(fèi)過多的實(shí)例赤炒,比如Context氯析。
- ②:Context盡量使用Application Context,因?yàn)锳pplication的Context的生命周期比較長(zhǎng)莺褒,引用它不會(huì)出現(xiàn)內(nèi)存泄露的問題掩缓。
- ③:使用WeakReference代替強(qiáng)引用。比如可以使用WeakReference<Context> mContextRef;
-
Bitmap引起的內(nèi)存泄漏
- 及時(shí)銷毀(調(diào)用recycle并不確定該bitmap會(huì)立即被回收癣朗,但給虛擬機(jī)說了“改圖片是可以銷毀的了”拾因,如有需要可手動(dòng)通過代碼置空NULL)
- 設(shè)置采樣率
我在性能優(yōu)化篇有說到過采樣率,將圖片進(jìn)行縮放
private ImageView preview;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;//寬高都為原來的1/2旷余,即圖片為原來的1/4
Bitmap bitmap = BitmapFactory.decodeStream(cr.openInputStream(uri), null, options);
preview.setImageBitmap(bitmap);
- 使用軟引用保存圖片的引用(SoftRefrence)
-
cursor未關(guān)閉
Cursor是Android查詢數(shù)據(jù)后得到的一個(gè)管理數(shù)據(jù)集合的類绢记,正常情況下,如果查詢得到的數(shù)據(jù)量較小時(shí)不會(huì)有內(nèi)存問題正卧,而且虛擬機(jī)能夠保證Cusor最終會(huì)被釋放掉蠢熄。
然而如果Cursor的數(shù)據(jù)量特別大時(shí),應(yīng)該保證Cursor占用的內(nèi)存被及時(shí)的釋放掉炉旷,而不是等待GC來處理签孔。并且 Android明顯是傾向于編程者手動(dòng)的將Cursor close掉,因?yàn)樵谠创a中我們發(fā)現(xiàn)窘行,如果等到垃圾回收器來回收時(shí)饥追,會(huì)給用戶以錯(cuò)誤提示。
所以我們使用Cursor的方式一般如下:
Cursor cursor = null;
try {
cursor = ctx.getContentResolver().query(uri,null, null,null,null);
if(cursor != null) {
cursor.moveToFirst();
//do something
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
有一種情況下罐盔,我們不能直接將Cursor關(guān)閉掉但绕,這就是在CursorAdapter中應(yīng)用的情況,但是注意,CursorAdapter在Acivity結(jié)束時(shí)并沒有自動(dòng)的將Cursor關(guān)閉掉捏顺,因此六孵,你需要在onDestroy函數(shù)中,手動(dòng)關(guān)閉cursor幅骄。
-
inputstream/outputstream
這個(gè)我們?cè)诓僮魍戤厱r(shí)關(guān)閉就好了 - 未反注冊(cè)
以廣播為例registerReceiver(receiver,filter);
和unregisterReceiver(receiver);
是成對(duì)出現(xiàn)的劫窒;未調(diào)用反注冊(cè)時(shí)程序不會(huì)crash掉,在log日志中也會(huì)出現(xiàn)錯(cuò)誤信息的 - 未緩存converview(少量數(shù)據(jù)時(shí)影響不大)
狀態(tài)異常
- 發(fā)生情形:
①:fragment中使用recycleview
adapter中加載layout布局時(shí)錯(cuò)誤使用方法(親測(cè))
LayoutInflater.from(mContext).inflate(R.layout.item_summary, parent);
- 使用以下方法得以解決
LayoutInflater.from(mContext).inflate(R.layout.item_summary, parent, false);
正在持續(xù)更新中……