Android初级、中级面试题收录(2)

2019年06月14日 798点热度 1人点赞 0条评论

如何把一个应用设置为系统应用

  • Android设置是Debug版本,且root,直接将该apk用adb工具push到system/app或system/priv-app
  • 如果是非root设备,需要编译后烧写镜像
  • 有些权限(如WRITE_SECURE_SETTINGS)不开放给第三方应用,只能在对应设备源码总编译然后作为系统app使用

Activity,Window,View三者的联系和区别?

  • Activity像一个工匠(控制单元)
  • Window像窗户(承载模型)
  • View像窗花(显示视图)
  • LayoutInflater像剪刀
  • Xml配置像窗花图纸。

Android两个应用能在同一个任务栈吗?

可以

Fragment是什么?你曾经遇到哪些有关Fragment的问题?

  • Fragment可以作为Activity界面的一部分组成出现
    • 其作用是:碎片整理,局部刷新。
  • 一个Activity中可以同时出现多个Fragment,并一个Fragment也可以在多个Activity中使用.
  • 在Activity中可以添加,删除,替换Fragment.Fragment可以响应自己的输入时间,并且有自己的生命周期,但其生命周期收Activity影响

Fragment生命周期

如何实现Activity窗口快速变暗

利用只读属性动画+WindowManager

 /*
  *@param from\>=0&&from\<=1.0f
  * @param to\>=0&&to\<=1.0f
  *
  * */
 private void dimBackground(final float from, final float to) {
 final Window window = getWindow();
 ValueAnimator valueAnimator = ValueAnimator.ofFloat(from, to);
 valueAnimator.setDuration(500);
 valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
 @Override
 public void onAnimationUpdate(ValueAnimator animation) {
 WindowManager.LayoutParams params = window.getAttributes();
 params.alpha = (Float) animation.getAnimatedValue();
 window.setAttributes(params);
 }
 });
 valueAnimator.start();
 }

是否使用过本地广播,和全局广播有什么区别?

本地广播在本应用范围内传播,不用担心隐私数据泄露,不用担心别的应用伪造广播.相比全局广播,本地广播更高效.

注册广播的几种方法?

  • 1.静态注册:在清单文件中注册, 常见的有监听设备启动,常驻注册不会随程序生命周期改变
  • 2.动态注册:在代码中注册,随着程序的结束,也就停止接受广播了补充一点:有些广播只能通过动态方式注册,比如时间变化事件、屏幕亮灭事件、电量变更事件,因为这些事件触发频率通常很高,如果允许后台监听,会导致进程频繁创建和销毁,从而影响系统整体性能

为什么Android引入广播机制?

  • a:从MVC的角度考虑(应用程序内) 其实回答这个问题的时候还可以这样问,android为什么要有那4大组件,现在的移动开发模型基本上也是照搬的web那一套MVC架构,只不过是改了点嫁妆而已。
    • android的四大组件本质上就是为了实现移动或者说嵌入式设备上的MVC架构
    • 它们之间有时候是一种相互依存的关系,有时候又是一种补充关系,引入广播机制可以方便几大组件的信息和数据交互。
  • b:程序间互通消息(例如在自己的应用程序内监听系统来电)
  • c:效率上(参考UDP的广播协议在局域网的方便性)
  • d:设计模式上(反转控制的一种应用,类似监听者模式)

了解IntentServices吗?

  • IntentService是Service的子类,是一个异步的,会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题
  • 生成一个默认的且与线程相互独立的工作线程执行所有发送到onStartCommand()方法的Intent,可以在onHandleIntent()中处理.
  • 串行队列,每次只运行一个任务,不存在线程安全问题,所有任务执行完后自动停止服务,不需要自己手动调用stopSelf()来停止.

如何提升Service进程优先级

在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = “1000”这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。

ContentProvider和sql的区别

ContentProvider的主要还是用于数据共享,其可以对Sqlite,SharePreferences,File等进行数据操作用来共享数据。而sql的可以理解为数据库的一门语言,可以使用它完成CRUD等一系列的操作

