Android面试题(含答案)

来源:互联网 发布:程序员数学 编辑:程序博客网 时间:2024/04/30 20:51

1.service的启动方式

  • Context.startService方式启动:启动时服务没有创建时,会先调用onCreate()方法,然后调用onStart()方法,若启动时此服务已经被创建,则直接调用onStart()方法,不会再重新创建;停止时(调用stopService())会调用onDestory()方法;如果调用者退出时没有调用stopService,则service会一直在后台运行;
  • Context.bindService方式启动:启动时先调用onCreat()->onBind()方法;调用者退出或主动解除绑定时调用onUnbind()->onDestory();
  • 需要注意一点:如果先通过startService启动了服务,然后又通过bindService启动服务,当调用onUnbind()方法时不会调用onDestory()方法,服务还会继续运行。

2.广播注册的方式有几种?有什么不同?

有两种,静态注册和动态注册,具体如下:
  • 静态注册:是在应用程序的AndroidManifast.xml中注册的广播,这种广播为常驻型广播,即当应用程序关闭了,当有广播信息时,广播接收器依然可以接收到广播,如注册开机启动的广播
  • 动态注册:在应用程序中注册广播,应用程序结束了,广播也就没有了,如在Activity的onCreate或者onResume中注册广播接受者,在onDestroy中注销广播接收者,这种注册方式成为动态注册,注册的广播成为非常驻型广播。

3.自定义View中的onMeasure() 方法的作用?

这里顺便提一下onLayout()和onDraw()方法:
  • onMeasure:这个方法用来确定view的大小,这个方法有两个参数onMeasure(int widthMeasureSpec, int heightMeasureSpec);这两个参数由view的layout_width、layout_height、padding、margin和weight决定的;
  • onLayout:这个方法用来确定view在ViewGroup中的位置;
  • onDraw:这个方法主要用来绘制view,决定view是什么样子的。

4.Android中数据存储方式

  • SharedPreferences存储数据:基于XML文件存储的key-value键值对,通常用来存储一些简单的配置信息;
  • 文件存储数据:通过Context的IO流读写文件数据;
  • SQLite存储数据:轻量级数据库,支持SQL语言;
  • ContentProvider存储数据:ContentProvider为数据的存储和读取提供了统一的接口,数据在应用程序件中可以共享,Android的许多内置数据都是通过ContentProvider存储的,如视频、音频、图片、通讯录等
  • 网络存储数据

5.Activity的生命周期,切屏是生命周期的调用情况

Activity的生命周期自己脑补,这里说下切屏时Activity的生命周期的调用情况:
  1. 不设置Activity的Android:configChanges时,切屏会重新调用各个生命周期,其中:切横屏会调用一下,切竖屏会调用两次
  2. 设置Activity的Android:configChanges=”orientation”时,切屏也会重新调用各个生命周期,但都只会调用一次
  3. 设置Activity的Android:configChanges=”orientation|keyboardHidden”时,切屏不会重新调用各个生命周期,只会调用onConfigurationChanged方法

6.在应用退出时怎样确保所有的Activity都关闭了

  1. 定义一个集合,每次进入一个Activity就将当前Activity加入集合中,在ondestory方法中remove掉,在退出应用时遍历集合,关闭集合中的Activity
  2. 通过广播的方式,在每个Activity中注册一个广播接收器,在应用退出时发送一个广播,finish掉每个Activity

    以上两种方式可以写在基类中,避免写起来麻烦,也符合代码规范和面向对象的思想。

7.Service和IntentService的区别

  • Service:Service是后台的服务,不是独立的进程,也不是独立的线程,它是依赖于主线程的,所以要避免在Service中执行耗时的操作,避免发生ANR
  • IntentService:继承于Service,包含Service的全部生命周期和特性,IntentService在创建时(onCreaate()方法中)开启了一个HandlerThread线程来处理Intent对象中所对应的任务,可以避免阻塞主线程。

8.dvm的进程和Linux的进程是否为同一个概念

dvm指的是dalivk虚拟机。每一个Android应用程序都在它自己的进程中运行,都有一个dalivk虚拟机实例,而每一个dvm都是linux中的一个进程,所以可以认为两者是同一个概念。

9.怎样判断是否有SD卡

判断Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)的值,若为true,则有。

10.listview的优化

  1. 复用convertview, 不然假如有1000条数据,那么我们滑动,就会 产生1000个convertview ,这对内存是很大的浪费,所以 我们一定要复用。
  2. 减少 findviewbyid 的次数, 因为 每次 去 执行 findviewbyid 也是要消耗资源的,我们要尽可能的减少,通常 我们定义一个viewholder,去管理 这些id ,然后通过tag 去直接拿到 id。
  3. 分页加载,延迟加载 预加载。 这个在我们以前项目,有一个榜单,数据量很大,一次请求过来的数据量很大,这样有两个问题,一个是 请求网络 时间可能会很长,另一个展示数据 上面 体验对不是很好,所以 我们做了 第一次加载 20条,然后每次请求 再去 加载10条新数据。
  4. 就是 对 listview 中一些 类似头像, 图片的 优化。这里 类似 三级缓存,推荐大家看一下 开源 的universal-image-loader 的源码。或者 这篇文章http://www.jb51.net/article/38162.htm,

