Android面试题
1.加密
对称加密:加密和解密数据都是使用同一个key,如DES
非对称加密:加密和解密使用不同的key.发送数据之前要先和服务器约定生成公钥和私钥,使用公钥加密的数据可以用私钥解密,反之不行。如RSA、ssh、ssl。
2.android的安全问题
①错误导出组件
②参数校验不严
③WebView引入各种安全问题(JS注入)
④不混淆、不妨二次打包
⑤明文存储关键信息
⑥错误使用HTTPS
⑦山寨加密方法
⑧滥用权限、内存泄漏、使用debug签名
3.设备横竖屏切换的时候,生命周期
①不设置android:configChanges时,切屏会重新调用生命周期,切横屏时会执行一次,切竖屏时会执行两次。
②设置android:configChanges = "orientation"时,切横竖屏时各个生命周期都只执行一次
③设置android:configChanges = "orientation|keyboard"切屏时不会调用各个生命周期,只会走onConfigurationChanged方法
4.android进程间通信方式
intent,Binder(AIDL),Messenger,BroadcastReceiver
5.Parcelable和Serializable的区别
serializable: 简单易用。缺点:使用了反射,序列化过程较慢。使用IO读写存储在硬盘上。
parcelable:速度至上。直接在内存中读写。
6.wait()和sleep()的区别
①sleep来自thread类,wait()来自object类
②调用sleep()方法过程中,线程不会释放对象锁。而wait方法会释放
③sleep睡眠后不出让系统资源,wait出让系统资源其他线程可以占用CPU
④sleep需要指定一个睡眠时间,时间一到会自动唤醒
7.堆和栈的区别
①基本数据类型的变量和对象的引用都是在栈分配的
②堆内存用来存放有new创建的对象和数组
③类变量(静态变量)程序一加载类就在堆中为类变量分配内存,堆中的内存地址存放在栈中
④实例变量:当new的时候,系统在堆中开辟并不一定连续的空间给变量,当引用丢失后,被列入可回收名单,不会马上就释放堆中内存
⑤局部变量:声明在某个方法或代码段里,会在栈中开辟内存,当局部变量一旦脱离作用域,内存立即释放。
8.TCP/IP模型四层
应用层---传输层(TCP/UDP)---网络互联层(IP)---主机到网络层
建立一个TCP连接需要“三次握手”:
第一次握手:客户端发送syn包到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN,同时自己也发送一个SYN包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN包,想服务器发送确认包,此包发送完毕,客户端和服务器进入连接状态,完成三次握手。
9.Android系统结构
应用层---应用框架层---函数库---Linux内核
10.常用布局
LinearLayout---RelativeLayout---FrameLayout---TableLayout---AbsoluteLayout
11.Handler机制
主线程的main方法一运行会准备一个looper轮询器,looper在创建时会new一个MessageQueue消息队列,所以一个线程对应一个looper,一个looper对应一个MQ。
looper创建后,必须调用loop方法,这个方法有个死循环,会不断从消息队列中取消息,如果消息不为空,会调用handler的handleMessage方法处理消息。
如果要做耗时操作时,我们要开一个子线程new Thread,把耗时操作交给子线程处理,但是子线程不能更新UI,需要调用handler的sendMessage方法把更新UI的消息发送到消息队列中,交给主线程处理。
Handler的两种作用:①线程间的通信 ②在未来某个时间点执行一个消息
12.事件分发机制
事件分发的主角有View和ViewGroup。
View有两个方法:dispatchTouchEvent(分发事件)和onTouchEvent(处理事件);
ViewGroup有三个方法:dispatchTouchEvent(分发事件)和onTouchEvent(处理事件),还有onInterceptTouchEvent(拦截事件)。
结构的模型类似下图