数据存储相关

  • 文件存储:通过Java.io.FileInputStream和java.io.FileOutputStream这两个类来实现对文件的读写,java.io.File类则用来构造一个具体指向某个文件或者文件夹的对象。
  • SharedPreferences:SharedPreferences是一种轻量级的数据存储机制,他将一些简单的数据类型的数据,包括boolean类型,int类型,float类型,long类型以及String类型的数据,以键值对的形式存储在应用程序的私有Preferences目录(/data/data/<包名>/shared_prefs/)中,这种Preferences机制广泛应用于存储应用程序中的配置信息。
  • SQLite数据库:当应用程序需要处理的数据量比较大时,为了更加合理地存储、管理、查询数据,我们往往使用关系数据库来存储数据。Android系统的很多用户数据,如联系人信息,通话记录,短信息等,都是存储在SQLite数据库当中的,所以利用操作SQLite数据库的API可以同样方便的访问和修改这些数据。
  • ContentProvider:主要用于在不同的应用程序之间实现数据共享的功能,不同于sharepreference和文件存储中的两种全局可读写操作模式,内容提供其可以选择只对哪一部分数据进行共享,从而保证我们程序中的隐私数据不会有泄漏的风险

如何将打开res aw目录中的数据库文件?

  • 在Android中不能直接打开res aw目录中的数据库文件,而需要在程序第一次启动时将该文件复制到手机内存或SD卡的某个目录中,然后再打开该数据库文件。
  • 复制的基本方法是使用getResources().openRawResource方法获得res aw目录中资源的 InputStream对象,然后将该InputStream对象中的数据写入其他的目录中相应文件中。
  • 在Android SDK中可以使用SQLiteDatabase.openOrCreateDatabase方法来打开任意目录中的SQLite数据库文件。

什么是aar?aar是jar有什么区别?

