zoukankan      html  css  js  c++  java
  • 最新Android面试题整理,收藏下吧值得拥有!

    这是我近段时间收集的面试题,献给打算年后找工作的同学们。文中涉及的知识比较广也可能比较零散,并且一些较为基础的知识我都略去了(比如Android四大组件是什么这类问题),有些我附上了自己的理解,有些附上了详细的相关文章链接。大家挑自己感兴趣的内容查看即可,后期我也会继续不断补充。

     

    基础组件篇
    横竖屏切换时Activity的生命周期变化?
    不设置Activity的android:configChanges时,切屏会重新回调各个生命周期,切横屏时会执行一次,切竖屏时会执行两次

    设置Activity的android:configChanges=”orientation”时,切屏还是会调用各个生命周期,切换横竖屏只会执行一次

    设置Activity的android:configChanges=”orientation |keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法

    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

    相关文章: Android总结篇系列:Activity Intent Flags及Task相关属性
    Context相关问题
    Activity和Service以及Application的Context是不一样的,Activity继承自ContextThemeWraper.其他的继承自ContextWrapper.

    每一个Activity和Service以及Application的Context都是一个新的ContextImpl对象 getApplication()用来获取Application实例的,但是这个方法只有在Activity和Service中才能调用的到。那么也许在绝大多数情况下我们都是在Activity或者Service中使用Application的,但是如果在一些其它的场景,比如BroadcastReceiver中也想获得Application的实例,这时就可以借助getApplicationContext()方法.

    getApplicationContext()比getApplication()方法的作用域会更广一些,任何一个Context的实例,只要调用getApplicationContext()方法都可以拿到我们的Application对象。

    Context的数量等于Activity的个数 + Service的个数 + 1,这个1为Application.

    那Broadcast Receiver,Content Provider呢?Broadcast Receiver,Content Provider并不是Context的子类,他们所持有的Context都是其他地方传过去的,所以并不计入Context总数。

    怎么在Service中创建Dialog对话框
    1.在我们取得Dialog对象后,需给它设置类型,即:

    dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
    

    2.在Manifest中加上权限:
    View篇
    非UI线程可以更新UI吗?
    可以

    当访问UI时,ViewRootImpl会调用 checkThread 方法去检查当前访问UI的线程是哪个,如果不是UI线程则会抛出异常 执行onCreate方法的那个时候ViewRootImpl还没创建,无法去检查当前线程.ViewRootImpl的创建在onResume方法回调之后.

    void checkThread() {
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }
    }
    

    非UI线程是可以刷新UI的,前提是它要拥有自己的ViewRoot,即更新UI的线程和创建ViewRoot是同一个,或者在执行 checkThread() 前更新UI.

    相关文章: Android子线程真的不能更新UI么

    解决ScrollView嵌套ListView和GridView冲突的方法

    重写ListView的onMeasure方法,来自定义高度:

    @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, expandSpec);
        }
    

    主要考察对MeasureSpec的三种模式的理解,相关文章.

    自定义View优化策略
    为了加速你的view,对于频繁调用的方法,需要尽量减少不必要的代码。先从onDraw开始,需要特别注意不应该在这里做内存分配的事情,因为它会导致GC,从而导致卡顿。在初始化或者动画间隙期间做分配内存的动作。不要在动画正在执行的时候做内存分配的事情。

    你还需要尽可能的减少onDraw被调用的次数,大多数时候导致onDraw都是因为调用了invalidate().因此请尽量减少调用invaildate()的次数。如果可能的话,尽量调用含有4个参数的invalidate()方法而不是没有参数的invalidate()。没有参数的invalidate会强制重绘整个view。

    另外一个非常耗时的操作是请求layout。任何时候执行requestLayout(),会使得Android UI系统去遍历整个View的层级来计算出每一个view的大小。如果找到有冲突的值,它会需要重新计算好几次。另外需要尽量保持View的层级是扁平化的,这样对提高效率很有帮助。

    如果你有一个复杂的UI,你应该考虑写一个自定义的ViewGroup来执行他的layout操作。与内置的view不同,自定义的view可以使得程序仅仅测量这一部分,这避免了遍历整个view的层级结构来计算大小。这个PieChart 例子展示了如何继承ViewGroup作为自定义view的一部分。PieChart 有子views,但是它从来不测量它们。而是根据他自身的layout法则,直接设置它们的大小。

    线程篇
    Handler、Message、Looper、MessageQueue
    一、相关概念的解释

    主线程(UI线程)

    定义:当程序第一次启动时,Android会同时启动一条主线程(Main Thread) 作用:主线程主要负责处理与UI相关的事件

    Message(消息)

    定义:Handler接收和处理的消息对象(Bean对象)

    作用:通信时相关信息的存放和传递

    ThreadLocal

    定义:线程内部的数据存储类

    作用:负责存储和获取本线程的Looper

    MessageQueue(消息队列)

    定义:采用单链表的数据结构来存储消息列表

    作用:用来存放通过Handler发过来的Message,按照先进先出执行

    Handler(处理者)

    定义:Message的主要处理者

    作用:负责发送Message到消息队列&处理Looper分派过来的Message

    Looper(循环器)

    定义:扮演Message Queue和Handler之间桥梁的角色

    作用: 消息循环:循环取出Message Queue的Message 消息派发:将取出的Message交付给相应的Handler

    2、自己画下图解

    3、Handler发送消息有哪几种方式?

    一、sendMessage(Message msg) 二、post(Ruunable r)

    4、Handler处理消息有哪几种方式?

    这个直接看 dispatchMessage() 源码:

    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) {
    }
    

    5.Message、Handler、MessageQueen、Looper的之间的关系?

    首先,是这个MessageQueen,MessageQueen是一个消息队列,它可以存储Handler发送过来的消息,其内部提供了进队和出队的方法来管理这个消息队列,其出队和进队的原理是采用单链表的数据结构进行插入和删除的,即enqueueMessage()方法和next()方法。这里提到的Message,其实就是一个Bean对象,里面的属性用来记录Message的各种信息。

    然后,是这个Looper,Looper是一个循环器,它可以循环的取出MessageQueen中的Message,其内部提供了Looper的初始化和循环出去Message的方法,即prepare()方法和loop()方法。在prepare()方法中,Looper会关联一个MessageQueen,而且将Looper存进一个ThreadLocal中,在loop()方法中,通过ThreadLocal取出Looper,使用MessageQueen的next()方法取出Message后,判断Message是否为空,如果是则Looper阻塞,如果不是,则通过dispatchMessage()方法分发该Message到Handler中,而Handler执行handlerMessage()方法,由于handlerMessage()方法是个空方法,这也是为什么需要在Handler中重写handlerMessage()方法的原因。这里要注意的是Looper只能在一个线程中只能存在一个。这里提到的ThreadLocal,其实就是一个对象,用来在不同线程中存放对应线程的Looper。

    最后,是这个Handler,Handler是Looper和MessageQueen的桥梁,Handler内部提供了发送Message的一系列方法,最终会通过MessageQueen的enqueueMessage()方法将Message存进MessageQueen中。我们平时可以直接在主线程中使用Handler,那是因为在应用程序启动时,在入口的main方法中已经默认为我们创建好了Looper。

    相关文章: blog.csdn.net/qq_30379689…

    6.为什么在子线程中创建Handler会抛异常?

    Handler的工作是依赖于Looper的,而Looper(与消息队列)又是属于某一个线程(ThreadLocal是线程内部的数据存储类,通过它可以在指定线程中存储数据,其他线程则无法获取到),其他线程不能访问。因此Handler就是间接跟线程是绑定在一起了。因此要使用Handler必须要保证Handler所创建的线程中有Looper对象并且启动循环。因为子线程中默认是没有Looper的,所以会报错。 正确的使用方法是:

    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

    1、HandlerThread作用

    当系统有多个耗时任务需要执行时,每个任务都会开启一个新线程去执行耗时任务,这样会导致系统多次创建和销毁线程,从而影响性能。为了解决这一问题,Google提供了HandlerThread,HandlerThread是在线程中创建一个Looper循环器,让Looper轮询消息队列,当有耗时任务进入队列时,则不需要开启新线程,在原有的线程中执行耗时任务即可,否则线程阻塞。

    2、HanlderThread的优缺点

    • HandlerThread本质上是一个线程类,它继承了Thread;
    • HandlerThread有自己的内部Looper对象,可以进行looper循环;
    • 通过获取HandlerThread的looper对象传递给Handler对象,可以在 handleMessage()方法中执行异步任务。
    • 创建HandlerThread后必须先调用 HandlerThread.start() 方法,Thread会先调用run方法,创建Looper对象。
    • HandlerThread优点是异步不会堵塞,减少对性能的消耗
    • HandlerThread缺点是不能同时继续进行多任务处理,需要等待进行处理,处理效率较低
    • HandlerThread与线程池不同,HandlerThread是一个串行队列,背后只有一个线程。

    相关文章: Android 多线程之IntentService 完全详解

    IntentService

    • 它本质是一种特殊的Service,继承自Service并且本身就是一个抽象类

    • 它可以用于在后台执行耗时的异步任务,当任务完成后会自动停止

    • 它拥有较高的优先级,不易被系统杀死(继承自Service的缘故),因此比较适合执行一些高优先级的异步任务 它内部通过HandlerThread和Handler实现异步操作

    • 创建IntentService时,只需实现onHandleIntent和构造方法,onHandleIntent为异步方法,可以执行耗时操作

    • 即使我们多次启动IntentService,但IntentService的实例只有一个,这跟传统的Service是一样的,最终IntentService会去调用onHandleIntent执行异步任务。

    • 当任务完成后,IntentService会自动停止,而不需要手动调用 stopSelf() 。另外,可以多次启动IntentService,每个耗时操作都会以工作队列的方式在 IntentService 中 onHandlerIntent() 回调方法中执行,并且每次只会执行一个工作线程。

    相关文章: Android 多线程之IntentService 完全详解

    AsyncTask

    1、AsyncTask是什么

    AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并主线程中更新UI,通过AsyncTask可以更加方便执行后台任务以及在主线程中访问UI,但是AsyncTask并不适合进行特别耗时的后台任务,对于特别耗时的任务来说,建议使用线程池。

    2、AsyncTask使用方法

    三个参数 Params:表示后台任务执行时的参数类型,该参数会传给AysncTask的doInBackground()方法 Progress:表示后台任务的执行进度的参数类型,该参数会作为onProgressUpdate()方法的参数 Result:表示后台任务的返回结果的参数类型,该参数会作为onPostExecute()方法的参数 五个方法 onPreExecute():异步任务开启之前回调,在主线程中执行 doInBackground():执行异步任务,在线程池中执行 onProgressUpdate():当doInBackground中调用publishProgress时回调,在主线程中执行 onPostExecute():在异步任务执行之后回调,在主线程中执行 onCancelled():在异步任务被取消时回调

    3、AsyncTask引起的内存泄漏

    原因:非静态内部类持有外部类的匿名引用,导致Activity无法释放 解决: AsyncTask内部持有外部Activity的弱引用 AsyncTask改为静态内部类 Activity的onDestory()中调用AsyncTask.cancel()

    4.结果丢失

    屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。

    5、AsyncTask并行or串行

    AsyncTask在Android 2.3之前默认采用并行执行任务,AsyncTask在Android 2.3之后默认采用串行执行任务 如果需要在Android 2.3之后采用并行执行任务,可以调用AsyncTask的executeOnExecutor();

    6.AsyncTask内部的线程池

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

    sDefaultExecutor 是 SerialExecutor 的一个实例,而且它是个静态变量。也就是说,一个进程里面所有AsyncTask对象都共享同一个 SerialExecutor 对象。

    相关文章: android多线程-AsyncTask之工作原理深入解析

    杂谈

    一般情况下第一轮都是基础面试,需要扎实的基础

    最常用的Android 基础知识

    Java 基础知识

    了解一些 常用东西的原理,例如:handler, thread 等

    项目中的技术点

    第二轮的时候需要了解更深层次的东西

    Android 事件分发机制原理

    Android 绘图机制原理

    WindowManager 的相关知识

    进程间传输方式

    Java 内存管理机制

    一些常用的 list,map 原理,以及子类之间的差别

    能进入第三轮基本没什么问题,但是要注意以下问题

    该轮一般是 老大或者部门负责人,问的问题一般都看 深度与广度 当问及薪水的时候,要说一个合适的,小公司随意,大公司一定要慎重,当心里没底的时候,可以告诉对方,让对方给一个合理的薪资。一般都是在原工资基础之上增长,听猎头说一般涨幅都在15%-30%,超 NB 的可以要30%及以上,如果感觉自己还不错的,挺厉害的,建议最高20%,一般人就定在15% 左右最靠谱。公司内部一般有一套机制,根据公司情况而定。

    我们的面试原则就是拿到合理薪资,得到 offer

    个人发展情况,这个问题很难回答,如果和公司方向不符合,极有可能和公司无缘。建议多试探性的问问公司缺少什么,你能否给予公司对应的东西。当然对于有自我追求的人,那可以放心大胆的提。我的方向就是架构师,哈哈哈,挺极端的,别学我哦。我感觉选择都是双向的,因此我知道自己需要的是什么。

    你最擅长什么UI 还是其他什么?这个问题更不好回答。你要说你擅长 UI,是不是意味着你其他能力就不行?虽然我不知道面试官的用意,但是我能感觉到,这个问题不是那么好回答,我会回答说自己都行,来什么业务接什么需求。可能回答不太好,总之和公司的职位吻合就行,这样总不至于出错吧。

     

  • 相关阅读:
    jython resources
    Installing a Library of Jython ScriptsPart of the WebSphere Application Server v7.x Administration Series Series
    jython好资料
    ulipad install on 64bit win7 has issue
    an oracle article in high level to descibe how to archtichre operator JAVA relevet project
    table的宽度,单元格内换行问题
    Linux常用命令大全
    dedecms系统后台登陆提示用户名密码不存在
    登录织梦后台提示用户名不存在的解决方法介绍
    Shell常用命令整理
  • 原文地址:https://www.cnblogs.com/876013676ch/p/10187259.html
Copyright © 2011-2022 走看看