外层是ViewGroup,最内层是View。(只要是View,就表示最内层)
触摸时,事件来了:①最外层ViewGroup开始接收,在dispatchTouchEvenet()方法中,调用onInterceptTouchEvent(拦截事件):意思是问自己是否拦截此事件,返回true,表示拦截事件,调用自己的onTouchEvent方法;返回false,表示不拦截事件,事件下传子类;
②如果子类是ViewGroup,继续执行①的流程;
③如果子类是最内层View,在dispatchTouchEvenet()方法中,调用onTouchEvent():意思是问自己是否消费事件,返回true,表示消费事件,事件终止;返回false,表示不消费事件,事件返回给父类(就是上一级)。
④父类接受到返回的事件,调用onTouchEvent方法:返回true,消费事件,事件终止;返回false,不消费事件,事件继续返回。依次类推,返回到最外层ViewGroup,如果没人消费事件,事件丢失。
在触摸时分发机制会确定消费事件的目标,所谓的拦截事件:例如内部子类要消费事件,父类不同意,拦截了事件,事件就落在父类上了(拦截事件其实是将确定的目标置为null,子类的事件得不到确定);还有一种情况,父类拦截了子类的事件,但是子类可以请求父类不要拦截,在分发事件中添加getParent().requestDisallowInterceptTouchEvent(true);这样,子类又会获得事件了(这行代码会使拦截事件的置空方法进不去,子类的事件会得到确定)
13.activity的生命周期
当一个新的页面运行的时候执行顺序onCreate--onStart--onResume,当onResume执行后,页面处于可见可操作(运行状态);
当onRause运行后,页面处于可见但不可操作(暂停状态),走onResume可回到可被操作状态;
当onStop运行后,activity处于不可见不可操作(停止状态),走onRestart--onStart--onResume可回到运行状态;
当onDestroy运行后activity会被销毁;
当onRestart运行后,页面会回到最前面;
系统不经过用户同意将activity销毁时,会调用onSaveInstanceState()方法,可以重写这个方法保存一些数据到Bundle类型对象中,当用户再重启这个界面时Bundle对象会被作为参数传递给onCreate方法,利用这些数据将activity恢复到被摧毁之前的状态。
14.activity的四种启动模式
①standard:默认启动模式,调用startActivity方法,就会在任务栈中创建一个实例
②singleTop:栈顶模式,栈顶只有一个实例。如a开启b,b如果配置了singleTop,则不能开启新的b;
③singleTask:当前任务栈只有一个实例,a-->b-->c-->d,b配置singleTask,d再开启b时会把上面的c和d全部摧毁,把b暴露在栈顶;
④singleInstance:应用中只有一个实例,这个实例会单独占一个任务栈
15.广播
步骤:①写一个类继承BroadcastReceiver
②重写onReceive方法
③清单文件中注册广播接收者
④有的广播需要权限
有序广播:①发送方法 sendOrderedBroadcast ②接收顺序:可以指定优先级 ③可被中断
无序广播:①发送方法 sendBroadcast(intent)②接收顺序:没有顺序,同时接收 ③不可被中断
16.进程的优先级
①前台进程 ②可视进程 ③服务进程 ④后台进程 ⑤空进程
17.service服务
开启服务有两种方式:startService和bindService
startservice:①调用startservice后,走onCreate--onStartCommend ②多次调用startservice,onCreate只会走一次,onStartCommend会调用多次 ③通过startservice开启的service在activity退出后,不会销毁 ④只有手动调用stopservice方法,才会销毁服务 ⑤startservice方式开启的服务可以提升应用的进程优先级
bindservice:①调用bindservice后,走onCreate--onBind ②多次调用bindservice,这两个方法都只会执行一次 ③通过bindservice开启的service生命周期与activity的生命周期关联起来了 ④在activity退出时必须解绑 unbindservice(只能调用一次) ⑤service中的onBind方法中有返回值,那么在serviceConnection中第二个参数就是onBind方法的返回值
服务中可做耗时操作。
18.AIDL 安卓接口定义语言(解决的是跨进程调用的问题)
19.ContentProvider 内容提供者
跨应用 共享数据
内容观察者contentobserver :当数据发生变化时,会发一个notifychanged消息。
20.Context 上下文
getApplicationContext获取的是应用的上下文,生命周期是整个应用;而Activity.this获取的是这个Activity的上下文,生命周期是所在的Activity.
只有在创建对话框AlertDialog时必须使用activity作为上下文,因为AlertDialog是要显示在activity的上面,必须传一个activity的上下文才能正常显示;Toast跟AlertDialog不同,Toast是系统级的显示控件,会显示在所有应用的最上层不会被其他节目遮挡,所有传应用的上下文也可以显示Toast
上下文的计算公式 = 服务的个数 + activity的个数 + 1;
21.动画
动画分为两类:属性动画和View动画
View动画又分为:帧动画和补间动画
帧动画就是在xml文件中配置的一帧一帧的图片
属性动画和补间动画都可以旋转、平移和缩放,属性动画会改变原来控件的属性和位置,补间动画播放时则不改变原控件的属性。
22.JNI Java Native Interface(java本地接口)
JNI可以看做是一个翻译,实现JAVA语言和本地语言之间的互相调用
交叉编译原理:在一个平台上模拟另一个平台的特性进行编译
NDK:native develop kit 本地开发工具包
23.序列化和反序列化
把对象转换为字节序列的过程,叫对象的序列化
把字节序列恢复为对象的过程,叫对象的反序列化
24.内存泄露
分配的内存空间使用完毕后,没有得到释放。运行时间越长,占的内存越多,直至崩溃。
①对象内存过大
②资源释放问题:使用完资源,没有及时释放
③static变量生命周期长,要是与组件引用起来,组件很难被释放
25.ANR Application Not Responding
应用在特定时间内无响应
避免方法:①避免在主线程上进行复杂耗时的操作;
②broadCastReceiver 要进行复杂操作的的时候,可以在onReceive()方法中启动一个Service来处理;
③在设计及代码编写阶段避免出现出现同步/死锁或者错误处理不恰当等情况。
26.线程间通信
①共享内存 ②文件、数据库 ③handler ④java中的wait,notify,notifyAll
27.屏幕适配
px:像素 dp:像素密度
28.Socket和Http的区别
TCP/IP的参数模型有四层:应用层---传输层---网络互联层---主机到网络层
HTTP:首先是一个协议,是基于TCP/IP协议基础上的应用层协议,TCP/IP协议是传输层协议,主要解决数据如何在网络中传输;HTTP是应用层协议,主要解决如何包装数据。---短连接。
Socket:不属于协议范畴,而是一个调用接口(API),是对TCP/IP协议的封装,调用socket,才能使用TCP/IP协议。---长连接。
HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束猴,主动释放连接,由于HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是“短连接”。要保持客户端程序的在线状态,需要不断向服务器发起连接请求。服务器在收到该请求后对客户端进行回复,表示客户端“在线”;若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。
Socket连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
服务器监听:服务器套接字并不定位具体客户端套接字,而是出于等待连接的状态,实时监控网络状态,等待客户端的连接请求。
客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器的套接字。客户端的套接字必须先描述它要连接的服务器的套接字,指出服务器套接字的地址和端口号,然后向服务器套接字提出连接请求。
连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
socket的应用场景:网络游戏、银行交易、支付系统;
http的应用场景:OA(办公网络)、互联网;
29.对多线程的认识
主线程一般负责用户界面的绘制和及时响应用户的操作,让子线程在后台执行一些比较耗时的任务。
Android中使用多线程的原因:
①I/O操作:文件、网络和数据库
②复杂的运算
③定时操作
注意:异步就是多线程。对耗时操作应该放到非主线程中运行,避免阻塞主线程。子线程不能更新UI.
多线程用到的类:Thread、Handle、Runable、AsyncTask
AsyncTask是对Handler与线程池的封装。Handler是为了将消息发送给主线程。使用线程池的主要原因是避免不必要的创建及销毁线程的开销。
并发和并行:单核机器上,操作系统快速在进程间切换而模拟出的多线程---并发;多核情况下,并发就变为并行了。
阻塞状态:I/O操作访问磁盘时,相对于访问内存和简单计算,需要的时间比较长,此时就是阻塞状态,会阻塞进程(操作系统会让当前进程暂时休眠,去执行别的进程,以免浪费时间,当该进程处理完后,会发出信号通知操作系统来继续执行该进程)。
进程就是执行中的程序实例,而线程可以看作是进程中的最小执行单元。
创建一个新线程:①通过实现Runnable接口
实现Runnable接口并实例化,将这个对象传给Thread的构造器来创建一个新的线程
②通过继承Thread抽象类
继承并实例化直接创建一个新线程
二者比较:Thread虽然简单但是不能多继承,Runnable麻烦但是可以继承其他类
线程的生命周期:
①新建(new Thread)
②就绪(runnable):线程对象调用start方法后,会进入Runnable状态(在就绪队列中排队等待CPU资源)
③运行(running):线程获取CPU资源执行任务(run方法)
④死亡(dead):当前线程执行完毕或被其他线程杀死,该线程不能进入就绪状态;自然终止:run方法运行结束;异常终止:调用stop方法终止
⑤阻塞(blocked):由于某种原因正在运行的线程让出CPU并暂停自己的执行。睡眠可进入阻塞状态,等待也可进入阻塞状态,还可被另一个线程阻塞(suspend方法)

浙公网安备 33010602011771号