“aar”包是 Android 的类库项目的二进制发行包。
文件扩展名是.aar,maven 项目类型应该也是aar,但文件本身是带有以下各项的 zip 文件:

  • /AndroidManifest.xml (mandatory)
  • /classes.jar (mandatory)
  • /res/ (mandatory)
  • /R.txt (mandatory)
  • /assets/ (optional)
  • /libs/*.jar (optional)
  • /jni//*.so (optional)
  • /proguard.txt (optional)
  • /lint.jar (optional)

这些条目是直接位于 zip 文件根目录的。 其中R.txt 文件是aapt带参数–output-text-symbols的输出结果。
jar打包不能包含资源文件,比如一些drawable文件、xml资源文件之类的,aar可以。

SQLite支持事务吗?添加删除如何提高性能?

SQLite作为轻量级的数据库,比MySQL还小,但支持SQL语句查询,提高性能可以考虑通过原始经过优化的SQL查询语句方式处理

如何将SQLite数据库(dictionary.db文件)与apk文件一起发布?

可以将dictionary.db文件复制到Eclipse Android工程中的res aw目录中。所有在res aw目录中的文件不会被压缩,这样可以直接提取该目录中的文件。可以将dictionary.db文件复制到res aw目录中

如何保证Service在后台不被kill

  • Service设置成START_STICKY kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样
  • 通过 startForeground将进程设置为前台进程, 做前台服务,优先级和前台应用一个级别​,除非在系统内存非常缺,否则此进程不会被 kill
  • 双进程Service: 让2个进程互相保护**,其中一个Service被清理后,另外没被清理的进程可以立即重启进程
  • QQ黑科技: 在应用退到后台后,另起一个只有 1 像素的页面停留在桌面上,让自己保持前台状态,保护自己不被后台清理工具杀死
  • 在已经root的设备下,修改相应的权限文件,将App伪装成系统级的应用 Android4.0系列的一个漏洞,已经确认可行
  • 用C编写守护进程(即子进程) : Android系统中当前进程(Process)fork出来的子进程,被系统认为是两个不同的进程。当父进程被杀死的时候,子进程仍然可以存活,并不受影响。*鉴于目前提到的在Android->- Service层做双守护都会失败*,我们可以fork出c进程,多进程守护。死循环在那检查是否还存在,具体的思路如下(Android5.0以上的版本不可行)
  • 用C编写守护进程(即子进程),守护进程做的事情就是循环检查目标进程是否存在,不存在则启动它。
    在NDK环境中将1中编写的C代码编译打包成可执行文件(BUILD_EXECUTABLE)。主进程启动时将守护进程放入私有目录下,赋予可执行权限,启动它即可。
  • 联系厂商,加入白名单

Android中如何获得手机的唯一标示.

  • 1 首先尝试读取IMEI、Mac地址、CPU号等物理信息(有不少工具可以修改IMEI);
  • 2 如果均失败,可以自己生成UUID然后保存到文件(文件也可能被篡改或删除)

参考:[blog.csdn.net/xushuaic/ar…]

mipmap文件夹和drawable文件夹的区别

它只是用来放启动图标的,好处就是,你只用放一个mipmap图标,它就会给你各种版本(比如平板,手机)的apk自动生成相应分辨率的图标,以节约空间。

ListView卡顿的原因以及优化策略

  • 重用converView: 通过复用converview来减少不必要的view的创建,另外Infalte操作会把xml文件实例化成相应的View实例,属于IO操作,是耗时操作。
  • 减少findViewById()操作: 将xml文件中的元素封装成viewholder类,通过converview的setTag和getTag方法将view与相应的holder对象绑定在一起,避免不必要的findviewbyid操作
  • 避免在 getView 方法中做耗时的操作: 例如加载本地 Image 需要载入内存以及解析 Bitmap ,都是比较耗时的操作,如果用户快速滑动listview,会因为getview逻辑过于复杂耗时而造成滑动卡顿现象。用户滑动时候不要加载图片,待滑动完成再加载,可以使用这个第三方库glide
  • Item的布局层次结构尽量简单,避免布局太深或者不必要的重绘
  • 尽量能保证 Adapter 的 hasStableIds() 返回 true 这样在 notifyDataSetChanged() 的时候,如果item内容并没有变化,ListView 将不会重新绘制这个 View,达到优化的目的
  • 在一些场景中,ScollView内会包含多个ListView,可以把listview的高度写死固定下来。 由于ScollView在快速滑动过程中需要大量计算每一个listview的高度,阻塞了UI线程导致卡顿现象出现,如果我们每一个item的高度都是均匀的,可以通过计算把listview的高度确定下来,避免卡顿现象出现
  • 使用 RecycleView 代替listview: 每个item内容的变动,listview都需要去调用notifyDataSetChanged来更新全部的item,太浪费性能了。RecycleView可以实现当个item的局部刷新,并且引入了增加和删除的动态效果,在性能上和定制上都有很大的改善
  • ListView 中元素避免半透明: 半透明绘制需要大量乘法计算,在滑动时不停重绘会造成大量的计算,在比较差的机子上会比较卡。 在设计上能不半透明就不不半透明。实在要弄就把在滑动的时候把半透明设置成不透明,滑动完再重新设置成半透明。
  • 尽量开启硬件加速: 硬件加速提升巨大,避免使用一些不支持的函数导致含泪关闭某个地方的硬件加速。当然这一条不只是对 ListView。

ViewHolder为什么要被声明成静态内部类

这是个错误提问,ViewHolder主要分装了Adpter的View,如果设置成static的,那么View持有Context不会被回收,这样会造成内存泄露。

Android中的动画有哪些?

  • 逐帧动画(Drawable Animation):加载一系列Drawable资源来创建动画,简单来说就是播放一系列的图片来实现动画效果,可以自定义每张图片的持续时间
  • 补间动画(Tween Animation):Tween可以对View对象实现一系列简单的动画效果,比如位移,缩放,旋转,透明度等等。但是它并不会改变View属性的值,只是改变了View的绘制的位置,比如,一个按钮在动画过后,不在原来的位置,但是触发点击事件的仍然是原来的坐标。
  • 属性动画(Property Animation):动画的对象除了传统的View对象,还可以是Object对象,动画结束后,Object对象的属性值被实实在在的改变了

Android动画原理

  • Animation框架定义了透明度,旋转,缩放和位移几种常见的动画,而且控制的是整个View
  • 实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值
  • 然后调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧,如果动画没有完成,继续调用invalidate()函数,启动下次绘制来驱动动画
  • 动画过程中的帧之间间隙时间是绘制函数所消耗的时间,可能会导致动画消耗比较多的CPU资源,最重要的是,动画改变的只是显示,并不能相应事件

View绘制相关

SurfaceView和View的区别

  • SurfaceView中采用了双缓存技术,在单独的线程中更新界面
  • View在UI线程中更新界面

介绍下自定义view的基本流程

  • 1、 明确需求,确定你想实现的效果
  • 2、确定是使用组合控件的形式还是全新自定义的形式,组合控件即使用多个系统控件来合成一个新控件,你比如titilebar,这种形式相对简单,参考
  • 3、如果是完全自定义一个view的话,你首先需要考虑继承哪个类,是View呢,还是ImageView等子类。
  • 4、根据需要去复写View#onDraw、View#onMeasure、View#onLayout方法
  • 5.根据需要去复写dispatchTouchEvent、onTouchEvent方法
  • 6、根据需要为你的自定义view提供自定义属性,即编写attr.xml,然后在代码中通过TypedArray等类获取到自定义属性值
  • 7、需要处理滑动冲突、像素转换等问题
    谈谈View的绘制流程

谈谈View的绘制流程

measure()方法,layout(),draw()三个方法主要存放了一些标识符,来判断每个View是否需要再重新测量,布局或者绘制,主要的绘制过程还是在onMeasure,onLayout,onDraw这个三个方法中

  • 1.onMesarue() 为整个View树计算实际的大小,即设置实际的高(对应属性:mMeasuredHeight)和宽(对应属性: mMeasureWidth),每个View的控件的实际宽高都是由父视图和本身视图决定的。
  • 2.onLayout() 为将整个根据子视图的大小以及布局参数将View树放到合适的位置上。
  • 3.onDraw() 开始绘制图像,绘制的流程如下
    • 首先绘制该View的背景
    • 调用onDraw()方法绘制视图本身 (每个View都需要重载该方法,ViewGroup不需要实现该方法)
    • 如果该View是ViewGroup,调用dispatchDraw ()方法绘制子视图
      绘制滚动条

自定义View执行invalidate()方法,为什么有时候不会回调onDraw()

  • 自定义一个view时,重写onDraw。调用view.invalidate(),会触发onDraw和computeScroll()。前提是该view被附加在当前窗口.
    view.postInvalidate(); //是在非UI线程上调用的
  • 自定义一个ViewGroup,重写onDraw。onDraw可能不会被调用,原因是需要先设置一个背景(颜色或图)。表示这个group有东西需要绘制了,才会触发draw,之后是onDraw。因此,一般直接重写dispatchDraw来绘制viewGroup.自定义一个ViewGroup,dispatchDraw会调用drawChild.

事件传递机制

谈谈touch事件的传递流程

  • 所有Touch事件都被封装成了MotionEvent对象,包括Touch的位置、时间、历史记录以及第几个手指(多指触摸)等。
  • 事件类型分为ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每个事件都是以ACTION_DOWN开始ACTION_UP结束。
  • 对事件的处理包括三类,分别为传递——dispatchTouchEvent()函数、拦截——onInterceptTouchEvent()函数、消费——onTouchEvent()函数和OnTouchListener()

简单来说:

  • 事件从Activity.dispatchTouchEvent()开始传递,只要没有被停止或拦截,从最上层的View(ViewGroup)开始一直往下(子View)传递。子View可以通过onTouchEvent()对事件进行处理。
  • 事件由父View(ViewGroup)传递给子View,ViewGroup可以通过onInterceptTouchEvent()对事件做拦截,停止其往下传递。
  • 如果事件从上往下传递过程中一直没有被停止,且最底层子View没有消费事件,事件会反向往上传递,这时父View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到Activity的onTouchEvent()函数。
  • 如果View没有对ACTION_DOWN进行消费,之后的其他事件不会传递过来。

= OnTouchListener优先于onTouchEvent()对事件进行消费。
上面的消费即表示相应函数返回值为true。

View中setOnTouchListener中的onTouch,onTouchEvent,onClick的执行顺序

onTouch优于onTouchEvent,onTouchEvent优于onClick
触摸事件的分发机制详见:
Android触摸事件分发机制完全解析《一》

什么是Dalvik虚拟机

  • Dalvik虚拟机是Android平台的核心。
  • 它可以支持.dex格式的程序的运行
  • .dex格式是专为Dalvik设计的一种压缩格式
  • 可以减少整体文件尺寸
  • 提高I/O操作的速度
  • 适合内存和处理器速度有限的系统

Dalvik虚拟机和JVM有什么区别

  • Dalvik 基于寄存器,而 JVM 基于栈。基于寄存器的虚拟机对于更大的程序来说,在它们编译的时候,花费的时间更短。
  • Dalvik执行.dex格式的字节码,而JVM执行.class格式的字节码

Android为每个应用程序分配的内存大小是多少

  • 一般是16m或者24m,但是可以通过android:largeHeap申请更多内存

【转载】https://juejin.im/post/598f00da51882548630c0eab
来源:掘金

Horry

一个专门收集Android面试题的网站

文章评论

您需要 登录 之后才可以评论