我是靠谱客的博主 美丽电脑,最近开发中收集的这篇文章主要介绍android常见面试题与我自己的回答 (三),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1,ANR产生的原因和处理?

ANR的产生需要同时满足三个条件:

  • 主线程:只有应用程序进程的主线程响应超时才会产生ANR;

  • 超时时间:产生ANR的上下文不同,超时时间也会不同,但只要在这个时间上限内没有响应就会ANR;

  • 输入事件/特定操作:输入事件是指按键、触屏等设备输入事件,特定操作是指BroadcastReceiver和Service的生命周期中的各个函数,产生ANR的上下文不同,导致ANR的原因也会不同;

主线程对输入事件在5秒内没有处理完毕

主线程在执行BroadcastReceiveronReceive函数时10秒内没有执行完毕

主线程在执行Service的各个生命周期函数时20秒内没有执行完毕

三种ANR发生时都会在log中输出错误信息,你会发现各个应用进程和系统进程的函数堆栈信息都输出到了一个/data/anr/traces.txt的文件中,这个文件是分析ANR原因的关键文件,同时在日志中还会看到当时的CPU使用率

发生ANR时Android为我们提供了两种“利器”:traces文件和CPU使用率


2,HashMap的实现

哈希表是由数组+链表组成的,一个长度为16的数组中,每个元素存储的是一个链表的头结点。那么这些元素是按照什么样的规则存储到数组中呢。一般情况是通过hash(key)%len获得,也就是元素的key的哈希值对数组长度取模得到。

解决hash冲突的办法

  1. 开放定址法(线性探测再散列,二次探测再散列,伪随机探测再散列)
  2. 再哈希法
  3. 链地址法
  4. 建立一个公共溢出区

再散列rehash过程

当哈希表的容量超过默认容量时,必须调整table的大小。当容量已经达到最大可能值时,那么该方法就将容量调整到Integer.MAX_VALUE返回,这时,需要创建一张新表,将原表的映射到新表中。


3,Service 两种启动方式

1通过startService
Service会经历onCreate->onStart
stopService的时候直接onDestroy
  

如果是调用者(TestServiceHolder)自己直接退出而没有调用stopService的话,Service会一直在后台运行。
下次TestServiceHolder再起来可以stopService。
  
2通过bindService
Service只会运行onCreate,这个时候TestServiceHolder和TestService绑定在一起
  
TestServiceHolder退出了,Srevice就会调用onUnbind->onDestroyed
所谓绑定在一起就共存亡了。


4,Android跨进程通信

一、访问其他应用程序的Activity

Activity的跨进程访问与进程内访问略有不同。虽然它们都需要Intent对象,但跨进程访问并不需要指定Context对象和Activity的 Class对象,而需要指定的是要访问的Activity所对应的Action(一个字符串)。有些Activity还需要指定一个Uri(通过 Intent构造方法的第2个参数指定)。

二、Content Provider 

1.  编写一个继承于android.content.ContentProvider的子类。该类是ContentProvider的核心类。在该类中会实现 query、insert、update及delete方法。实际上调用ContentResolver类的这4个方法就是调用 ContentProvider类中与之要对应的方法。在本文中只介绍query。至于insert、update、delete和query的用法类 似。也是通过Uri传递参数,然后在这些方法中接收这些参数,并做进一步地处理。
2.  在AndroidManifest.xml文件中配置ContentProvider。要想唯一确定一个ContentProvider,需要指定这个 ContentProvider的URI,除此之外,还需要指定URI所对应的ContentProvider类。这有些象Servlet的定义,除了要 指定Servlet对应的Web地址,还要指定这个地址所对应的Servlet类

3,广播(Broadcast) 

4,AIDL服务

1.  在Eclipse工程的package目录中建立一个扩展名为aidl的文件。package目录就是Java类所在的目录。该文件的语法类似于Java代码。aidl文件中定义的是AIDL服务的接口。这个接口需要在调用AIDL服务的程序中访问。
2.  如果aidl文件的内容是正确的,Eclipse插件会自动生成一个Java接口文件(*.java)。
3.  建立一个服务类(Service的子类)。
4.  实现由aidl文件生成的Java接口。
5.  在AndroidManifest.xml文件中配置AIDL服务,尤其要注意的是,<action>标签的android:name属性值就是客户端要引用该服务的ID,也就是Intent类构造方法的参数值。

