当前位置 博文首页 > 云雾蜜蜜,咩咩:??[灵魂拷问]Android面试高频100问(架构师方向)

    云雾蜜蜜,咩咩:??[灵魂拷问]Android面试高频100问(架构师方向)

    作者:[db:作者] 时间:2021-08-14 15:04

    前言

    本文主要受众为开发人员,所以不涉及到Android的服务部署等操作,且内容较多,大家准备好耐心和瓜子矿泉水.
    前一阵空闲下来整理了下前阿里P7高级工程师留下Android高频面试题,之前在网上偶然看到一篇和Android相关的面试文章,发现其中的一些问题自己也回答不好,虽然知识点大部分都知道,但是无法将知识串联起来.
    因此决定搞一个Android灵魂100问,试着用回答问题的方式,让自己对知识点的理解更加深入一点.
    此文不会事无巨细的从Android的用法开始讲解,主要针对的是开发人员需要知道的一些Android的知识点,主要包括基础,项目、性能优化、开源框架等方面,以在面试中高频的问句形式给出答案.(文末有惊喜)

    Activity相关

    1、什么是Activity?
    四大组件之一,一般的,一个用户交互界面对应一个activity
    setContentView() ,// 要显示的布局
    button.setOnclickLinstener{
    }, activity 是Context的子类,同时实现了window.callback和keyevent.callback, 可以处理与窗体用户交互的事件.
    我开发常用的的有FragmentActivitiyListActivity ,PreferenceActivity ,TabAcitivty等
    2、请描述一下Activity 生命周期
    Activity从创建到销毁有多种状态,从一种状态到另一种状态时会激发相应的回调方法,这些回调方法包括:onCreate onStart onResume onPause onStop onDestroy
    其实这些方法都是两两对应的,onCreate创建与onDestroy销毁;
    onStart可见与onStop不可见;onResume可编辑(即焦点)与onPause;
    如果界面有共同的特点或者功能的时候,还会自己定义一个BaseActivity.
    进度对话框的显示与销毁
    3、常见的Activity类型有FragmentActivitiy,ListActivity,TabAcitivty等。请描述一下Activity 生命周期
    Activity从创建到销毁有多种状态,从一种状态到另一种状态时会激发相应的回调方法,这些回调方法包括:onCreate onStart onResume onPause onStop onDestroy
    其实这些方法都是两两对应的,onCreate创建与onDestroy销毁;
    onStart可见与onStop不可见;onResume可编辑(即焦点)与onPause。
    4、两个Activity之间跳转时必然会执行的是哪几个方法?
    一般情况下比如说有两个activity,分别叫A,B,当在A里面激活B组件的时候, A会调用 onPause()方法,然后B调用onCreate() ,onStart(), onResume()。
    这个时候B覆盖了窗体, A会调用onStop()方法. 如果B是个透明的,或者是对话框的样式, 就不会调用A的onStop()方法。

    Service相关

    1、Service是否在main thread中执行, service里面是否能执行耗时的操作?
    默认情况,如果没有显示的指servic所运行的进程, Service和activity是运行在当前app所在进程的main thread(UI主线程)里面。
    service里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 )
    特殊情况 ,可以在清单文件配置 service 执行所在的进程 ,让service在另外的进程中执行

    <service
                android:name="com.baidu.location.f"
                android:enabled="true"
                android:process=":remote" >
            </service>
    

    2、什么是IntentService?有何优点?
    我们通常只会使用Service,可能IntentService对大部分同学来说都是第一次听说。那么看了下面的介绍相信你就不再陌生了。如果你还是不了解那么在面试的时候你就坦诚说没用过或者不了解等。并不是所有的问题都需要回答上来的。

    3、Activity怎么和Service绑定,怎么在Activity中启动自己对应的Service?

    • Activity通过bindService(Intent service, ServiceConnection conn, int flags)跟Service进行绑定,当绑定成功的时候Service会将代理对象通过回调的形式传给conn,这样我们就拿到了Service提供的服务代理对象。
    • 在Activity中可以通过startService和bindService方法启动Service。一般情况下如果想获取Service的服务对象那么肯定需要通过bindService()方法,比如音乐播放器,第三方支付等。如果仅仅只是为了开启一个后台任务那么可以使用startService()方法。

    Android性能优化方面

    1、如何对Android应用进行性能分析
    一款App流畅与否安装在自己的真机里,玩几天就能有个大概的感性认识。不过通过专业的分析工具可以使我们更好的分析我们的应用。而在实际开发中,我们解决完当前应用所有bug后,就会开始考虑到新能的优化。
    如果不考虑使用其他第三方性能分析工具的话,我们可以直接使用ddms中的工具,其实ddms工具已经非常的强大了。ddms中有traceview、heap、allocation tracker等工具都可以帮助我们分析应用的方法执行时间效率和内存使用情况

    2、什么情况下会导致内存泄露
    Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的机器为24M。因此我们所能利用的内存空间是有限的。如果我们的内存占用超过了一定的水平就会出现OutOfMemory的错误
    内存溢出的几点原因:
    (1)资源释放问题
    (2)对象内存过大问题
    (3)static关键字的使用问题

    3、如何避免OOM异常
    OOM内存溢出,想要避免OOM异常首先我们要知道什么情况下会导致OOM异常
    (1)图片过大导致OOM
    (2)界面切换导致OOM
    (3)查询数据库没有关闭游标
    (4)构造Adapter时,没有使用缓存的 convertView
    (5)Bitmap对象不再使用时调用recycle()释放内存
    (6)其他
    Android应用程序中最典型的需要注意释放资源的情况是在Activity的生命周期中,在onPause()、onStop()、 onDestroy()方法中需要适当的释放资源的情况。使用广播没有注销也会产生OOM

    4、Android线程间通信有哪几种方式?
    ?共享内存(变量);
    ?文件,数据库;
    ?Handler;
    ?Java里的wait(),notify(),notifyAll()

    5、简述android应用程序结构是哪些?
    Android应用程序结构也就是讲我们的工程结构:

    事件处理

    1、事件分发中的onTouch和onTouchEvent有什么区别,又该如何使用?
    这两个方法都是在View的dispatchTouchEvent中调用的,onTouch优先于onTouchEvent执行。如果在onTouch方法中通过返回true将事件消费掉,onTouchEvent将不会再执行。
    另外需要注意的是,onTouch能够得到执行需要两个前提条件,第一mOnTouchListener的值不能为空,第二当前点击的控件必须是enable的。因此如果你有一个控件是非enable的,那么给它注册onTouch事件将永远得不到执行。对于这一类控件,如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实现。

    2、AIDL的全称是什么?如何工作?能处理哪些类型的数据?
    AIDL全称Android Interface Definition Language(AndRoid接口描述语言) 是一种接口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程跨界对象访问的目的。需要完成2件事情:

    1. 引入AIDL的相关类.;
    2. 调用aidl产生的class.理论上, 参数可以传递基本数据类型和String, 还有就是Bundle的派生类, 不过在Eclipse中,目前的ADT不支持Bundle做为参数。

    线程篇

    1、相关概念的解释

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

    private final class WorkThread extends Thread {
            private Handler mHandler;
            public Handler getHandler() {
                return mHandler;
            }
              public void quit() {
                mHandler.getLooper().quit();
            }
            @Override
            public void run() {
                super.run();
                //创建该线程对应的Looper,
                // 内部实现
                // 1。new Looper()
                // 2。将1步中的lopper 放在ThreadLocal里,ThreadLocal是保存数据的,主要应用场景是:线程间数据互不影响的情况
                // 3。在1步中的Looper的构造函数中new MessageQueue();
                //其实就是创建了该线程对用的Looper,Looper里创建MessageQueue来实现消息机制
                //对消息机制不懂得同学可以查阅资料,网上很多也讲的很不错。
                Looper.prepare();
                mHandler = new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                        Log.d("WorkThread", (Looper.getMainLooper() == Looper.myLooper()) + "," + msg.what);
                    }
                };
                //开启消息的死循环处理即:dispatchMessage
                Looper.loop();
                //注意这3个的顺序不能颠倒
                Log.d("WorkThread", "end");
            }
        }
    

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

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

    5、子线程发消息到主线程进行更新UI,除了handler和AsyncTask,还有什么
    1、用Activity对象的runOnUiThread方法更新
    在子线程中通过runOnUiThread()方法更新UI:


    如果在非上下文类中(Activity),可以通过传递上下文实现调用;


    2、用View.post(Runnable r)方法更新UI

    开源框架相关

    1、开发中都使用过哪些框架、平台
    1.EventBus(事件处理)
    2.xUtils(网络、图片、ORM)

    2、可以先说下三级缓存的原理

    1. 从缓存中加载。
    2. 从本地文件中加载(数据库,SD)
    3. 从网络加载。

    a.加载bitmap的时候无需考虑bitmap加载过程中出现的oom(内存溢出)和android容器快速滑动的时候出现的图片错位等现象。(16M)
    b. 支持加载网络图片和本地图片。
    c. 内存管理使用的lru算法(移除里面是有频率最少的对象),更好的管理bitmap的内存。
    d.可配置线程加载的数量,缓存的大小,缓存的路径,加载显示的动画等。

    3、 可以先说下Gson的作用,然后在向后拓展下。
    Gson呢,是google提供的一个快速解析json数据的开源框架,原来我们解析数据的时候都是jsonObject jsonArray 一层层解析,我发现这样层层解析很浪费时间,于是我在业余时间研究了Gson,Gson满足了我们快速开发的特性,只要从服务器拿到json数据用Gson解析,Gson就会返回一个数据对象,我们就可以直接对数据进行操作了。原来解析可能需要十几分钟的事,现在两三分钟就搞定了

    4、imageLoader (图片处理框架)
    目前主流的图片缓存处理框架,只要配置相关参数即可。

    5、项目的流程
    这个在项目中不一定问,但是大家要知道项目开发的流程,作为有经验的程序员程序的流程是一定知道的。
    按时间轴来排列:
    立项:确定项目、负责人、开发的周期、成本、人力、物力
    需求:文档、原型图
    开发:编码
    测试:测试人员
    上线:产品部门
    维护:修复新的bug
    升级:改版、添加新的功能

    项目

    1、什么是socket?,TCP 和 UDP每个数据包的大小
    Socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信连的句柄,应用程序通常通过“套接字”向网络发送请求或者应答网络请求,它就是网络通信过程中端点的抽象表示。它主要包括TCP,UDP两个协议。

    • UDP 包的大小是 1492 - IP头(20) - UDP头(8) = 1464字节
    • TCP 包的大小是 1492 - IP头(20) - TCP头(20) = 1452字节

    2、用 volley 如何下载数据较大的文件 Volley 的二次封装是怎样做的
    (1)Volley本身不支持大数据文件的下载,如果必须使用的volley进行下载,可进行断点下载;将每次的下载文件尽可能的切割成更小的文件进行下载。
    (2)二次封装
    ①直接封装一个数据接口,方便我们在Activity中直接得到网络请求的结果数据。
    ②封装一个JsonObject请求结果的泛型封装类,方便对不同的实体类的解析。
    ③封装Volley请求方法,包括GET,POST等主流请求方式,及json文件的解析方法。最后,在Activity中的调用。

    3、如何实现文件断点上传
    在Android中上传文件可以采用HTTP方式,也可以采用Socket方式,但是HTTP方式不能上传大文件,这里介绍一种通过Socket方式来进行断点续传的方式,服务端会记录下文件的上传进度,当某一次上传过程意外终止后,下一次可以继续上传,这里用到的其实还是J2SE里的知识。

    这个上传程序的原理是:客户端第一次上传时向服务端发送“Content-Length=35;filename=WinRAR_3.90_SC.exe;sourceid=“这种格式的字符串,服务端收到后会查找该文件是否有上传记录,如果有就返回已经上传的位置,否则返回新生成的sourceid以及position为0,类似sourceid=2324838389;position=0“这样的字符串,客户端收到返回后的字符串后再从指定的位置开始上传文件。

    4、简述一下MVC和MVP这两种设计模式,说说各自的特点


    在MVC里,View是可以直接访问Model的!从而,View里会包含Model信息,不可避免的还要包括一些业务逻辑。 在MVC模型里,更关注的Model的不变,而同时有多个对Model的不同显示,及View。所以,在MVC模型里,Model不依赖于View,但是 View是依赖于Model的。不仅如此,因为有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少那些业务逻辑是无法重用的。

    5、说说mvc模式的原理,它在android中的运用
    MVC英文即Model-View-Controller,即把一个应用的输入、处理、输出流程按照Model、View、Controller的方式进行分离,这样一个应用被分成三个层——模型层、视图层、控制层。
    Android中界面部分也采用了当前比较流行的MVC框架,在Android中M就是应用程序中二进制的数据,V就是用户的界面。Android的界面直接采用XML文件保存的,界面开发变的很方便。在Android中C也是很简单的,一个Activity可以有多个界面,只需要将视图的ID传递到setContentView(),就指定了以哪个视图模型显示数据。
    在Android SDK中的数据绑定,也都是采用了与MVC框架类似的方法来显示数据。在控制层上将数据按照视图模型的要求(也就是Android SDK中的Adapter)封装就可以直接在视图模型上显示了,从而实现了数据绑定。比如显示Cursor中所有数据的ListActivity,其视图层就是一个ListView,将数据封装为ListAdapter,并传递给ListView,数据就在ListView中显示。

    由于文章篇幅有限,资料放在在我的QQ技术交流群里可以自助拿走,如果在学习或工作中遇到了问题,群里会有一些大神帮忙解答,有时你闷头想一天,不如别人的三言两语就醍醐灌顶,群793544421

    推荐↓↓↓

    cs
    下一篇:没有了