这是我近段时间收集的面试题, 献给打算年后找工作的同学们. 文中涉及的知识比较广也可能比较零散, 并且一些较为基础的知识我都略去了(比如 Android 四大组件是什么这类问题), 有些我附上了自己的理解, 有些附上了详细的相关文章链接. 大家挑自己感兴趣的内容查看即可, 后期我也会继续不断补充.
基础组件篇
横竖屏切换时 Activity 的生命周期变化?
不设置 Activity 的 Android:configChanges 时, 切屏会重新回调各个生命周期, 切横屏时会执行一次, 切竖屏时会执行两次
设置 Activity 的 Android:configChanges="orientation" 时, 切屏还是会调用各个生命周期, 切换横竖屏只会执行一次
设置 Activity 的 Android:configChanges="orientation |keyboardHidden" 时, 切屏不会重新调用各个生命周期, 只会执行 onConfigurationChanged 方法
000000000000.PNG
onSaveInstanceState() 与 onRestoreIntanceState()
资源相关的系统配置发生改变或者资源不足: 例如屏幕旋转, 当前 Activity 会销毁, 并且在 onStop 之前回调 onSaveInstanceState 保存数据, 在重新创建 Activity 的时候在 onStart 之后回调 onRestoreInstanceState. 其中 Bundle 数据会传到 onCreate(不一定有数据)和 onRestoreInstanceState(一定有数据). 用户或者程序员主动去销毁一个 Activity 的时候不会回调, 其他情况都会调用, 来保存界面信息. 如代码中 finish()或用户按下 back, 不会回调.
如何保证 Service 不被杀死?
提供进程优先级, 降低进程被杀死的概率 方法一: 监控手机锁屏解锁事件, 在屏幕锁屏时启动 1 个像素的 Activity, 在用户解锁时将 Activity 销毁掉. 方法二: 启动前台 service. 方法三: 提升 service 优先级: 在 AndroidManifest.xml 文件中对于 intent-filter 可以通过 Android:priority = "1000" 这个属性设置最高优先级, 1000 是最高值, 如果数字越小则优先级越低, 同时适用于广播.
在进程被杀死后, 进行拉活 方法一: 注册高频率广播接收器, 唤起进程. 如网络变化, 解锁屏幕, 开机等 方法二: 双进程相互唤起. 方法三: 依靠系统唤起. 方法四: onDestroy 方法里重启 service:service +broadcast 方式, 就是当 service 走 ondestory 的时候, 发送一个自定义的广播, 当收到广播的时候, 重新启动 service;
依靠第三方 根据终端不同, 在小米手机 (包括 MIUI) 接入小米推送, 华为手机接入华为推送; 其他手机可以考虑接入腾讯信鸽或极光推送与小米推送做 A/B Test.
简述下 Acitivty 任务栈和使用方法
任务栈是一种后进先出的结构. 位于栈顶的 Activity 处于焦点状态, 当按下 back 按钮的时候, 栈内的 Activity 会一个一个的出栈, 并且调用其 onDestory()方法. 如果栈内没有 Activity, 那么系统就会回收这个栈, 每个 App 默认只有一个栈, 以 App 的包名来命名. 1,standard: 默认模式: 每次启动都会创建一个新的 activity 对象, 放到目标任务栈中
2,singleTop: 判断当前的任务栈顶是否存在相同的 activity 对象, 如果存在, 则直接使用, 如果不存在, 那么创建新的 activity 对象放入栈中
3,singleTask: 在任务栈中会判断是否存在相同的 activity, 如果存在, 那么会清除该 activity 之上的其他 activity 对象显示, 如果不存在, 则会创建一个新的 activity 放入栈顶
4,singleIntance: 会在一个新的任务栈中创建 activity, 并且该任务栈种只允许存在一个 activity 实例, 其他调用该 activity 的组件会直接使用该任务栈种的 activity 对象
方法一: 使用 Android:launchMode="standard|singleInstance|single Task|singleTop" 来控制 Acivity 任务栈.
方法二: Intent Flags:
- Intent intent=new Intent();
- intent.setClass(MainActivity.this, MainActivity2.class);
- intent.addFlags(Intent. FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
Flags 有很多, 比如:
Intent.FLAG_ACTIVITY_NEW_TASK 相当于 singleTask
Intent. FLAG_ACTIVITY_CLEAR_TOP 相当于 singleTop
- void checkThread() {
- if (mThread != Thread.currentThread()) {
- throw new CalledFromWrongThreadException(
- "Only the original thread that created a view hierarchy can touch its views.");
- }
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>> 2, MeasureSpec.AT_MOST);
- super.onMeasure(widthMeasureSpec, expandSpec);
- }
- public void dispatchMessage(Message msg) {
- if (msg.callback != null) {
- //1. post()方法的处理方法
- handleCallback(msg);
- } else {
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {
- return;
- }
- }
- //2. sendMessage()方法的处理方法
- handleMessage(msg);
- }
- }
- //1. post()方法的最终处理方法
- private static void handleCallback(Message message) {
- message.callback.run();
- }
- //2. sendMessage()方法的最终处理方法
- public void handleMessage(Message msg) {
- }
- handler = null;
- new Thread(new Runnable() {
- private Looper mLooper;
- @Override
- public void run() {
- // 必须调用 Looper 的 prepare 方法为当前线程创建一个 Looper 对象, 然后启动循环
- //prepare 方法中实质是给 ThreadLocal 对象创建了一个 Looper 对象
- // 如果当前线程已经创建过 Looper 对象了, 那么会报错
- Looper.prepare();
- handler = new Handler();
- // 获取 Looper 对象
- mLooper = Looper.myLooper();
- // 启动消息循环
- Looper.loop();
- // 在适当的时候退出 Looper 的消息循环, 防止内存泄漏
- mLooper.quit();
- }
- }).start();
- HandlerThread
来源: http://www.jianshu.com/p/d9cf5096a403