在编写AIDL服务和客户端时要注意如下两点:

1.  AIDL服务中的onBind方法必须返回AIDL接口对象(MyServiceImpl对象)。该对象也是onServiceConnected事件方法的第2个参数值。
2.  bindService方法的第1个参数是Intent对象,该对象构造方法的参数需要指定AIDL服务的ID,也就是在 AndroidManifest.xml文件中<service>标签的<action>子标签的android:name属性 的值。


5,堆和栈的区别

栈区(stack)—   由编译器自动分配释放   ,存放函数的参数值,局部变量的值等。其  操作方式类似于数据结构中的栈。  

堆区(heap)   —   一般由程序员分配释放,   若程序员不释放,程序结束时可能由OS回 收。

碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以参考数据结构,这里我们就不再一一讨论了。
    生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。
    分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
    分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。


6,Android平台体系结构中的虚拟机与JAVA中的虚拟机有什么不同

Dalvik 和标准Java 虚拟机(JVM)首要差别
Dalvik 基于寄存器,而 JVM 基于栈。基于寄存器的虚拟机对于更大的程序来说,在它们编译的时候,花费的时间更短。
Dalvik 和Java 运行环境的区别
1:Dalvik主要是完成对象生命周期管理,堆栈管理,线程管理,安全和异常管理,以及垃圾回收等等重要功能。
2:Dalvik负责进程隔离和线程管理,每一个Android应用在底层都会对应一个独立的Dalvik虚拟机实例,其代码在虚拟机的解释下得以执行。
3:不同于Java虚拟机运行java字节码,Dalvik虚拟机运行的是其专有的文件格式Dex
4:dex文件格式可以减少整体文件尺寸,提高I/o操作的类查找速度。
5:odex是为了在运行过程中进一步提高性能,对dex文件的进一步优化。
6:所有的Android应用的线程都对应一个Linux线程,虚拟机因而可以更多的依赖操作系统的线程调度和管理机制
7:有一个特殊的虚拟机进程Zygote,他是虚拟机实例的孵化器。它在系统启动的时候就会产生,它会完成虚拟机的初始化,库的加载,预制类库和初始化的操作。如果系统需要一个新的虚拟机实例,它会迅速复制自身,以最快的数据提供给系统。对于一些只读的系统库,所有虚拟机实例都和Zygote共享一块内存区域。


7,listview优化

1,利用convertview回收视图,效率提高200%.

2,利用viewholder模式,效率在提高50%

3,图片处理,缓存等

1.图像尺寸不合适会导致自动缩放

2.避免实时缩放

3.最好预先缩放到视图大小

4,在性能敏感的代码里,避免创建java对象

1.测量 onmeasure()

2.布局onlayout()

3.绘图 ondraw() dispatchdraw()

4.事件处理 ontouchevent() dispatchtouchevent()

5.adapter: getview() bindview()


8,Android内存泄露

1,查询数据库而没有关闭Cursor

2,调用registerReceiver后未调用unregisterReceiver().

3,未关闭InputStream/OutputStream

4,Bitmap使用后未调用recycle()

5,Context泄露

6,集合中对象没清理造成的内存泄漏


9,HashMap与ConcurrentHashMap的区别

ConcurrentHashMap具体是怎么实现线程安全的呢,肯定不可能是每个方法加synchronized,那样就变成了HashTable。

从ConcurrentHashMap代码中可以看出,它引入了一个“分段锁”的概念,具体可以理解为把一个大的Map拆分成N个小的HashTable,根据key.hashCode()来决定把key放到哪个HashTable中。

在ConcurrentHashMap中,就是把Map分成了N个Segment,put和get的时候,都是现根据key.hashCode()算出放到哪个Segment中

以上就是ConcurrentHashMap的工作机制,通过把整个Map分为N个Segment(类似HashTable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。

最后

以上就是美丽电脑为你收集整理的android常见面试题与我自己的回答 (三)的全部内容,希望文章能够帮你解决android常见面试题与我自己的回答 (三)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(56)

评论列表共有 0 条评论

立即
投稿
返回
顶部