Android面试大全(四大组件篇)
Android面试大全(性能优化篇)
Android面试大全(异常处理篇)
Android面试大全(开源框架篇)
Android面试大全(网络篇)
Android面试大全(java篇)
开发中常见Exception
- 空指针问题
这种问题通过查看Log日志带有NullpointerException
,定位到出错位置解决就好了,比如:控件或集合未初始化 - 权限问题
这类问题通常log日志中会带有Permission
关键字,同时系统会提示缺少具体哪种权限,解决就是在AndroidManifest.xml
清单文件中声明一下 - 说明
Android四大组件都需要进行注册才能正常使用,其中Activity、Service、Content Provider内容提供者都需要在AndroidManifest
清单文件中注册申明,BroadCastReceiver广播有两种动态注册方式:静态注册(即在AndroidManifest.xml文件中注册)或动态注册(通过java代码注册)
private final String action ="com.activity.send";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//注册广播,
// 面试过程中有面试到动态注册广播时,需要几个参数,分别是什么
IntentFilter filter = new IntentFilter();
filter.addAction(action);
/**
* 两个参数 BroadCastreceiver实例,IntentFilter,通常使用的也是这种
*/
registerReceiver(receiver,filter);
/**
* 四个参数:广播接收器实例,IntentFilter,广播权限,Handler
*/
// registerReceiver(receiver,filter,"android.permission",Handler);
Button button = new Button(this);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//发送广播
sendBroadcast(new Intent(action));
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
//销毁前需要取消广播注册
unregisterReceiver(receiver);
}
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(action)){
//TODO 接收到广播,做出相应处理
//在此方法中不能创建线程,也不能做太过耗时的操作
//广播接收器超过10s的操作会ANR(Application Not Response)
}
}
};
-
找不到activity类
log日志类型ActivityNotFoundException
,这种原因是自己创建一个类继承自activity,未在AndroidManifest.xml
清单文件中注册,声明如下
<activity android:name=".CustomActivity" ></activity>
-
数组越界
在操作集合时,索引(position超出范围)出错
网络请求 出错
- java.lang.IllegalArgumentException: rawResponse must be successful response
- 可检查下网络请求方式是否正确,如:post请求使用了get方式
- url地址出错
- 参数出错
ANR
Application Not Response,在手机上我们不时会看到程序无响应
等字样,这就是在一定时间内为做完某项操作导致程序发生ANR异常
- 程序主线程(UI线程)是不能做耗时操作的
- Activity最长响应时间为5s
- BroadCastReceiver最长响应时间为10s
- Service最长响应时间为20s
超时即会发生ANR异常,太过耗时的操作可以创建子线程去完成,我们也知道Service是运行在后台的服务,用户看不见,也能做一些耗时操作,长时间的耗时操作可考虑使用IntentService(extends Service
),是Service的子类;
Service
与BroadcastReceiver
都运行在主线程中
OOM
OutOfMemory
,Android的虚拟机是基于寄存器的Dalvik,最大堆大小一般是16M,有的机器为24M。OutOfMemory的错误,通常 是堆内存溢出。对一般手机应用,手机资源是相当有限的,堆内存的上限值只有16M(有的24M)Android的缺 省值是16M(某些机型是24M),而对于普通应用这是不能改的,当应用程序处理大资源的资源,如图片或视频等媒体资源时,数量一多,时间一长,16M的资源很容易耗尽,所以OOM很容易出现。
虽然Java
有垃圾回收机制,但也存在内存泄露。如果我们一个程序中,已经不再使用某个对象,但是因为仍然有引用指向它,垃圾回收器就无法回收它,当然该对象占用的内存就无法被使用,这就造成了内存泄露。如果我们的java运行很久,而这种内存泄露不断的发生,最后就没内存可用了。当然java的,内存泄漏和C/C++是不一样的。如果java程序完全结束后,它所有的对象就都不可达了,系统就可以对他们进行垃圾回收,它的内存泄露仅仅限于它本身,而不会影响整个系统的。
C/C++的内存泄露就比较糟糕了,它的内存泄露是系统级,即使C/C++程序退出,它的泄露的内存也无法被系统回收,永远不可用 了,除非重启机器。
Android的一个应用程序的内存泄露对别的应用程序影响不大。为了能够使得Android应用程序安全且快速的运行,Android的每个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,它是由Zygote服务进程孵化出的,也就是说每个应用程序都是在属于自己的进程中运行的。 Android为不同类型的进程分配了不同的内存使用上限,如果程序在运行过程中出现了内存泄漏的而造成应用进程使用的内存超过了这个上限,则会被系统视为内存泄漏,从而被kill掉,这使得仅仅自己的进程被kill掉,而不会影响其他进程(如果是system_process等系统进程出问题的话,则会引起系统重启),这是,我们的应用程序就会崩溃,我们就会看到OOM。
引发OOM的原因
- 资源文件未及时关闭:File(未关闭
InputStream
/OutputStream
)、数据库Cursor
未关闭 - 构造adapter未缓存convertView
- 未反注册引起(比如广播)
- Bitmap未使用时未及时recycle()释放
- Context引起的泄漏
- static关键字的不当使用
解决办法
-
static
关键字的使用
static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。用static这个关键字修饰变量,使得该变量的生命周期大大延长,并且访问也极其方便,用类名就能直接访问,各个资源间 传值也极其方便,所以它经常被我们使用。但如果用它来引用一些资源耗费过多的实例(Context的情况最多),这时就要谨慎对待了。- ①:应该尽量避免static成员变量引用资源耗费过多的实例,比如Context。
- ②:Context尽量使用Application Context,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题。
- ③:使用WeakReference代替强引用。比如可以使用WeakReference<Context> mContextRef;
-
Bitmap引起的内存泄漏
- 及时销毁(调用recycle并不确定该bitmap会立即被回收,但给虚拟机说了“改图片是可以销毁的了”,如有需要可手动通过代码置空NULL)
- 设置采样率
我在性能优化篇有说到过采样率,将图片进行缩放
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未关闭
Cursor是Android查询数据后得到的一个管理数据集合的类,正常情况下,如果查询得到的数据量较小时不会有内存问题,而且虚拟机能够保证Cusor最终会被释放掉。
然而如果Cursor的数据量特别大时,应该保证Cursor占用的内存被及时的释放掉,而不是等待GC来处理。并且 Android明显是倾向于编程者手动的将Cursor close掉,因为在源代码中我们发现,如果等到垃圾回收器来回收时,会给用户以错误提示。
所以我们使用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关闭掉,这就是在CursorAdapter中应用的情况,但是注意,CursorAdapter在Acivity结束时并没有自动的将Cursor关闭掉,因此,你需要在onDestroy函数中,手动关闭cursor。
-
inputstream/outputstream
这个我们在操作完毕时关闭就好了 - 未反注册
以广播为例registerReceiver(receiver,filter);
和unregisterReceiver(receiver);
是成对出现的;未调用反注册时程序不会crash掉,在log日志中也会出现错误信息的 - 未缓存converview(少量数据时影响不大)
状态异常
IllegalStateException- 发生情形:
①:fragment中使用recycleview
adapter中加载layout布局时错误使用方法(亲测)
LayoutInflater.from(mContext).inflate(R.layout.item_summary, parent);
- 使用以下方法得以解决
LayoutInflater.from(mContext).inflate(R.layout.item_summary, parent, false);
正在持续更新中……
网友评论