下面几道来自鸿洋大神的Blog

11.请解释下在单线程模型中Message,Handler,Message Queue,Looper之间的关系

拿主线程来说,主线程在启动时会调用Looper.prepare()方法,初始化一个Looper,放入ThreadLocal中,接着调用Looper.loop()方法不断循环遍历MessageQueue,Handler的创建依赖于当前线程的中Looper,如果没有Looper,必须调用Looper.prepare()。Handler通过sendMessage到MessageQueue,Looper不断遍历MessageQueue,从中取出消息,回调Handler的handleMessage方法。

12.内存溢出和内存泄漏有什么区别?何时会产生内存泄漏?内存优化有哪些方法?

  • 内存溢出:内存溢出指的是程序(应用)运行所需要的内存超出了它可用的最大内存
  • 内存泄露:内存泄露指的是应用程序中对于某一内存空间使用完之后未释放,导致系统无法回收这块内存。
  • 内存优化:Android中容易导致内存溢出的部分就是图片的加载,我们可以使用图片的压缩加上使用LruCache缓存的目的来控制图片所能够使用的内存;对于比较耗资源的对象及时的关闭,例如Database Conn , 各种传感器 , Service 等等。

13.AsyncTask的使用场景有哪些?它的缺陷是什么?如何解决?

  • 使用场景:适用于执行一些耗时操作,耗时操作完成后更新主线程,或者在耗时操作中对主线程UI进行更新。
  • 缺陷:AsyncTask中维护这一个长度为128的线程池,可以同时执行5个线程,还有一个缓冲队列,当线程池中已经有128个线程时,再加入新的线程时会抛出RejectedExecutionException。
  • 解决:可以由一个控制线程来在AsyncTask调用时判断线程池是否满了,若满了,则把这个线程休眠否则则请求AsyncTask继续处理。

14.Activity间通过Intent传递数据大小有没有限制

貌似是40K。

15.Activity间通过Intent传递数据大小有没有限制?

assets目录更像一个附录类型的目录,Android不会为这个目录中的文件生成ID并保存在R类当中,因此它与Android中的一些类和方法兼容度更低。同时,由于你需要一个字符串路径来获取这个目录下的文件描述符,访问的速度会更慢。但是把一些文件放在这个目录下会使一些操作更加方便,比方说拷贝一个数据库文件到系统内存中。要注意的是,你无法在Android XML文件中引用到assets目录下的文件,只能通过AssetManager来访问这些文件。数据库文件和游戏数据等放在这个目录下是比较合适的。另外,网上关于assets和raw的资料都千篇一律了,因此关于这两者中单个文件大小不能超过1M的错误描述也在传播,即如果读取超过1M的文件会报"Data exceeds UNCOMPRESS_DATA_MAX (1314625 vs 1048576)"的IOException,还引申出种种解决方案。个人认为不应该有这样的限制,为了验证这个说法写了个Demo,发现将近5M的压缩包在assets和raw中都能正常访问,因此在这里纠正一下,理论上只要打包不超过Android APK 50M大小的限制都是没有问题的。当然了,不排除是Android很早期的时候因为设备硬件原因aapt在编译的时候对这两个文件夹大小做出了限制,如果是这样,较新版的ADT应该不会出现这种情况。

16.启动一个程序,可以主界面点击图标进入,也可以从一个程序中跳转过去,二者有什么区别?

是因为启动程序(主界面也是一个app),发现了在这个程序中存在一个设置为<category android:name="android.intent.category.LAUNCHER" />的activity,所以这个launcher会把icon提出来,放在主界面上。当用户点击icon的时候,发出一个Intent:Intent intent = mActivity.getPackageManager().getLaunchIntentForPackage(packageName);mActivity.startActivity(intent);  跳过去可以跳到任意允许的页面,如一个程序可以下载,那么真正下载的页面可能不是首页(也有可能是首页),这时还是构造一个Intent,artActivity。这个intent中的action可能有多种view,download都有可能。系统会根据第三方程序向系统注册的功能,为你的Intent选择可以打开的程序或者页面。所以唯一的一点不同的是从icon的点击启动的intent的action是相对单一的,从程序中跳转或者启动可能样式更多一些。本质是相同的。

17.程序之间的亲和性的理解。

  1. 默认情况下一个应用的所有Activity都是具有相同的affinity,都是从application中继承,application的affinity默认就是manifest的包名。
  2. affinity对Activity来说,就像是身份证一样,可以告诉所在的Task,自己属于其中的一员。
  3. 应用场合:
    a:根据affinity重新为Activity选择合适的宿主Task;
    b:与allowTaskReparenting属性配合;
    c:启动Activity使用Intent设置了FLAG_ACTIVITY_NEW_TASK标记。

0 0
原创粉丝点击