1549页Android最新面试题含答案

155 阅读32分钟

在今年年初的疫情中,成了失业人员之一,于是各种准备面试,发现面试题网上很多,但是都是很凌乱的,而且一个地方一点,没有一个系统的面试题库,有题库有的没有答案或者是答案很简洁,没有达到面试的要求。所以一直想系统的整理一份面试题。

最近终于得闲花了将近一个月的时间整理了一份面试题库。这些面试题,包括我本人自己去面试遇到的,还有其他人员去面试遇到的,我都统一的整理了一下,希望对大家有用。作者不易,如有错误望见谅。

一、java面试题(基础+进阶)(必须)

1.java中==和equals和hashCode的区别

==是运算符,用来比较两个值、两个对象的内存地址是否相等; equals是Object类的方法,默认情况下比较两个对象是否是同一个对象,内部实现是通过“==”来实现的。 如果想比较两个对象的其他内容,则可以通过重写equals方法, hashCoed也是Object类里面的方法,返回值是一个对象的哈希码,同一个对象哈希码一定相等,但不同对象哈希码也有可能相等。 1、如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。 2、如果两个对象不equals,他们的hashcode有可能相等。 3、如果两个对象hashcode相等,他们不一定equals。 4、如果两个对象hashcode不相等,他们一定不equals。

2.int、char、long各占多少字节数(笔试题多出现)

Int:4字节 chat:2字节 long\double:8字节

3.int与integer的区别 (笔试)

1、Integer是int的包装类,int则是java的一种基本数据类型 2、Integer变量必须实例化后才能使用,而int变量不需要 3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值 4、Integer的默认值是null,int的默认值是0

4.谈谈对java多态的理解

多态是指:父类引用指向子类对象,在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。(同一消息可以根据发送对象的不同而采用多种不同的行为方式。

多态的作用:消除类型之间的耦合关系。

实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。

实现多态的三要素:继承,重写,父类引用指向子类对象(即,声明是父类,实际指向的是子类的一个对象)

5.String、StringBuffer、StringBuilder区别

1、三者在执行速度上:StringBuilder > StringBuffer > String (由于String是常量,不可改变,拼接时会重新创建新的对象)。 2、StringBuffer是线程安全的,StringBuilder是线程不安全的。(由于StringBuffer有缓冲区)

6.什么是内部类?内部类的作用

内部类:将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。 作用:1.每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整,    2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。    3.方便编写事件驱动程序    4.方便编写线程代码

7.抽象类和接口区别

相同: 1、都能被继承 2、继承的类都必须将未实现的函数实现 3、只关注方法的定义,不关注方法的实现 差异: 1、一个子类可以继承多个接口,但是只能继承一个父类 2、抽象类在对象中只能表示一种对象,接口可以被很多对象继承

8.抽象类与接口的应用场景

如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。 如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。 如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。

9.抽象类是否可以没有方法和属性?

抽象类专用于派生出子类,子类必须实现抽象类所声明的抽象方法,否则,子类仍是抽象类。 包含抽象方法的类一定是抽象类,但抽象类中的方法不一定是抽象方法。 抽象类中可以没有抽象方法,但有抽象方法的一定是抽象类。所以,java中 抽象类里面可以没有抽象方法。 抽象类的作用在于子类对其的继承和实现,也就是多态;而没有抽象方法的抽象类的存在价值在于:实例化了没有意义,因为类已经定义好了,不能改变其中的方法体,但是实例化出来的对象却满足不了要求,只有继承并重写了他的子类才能满足要求。所以才把它定义为没有抽象方法的抽象类

10.泛型中extends和super的区别

1、< extends T>限定参数类型的上界:参数类型必须是T或T的子类型 限定参数类型的下界:参数类型必须是T或T的超类型 2、 只能用于方法返回,告诉编译器此返参的类型的最小继承边界为T,T和T的父类都能接收,但是入参类型无法确定,只能接受null的传入 只能用于限定方法入参,告诉编译器入参只能是T或其子类型,而返参只能用Object类接收既不能用于入参也不能用于返参

11.父类的静态方法能否被子类重写

不能,父类的静态方法能够被子类继承,但是不能够被子类重写,即使子类中的静态方法与父类中的静态方法完全一样,也是两个完全不同的方法。

12.进程和线程的区别(问的蛮多的,回答的时候用口语说出来,不要背书)

进程是cpu资源分配的最小单位,线程是cpu调度的最小单位。 进程之间不能共享资源,而线程共享所在进程的地址空间和其它资源。 一个进程内可拥有多个线程,进程可开启进程,也可开启线程。 一个线程只能属于一个进程,线程可直接使用同进程的资源,线程依赖于进程而存在。

13.final,finally,finalize的区别

final:修饰类、成员变量和成员方法,类不可被继承,成员变量不可变,成员方法不可重写 finally:与try...catch...共同使用,确保无论是否出现异常都能被调用到 finalize:类的方法,垃圾回收之前会调用此方法,子类可以重写finalize()方法实现对资源的回收

14.Serializable 和Parcelable 的区别

Serializable Java 序列化接口 在硬盘上读写 读写过程中有大量临时变量的生成,内部执行大量的i/o操作,效率很低。

Parcelable Android 序列化接口 效率高 使用麻烦 在内存中读写(AS有相关插件 一键生成所需方法) ,对象不能保存到磁盘中。

15.静态属性和静态方法是否可以被继承?是否可以被重写?以及原因?

可继承 不可重写 而是被隐藏 如果子类里面定义了静态方法和属性,那么这时候父类的静态方法或属性称之为"隐藏"。如果你想要调用父类的静态方法和属性,直接通过父类名.方法或变量名完成。

16.成员内部类、静态内部类、局部内部类和匿名内部类的理解,以及项目中的应用

java中内部类主要分为成员内部类、局部内部类(嵌套在方法和作用域内)、匿名内部类(没构造方法)、静态内部类(static修饰的类,不能使用任何外围类的非static成员变量和方法, 不依赖外围类) 使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。 因为Java不支持多继承,支持实现多个接口。但有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。

17.string 转换成 integer的方式及原理

String —>integer Intrger.parseInt(string); Integer—> string Integer.toString(); 原理: parseInt(String s)--内部调用parseInt(s,10)(默认为10进制) 正常判断null,进制范围,length等 判断第一个字符是否是符号位 循环遍历确定每个字符的十进制值 通过*= 和-= 进行计算拼接 判断是否为负值 返回结果。

18.哪些情况下的对象会被垃圾回收机制处理掉?

1.所有实例都没有活动线程访问。 2.没有被其他任何实例访问的循环引用实例。 3.Java 中有不同的引用类型。判断实例是否符合垃圾收集的条件都依赖于它的引用类型。 要判断怎样的对象是没用的对象。这里有2种方法: 1.采用标记计数的方法: 给内存中的对象给打上标记,对象被引用一次,计数就加1,引用被释放了,计数就减一,当这个计数为0的时候,这个对象就可以被回收了。当然,这也就引发了一个问题:循环引用的对象是无法被识别出来并且被回收的。所以就有了第二种方法: 2.采用根搜索算法: 从一个根出发,搜索所有的可达对象,这样剩下的那些对象就是需要被回收的

19.静态代理和动态代理的区别,什么场景使用?

由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。动态代理类:在程序运行时,运用反射机制动态创建而成。 场景:著名的Spring框架、Hibernate框架等等都是动态代理的使用例子

20.Java的异常体系

Throwable,Error,Exception

21.谈谈你对解析与分派的认识。

解析:Java中方法调用的目标方法在Class文件里面都是常量池中的符号引用,在类加载的解析阶段,会将其中的一部分符号引用转化为直接引用。这种解析的前提是:方法在程序真正运行之前就有一个可以确定的调用版本,并且这个方法的调用版本在运行期是不可改变的,即“编译期可知,运行期不可变”,这类目标的方法的调用称为解析(Resolve)。

只要能被invokestatic和invokespecial指令调用的方法,都可以在解析阶段中确定唯一的调用版本,符合条件的有静态方法(invokestatic指令)、私有方法、实例构造方法、父类方法(这3个是invokespecial指令),它们在类加载的的解析阶段就会将符号引用解析为该方法的直接引用。 分派:分派是多态性的体现,Java虚拟机底层提供了我们开发中“重载”(Overload)“和重写”(Override)的底层实现。其中重载属于静态分派,而重写则是动态分派的过程。 解析调用一定是个静态的过程,在编译期就完全确定,在类加载的解析阶段就将涉及的符号引用全部转变为可以确定的直接引用,不会延迟到运行期再去完成。

22.Java中实现多态的机制是什么?

答:方法的重写Overriding和重载Overloading是Java多态性的不同表现 重写Overriding是父类与子类之间多态性的一种表现 重载Overloading是一个类中多态性的一种表现.

23.说说你对Java反射的理解

JAVA反射机制是在运行状态中, 对于任意一个类, 都能够知道这个类的所有属性和方法; 对于任意一个对象, 都能够调用它的任意一个方法和属性。 从对象出发,通过反射(Class类)可以取得取得类的完整信息(类名 Class类型,所在包、具有的所有方法 Method[]类型、某个方法的完整信息(包括修饰符、返回值类型、异常、参数类型)、所有属性 Field[]、某个属性的完整信息、构造器 Constructors),调用类的属性或方法自己的总结: 在运行过程中获得类、对象、方法的所有信息。

24.说说你对Java注解的理解

元注解 元注解的作用就是负责注解其他注解。java5.0的时候,定义了4个标准的meta-annotation类型,它们用来提供对其他注解的类型作说明。 1.@Target 2.@Retention 3.@Documented 4.@Inherited

由于篇幅有限,只能分享部分面试题,更多面试题及答案可以我的【Github】阅读下载哦~无偿分享给大家,算是一个感恩回馈吧

二、Android面试题(基础+进阶)(必须)

1.四大组件是什么(这个不知道的话,没必要去面试了,转行吧)

Android四大组件有Activity,Service服务,Content Provider内容提供,BroadcastReceiver。

2.四大组件的生命周期和简单用法

activity:onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDetroy()

Service: service 启动方式有两种,一种是通过startService()方式进行启动,另一种是通过bindService()方式进行启动。不同的启动方式他们的生命周期是不一样. 通过startService()这种方式启动的service,生命周期是这样:调用startService() --> onCreate()--> onStartConmon()--> onDestroy()。这种方式启动的话,需要注意一下几个问题,第一:当我们通过startService被调用以后,多次在调用startService(),onCreate()方法也只会被调用一次,而onStartConmon()会被多次调用当我们调用stopService()的时候,onDestroy()就会被调用,从而销毁服务。第二:当我们通过startService启动时候,通过intent传值,在onStartConmon()方法中获取值的时候,一定要先判断intent是否为null。

通过bindService()方式进行绑定,这种方式绑定service,生命周期走法:bindService-->onCreate()-->onBind()-->unBind()-->onDestroy() bingservice 这种方式进行启动service好处是更加便利activity中操作service,比如加入service中有几个方法,a,b ,如果要在activity中调用,在需要在activity获取ServiceConnection对象,通过ServiceConnection来获取service中内部类的类对象,然后通过这个类对象就可以调用类中的方法,当然这个类需要继承Binder对象

contentProvider:contentProvider的生命周期、理解应该跟进程一样,它作为系统应用组件、其生命周期应该跟app应用的生命周期类似,只是它属于系统应用、所以随系统启动而初始化,随系统关机而结束;但也存在其他状态下结束进程、比如说系统内存不够时,进行内存回收、会根据生成时间态、用户操作等情况进行是否内存回收。

BroadcastReceiver:广播的生命周期从调用开始到onReceiver执行完毕结束,需要注意的是,一般广播的生命周期都极短,需要在10s内处理完onReceiver中的所有工作,所以,一般不进行耗时长的工作,如果有耗时长的工作,应当通过Intent传递给Service进行处理。(注意,不要在onReceiver中开启线程进行耗时任务处理,否则,在10s后,该线程会变成空线程,从而导致任务的丢失。同样的,也不要使用bindService来绑定服务。) 值得注意的是,如果是在代码中动态注册的广播,如:在Activity注册,那么在Activity的onDestory中需要使用unregisterReceiver注销广播。

3.Activity之间的通信方式

Intent 借助类的静态变量 借助全局变量/Application 借助外部工具 借助SharedPreference 使用Android数据库SQLite 赤裸裸的使用File Android剪切板 借助Service

4.横竖屏切换的时候,Activity 各种情况下的生命周期

分两种情况: 1.不设置Activity的android:configChanges,或设置Activity的android:configChanges="orientation",或设置Activity的android:configChanges="orientation|keyboardHidden",切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行一次。 横竖屏切换造成 activity 的生命周期 onPause()-onSaveInstanceState()-onStop()-onDestroy()-onCreat()-onStart()-onRestoreInstanceState()-onResume()即会导致 activity 的销毁和重建 。

2.配置 android:configChanges="orientation|keyboardHidden|screenSize",才不会销毁 activity,且只调用 onConfigurationChanged方法。 onSaveInstanceState() 与onRestoreIntanceState() 资源相关的系统配置发生改变或者资源不足时(例如屏幕旋转),当前 Activity 会销毁,并且在 onStop 之前回调 onSaveInstanceState 保存数据,在重新创建 Activity 的时候在onStart 之后回调 onRestoreInstanceState。其中 Bundle 数据会传到 onCreate(不一定有数据)和 onRestoreInstanceState(一定有数据)。 用户或者程序员主动去销毁一个 Activity 的时候不会回调(如代码中 finish()或用户按下 back,不会回调),其他情况都会调用,来保存界面信息。

5.Activity与Fragment之间生命周期比较

a. 在创建的过程中,是 Activity 带领 Fragment 执行生命周期的方法,所以它们生命周期执行的顺序如下: Activity -- onCreate() , Fragment -- onAttach() -> onCreate() -> onCreateView() -> onActivityCreated

Activity -- onStart() Fragment -- onStart()

Activity -- onResume() Fragment -- onResume()

最后,在销毁时是 Fragment 带领 Activity 执行生命周期的方法: Fragment -- onPause() Activity -- onPause()

Fragment -- onStop() Activity -- onStop()

Fragment -- onDestroyView() -> onDestroy() -> onDetach() Activity -- onDestroy()

6.Activity上有Dialog的时候按Home键时的生命周期

有 Dialog 和 无 Dialog 按 Home 键效果一样:

正常启动: onCreate() -> onStart() -> onResume() 按 home 键: onPause() -> onStop() 再次启动: onRestart() -> onStart() -> onResume()

7.两个Activity 之间跳转时必然会执行的是哪几个方法?

a. 正常情况下 Activity A 跳转到 Activity B 时: A调用 onCreate() 方法 -> onStart() 方法 -> onResume() 方法,此时 A 前台可见。当 A 跳转到 B 时,A 调用 onPause() 方法,然后调用新的 Activity B 中的 onCreate() 方法 -> onStart() 方法 -> onResume() 方法。最后 A 再调用onStop()方法。 b. 当 Activity B 为透明主题时: 除了最后 Activity A 不调用 onStop() 方法之外,其它都和 a 中的一样。

8.Activity的四种启动模式对比

此处延伸:栈(First In Last Out)与队列(First In First Out)的区别 区别:队列先进先出,栈先进后出 对插入和删除操作的"限定"。 栈是限定只能在表的一端进行插入和删除操作的线性表。 队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。 遍历数据速度不同

standard 模式

这是默认模式,每次激活Activity时都会创建Activity实例,并放入任务栈中。使用场景:大多数Activity。

singleTop 模式

如果在任务的栈顶正好存在该Activity的实例,就重用该实例( 会调用实例的 onNewIntent() ),否则就会创建新的实例并放入栈顶,即使栈中已经存在该Activity的实例,只要不在栈顶,都会创建新的实例。使用场景如新闻类或者阅读类App的内容页面。

singleTask 模式

如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的 onNewIntent() )。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。如果栈中不存在该实例,将会创建新的实例放入栈中。使用场景如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。

singleInstance 模式

在一个新栈中创建该Activity的实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例( 会调用实例的 onNewIntent() )。其效果相当于多个应用共享一个应用,不管谁激活该 Activity 都会进入同一个应用中。使用场景如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是B。

9.Activity状态保存于恢复

当 Activity 在异常情况( 系统内存不足或者系统配置发生了改变等 )被销毁重建后, 在销毁的时候 Activity 会调用 onSaveInstanceState() 方法用于保存 Activity 相关的状态和数据,然后在重建后的 Activity 的中我们可以通过 onCreate() 或者 onRestoreInstanceState() 方法恢复数据,这里我们需要注意的是如果通过 onCreate() 方法恢复,那么得先判断它的 intent 参数 是否为空,如果在 onRestoreInstanceState() 方法恢复就不会,因为只要 onRestoreInstanceState() 方法被调用就说明一定有数据,不会为空。Google 推荐使用 onRestoreInstanceState() 方法。

10.如何实现Fragment的滑动?

将Fragment与viewpager绑定,通过viewpager中的touch事件,会进行move事件的滑动处理。

11.fragment之间传递数据的方式?

1、在fragment中设置一个方法,然后进行调用 2、采取接口回调的方式进行数据传递。 3、广播或者是使用三方开源框架:EventBus

12.Activity 怎么和Service 绑定?怎么在Activity 中启动自己对应的Service?

1、activity能进行绑定得益于Serviece的接口。为了支持Service的绑定,实现onBind方法。 2、Service和Activity的连接可以用ServiceConnection来实现。需要实现一个新的ServiceConnection,重现onServiceConnected和OnServiceDisconnected方法,一旦连接建立,就能得到Service实例的引用。 3、执行绑定,调用bindService方法,传入一个选择了要绑定的Service的Intent(显示或隐式)和一个你实现了的ServiceConnection的实例

13.service和activity怎么进行数据交互?

1.通过 broadcast:通过广播发送消息到 activitry 2.通过 Binder:通过与 activity 进行绑定 (1)添加一个继承 Binder 的内部类,并添加相应的逻辑方法。 (2)重写 Service 的 onBind 方法,返回我们刚刚定义的那个内部类实例。 (3)Activity 中创建一个 ServiceConnection 的匿名内部类,并且 重 写 里 面 的 onServiceConnected 方 法 和onServiceDisconnected 方法,这两个方法分别会在活动与服务成功绑定以及解除绑定的时候调用(在onServiceConnected方法中,我们可以得到一个刚才那个 service 的 binder 对象,通过对这个 binder 对象进行向下转型,得到我们那个自定义的 Binder 实例,有了这个实例,做可以调用这个实例里面的具体方法进行需要的操作了)。

14.Service的开启方式,请描述一下Service 的生命周期,请描述一下Service 的生命周期

service 启动方式有两种,一种是通过startService()方式进行启动,另一种是通过bindService()方式进行启动。不同的启动方式他们的生命周期是不一样. 通过startService()这种方式启动的service,生命周期是这样:调用startService() --> onCreate()--> onStartConmon()--> onDestroy()。这种方式启动的话,需要注意一下几个问题,第一:当我们通过startService被调用以后,多次在调用startService(),onCreate()方法也只会被调用一次,而onStartConmon()会被多次调用当我们调用stopService()的时候,onDestroy()就会被调用,从而销毁服务。第二:当我们通过startService启动时候,通过intent传值,在onStartConmon()方法中获取值的时候,一定要先判断intent是否为null。 通过bindService()方式进行绑定,这种方式绑定service,生命周期走法:bindService-->onCreate()-->onBind()-->unBind()-->onDestroy() bingservice 这种方式进行启动service好处是更加便利activity中操作service,比如加入service中有几个方法,a,b ,如果要在activity中调用,在需要在activity获取ServiceConnection对象,通过ServiceConnection来获取service中内部类的类对象,然后通过这个类对象就可以调用类中的方法,当然这个类需要继承Binder对象

15.请描述一下广播BroadcastReceiver的理解

广播,是一个全局的监听器,属于Android四大组件之一。Android 广播分为两个角色:广播发送者、广播接收者。作用是监听 / 接收 应用 App 发出的广播消息,并 做出响应 可应用在: Android不同组件间的通信(含 :应用内 / 不同应用之间) 多线程通信 与 Android 系统在特定情况下的通信 如:电话呼入时、网络可用时

16.Broadcast注册方式与区别 (此处延伸:什么情况下用动态注册)

Broadcast广播,注册方式主要有两种. 第一种是静态注册,也可成为常驻型广播,这种广播需要在Androidmanifest.xml中进行注册,这中方式注册的广播,不受页面生命周期的影响,即使退出了页面,也可以收到广播这种广播一般用于想开机自启动啊等等,由于这种注册的方式的广播是常驻型广播,所以会占用CPU的资源。 第二种是动态注册,而动态注册的话,是在代码中注册的,这种注册方式也叫非常驻型广播,收到生命周期的影响,退出页面后,就不会收到广播,我们通常运用在更新UI方面。这种注册方式优先级较高。最后需要解绑,否会会内存泄露 广播是分为有序广播和无序广播。

17.本地广播和全局广播有什么差别?

BroadcastReceiver是针对应用间、应用与系统间、应用内部进行通信的一种方式 LocalBroadcastReceiver仅在自己的应用内发送接收广播,也就是只有自己的应用能收到,数据更加安全广播只在这个程序里,而且效率更高。

18.BroadcastReceiver,LocalBroadcastReceiver 区别

一、应用场景不同 1、BroadcastReceiver用于应用之间的传递消息; 2、而LocalBroadcastManager用于应用内部传递消息,比broadcastReceiver更加高效。 二、使用安全性不同 1、BroadcastReceiver使用的Content API,所以本质上它是跨应用的,所以在使用它时必须要考虑到不要被别的应用滥用; 2、LocalBroadcastManager不需要考虑安全问题,因为它只在应用内部有效。

19.AlertDialog,popupWindow区别

(1)Popupwindow在显示之前一定要设置宽高,Dialog无此限制。 (2)Popupwindow默认不会响应物理键盘的back,除非显示设置了popup.setFocusable(true);而在点击back的时候,Dialog会消失。 (3)Popupwindow不会给页面其他的部分添加蒙层,而Dialog会。 (4)Popupwindow没有标题,Dialog默认有标题,可以通过dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);取消标题 (5)二者显示的时候都要设置Gravity。如果不设置,Dialog默认是Gravity.CENTER。 (6)二者都有默认的背景,都可以通过setBackgroundDrawable(new ColorDrawable(android.R.color.transparent));去掉。 最本质的区别:AlertDialog是非阻塞式对话框:AlertDialog弹出时,后台还可以做事情;而PopupWindow是阻塞式对话框:PopupWindow弹出时,程序会等待,在PopupWindow退出前,程序一直等待,只有当我们调用了dismiss方法的后,PopupWindow退出,程序才会向下执行。

20.讲解一下Context

Context是一个抽象基类。在翻译为上下文,也可以理解为环境,是提供一些程序的运行环境基础信息。Context下有两个子类,ContextWrapper是上下文功能的封装类,而ContextImpl则是上下文功能的实现类。而ContextWrapper又有三个直接的子类, ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一个带主题的封装类,而它有一个直接子类就是Activity,所以Activity和Service以及Application的Context是不一样的,只有Activity需要主题,Service不需要主题。Context一共有三种类型,分别是Application、Activity和Service。这三个类虽然分别各种承担着不同的作用,但它们都属于Context的一种,而它们具体Context的功能则是由ContextImpl类去实现的,因此在绝大多数场景下,Activity、Service和Application这三种类型的Context都是可以通用的。不过有几种场景比较特殊,比如启动Activity,还有弹出Dialog。出于安全原因的考虑,Android是不允许Activity或Dialog凭空出现的,一个Activity的启动必须要建立在另一个Activity的基础之上,也就是以此形成的返回栈。而Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog),因此在这种场景下,我们只能使用Activity类型的Context,否则将会出错。 getApplicationContext()和getApplication()方法得到的对象都是同一个application对象,只是对象的类型不一样。 Context数量 = Activity数量 + Service数量 + 1 (1为Application)

21.Android属性动画特性

(1) 对任意对象的属性执行动画操作:属性动画允许对任意对象的属性执行动画操作,因为属性动画的性质是通过反射实现的。 (2)可改变背景颜色。 (3)真正改变 View 本身:因为是通过反射改变其属性,并刷新,如改变width,他会搜索getWidth(),反射获取,再通过进行某种计算,将值通过setWidth()设置进去并更新。

22.LinearLayout、RelativeLayout、FrameLayout的特性及对比,并介绍使用场景。

RelativeLayout的onMeasure过程 根据源码我们发现RelativeLayout会根据2次排列的结果对子View各做一次measure。 首先RelativeLayout中子View的排列方式是基于彼此的依赖关系,在确定每个子View的位置的时候,需要先给所有的子View排序一下,所以需要横向纵向分别进行一次排序测量

23.LinearLayout的onMeasure过程

LinearLayout会先做一个简单横纵方向判断 需要注意的是在每次对child测量完毕后,都会调用child.getMeasuredHeight()/getMeasuredWidth()获取该子视图最终的高度,并将这个高度添加到mTotalLength中。 但是getMeasuredHeight暂时避开了lp.weight>0且高度为0子View,因为后面会将把剩余高度按weight分配给相应的子View。因此可以得出以下结论: (1)如果我们在LinearLayout中不使用weight属性,将只进行一次measure的过程。(如果使用weight属性,则遍历一次wiew测量后,再遍历一次view测量) (2)如果使用了weight属性,LinearLayout在第一次测量时获取所有子View的高度,之后再将剩余高度根据weight加到weight>0的子View上。由此可见,weight属性对性能是有影响的。 1)RelativeLayout慢于LinearLayout是因为它会让子View调用2次measure过程,而LinearLayout只需一次,但是有weight属性存在时,LinearLayout也需要两次measure。 2)在不响应层级深度的情况下,使用Linearlayout而不是RelativeLayout。

24.谈谈对接口与回调的理解

接口回调就是指: 可以把使用某一接口的类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调用被类实现的接口的方法。实际上,当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法,这一过程称为对象功能的接口回调。

25.Android中View,SurfaceView和GLSurfaceView

View:显示视图,内置画布,提供图形绘制函数,触屏事件,按键事件函数;必须在UI线程中更新画面,速度较慢。 SurfaceView:基于View视图进行拓展的视图类,更适合2D游戏的开发;是View的子类,类似双缓机制,在新的线程中更新画面,所以刷新界面速度比View快。(双缓机制:即前台缓存和后台缓存,后台缓存计算场景、产生画面,前台缓存显示后台缓存已画好的画面。) GLSurfaceView:基于SurfaceView视图再次进行扩展的视图类,专用于3D游戏开发的视图;是SurfaceView的子类,OpenGL专用。(OpenGL:是一个开放的三维图形软件包。)

26.序列化的作用,以及Android两种序列化的区别

作用:java序列化主要有2个作用: 对象持久化,对象生存在内存中,想把一个对象持久化到磁盘,必须已某种方式来组织这个对象包含的信息,这种方式就是序列化; 远程网络通信,内存中的对象不能直接进行网络传输,发送端把对象序列化成网络可传输的字节流,接收端再把字节流还原成对象。

Serializable Java 序列化接口 在硬盘上读写 读写过程中有大量临时变量的生成,内部执行大量的i/o操作,效率很低。 Parcelable Android 序列化接口 效率高 使用麻烦 在内存中读写(AS有相关插件 一键生成所需方法) ,对象不能保存到磁盘中

27.差值器和估值器

差值器: 根据时间流逝的百分比计算当前属性改变的百分比。 估值器: 根据当前属性改变的百分比计算改变后的属性值

28.Android中数据存储方式

1 使用SharedPreferences存储数据 适用范围:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。 比如应用程序的各种配置信息(如是否打开音效等),解锁口 令密码等 核心原理:保存基于XML文件存储的key-value键值对数据,通常用来存储一些简单的配置信息。

2 文件存储数据 核心原理: Context提供了两个方法来打开数据文件里的文件IO流: FileInputStream openFileInput(String name); FileOutputStream openFileOutput(String name , int mode) 3 SQLite数据库存储数据 4 使用ContentProvider存储数据 5 网络存储数据 Requestlayout,onlayout,onDraw,DrawChild区别与联系 requestLayout()方法 :会导致调用measure()过程 和 layout()过程 。 说明:只是对View树重新布局layout过程包括measure()和layout()过程,不会调用draw()过程,但不会重新绘制 任何视图包括该调用者本身。 onLayout()方法(如果该View是ViewGroup对象,需要实现该方法,对每个子视图进行布局) 调用onDraw()方法绘制视图本身 (每个View都需要重载该方法,ViewGroup不需要实现该方法) drawChild()去重新回调每个子视图的draw()方法

29.invalidate和postInvalidate的区别及使用

1、postInvalidate() 方法在非 UI 线程中调用,通知 UI 线程重绘。 2、invalidate()方法在 UI 线程中调用,重绘当前 UI。Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。

Activity-Window-View三者的差别 这个问题真的很不好回答。所以这里先来个算是比较恰当的比喻来形容下它们的关系吧。Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图)LayoutInflater像剪刀,Xml配置像窗花图纸。 1:Activity构造的时候会初始化一个Window,准确的说是PhoneWindow。 2:这个PhoneWindow有一个“ViewRoot”,这个“ViewRoot”是一个View或者说ViewGroup,是最初始的根视图。 3:“ViewRoot”通过addView方法来一个个的添加View。比如TextView,Button等 4:这些View的事件监听,是由WindowManagerService来接受消息,并且回调Activity函数。比如onClickListener,onKeyDown等。

30.ActivityThread,AMS,WMS的工作原理

Activity与Window: Activity只负责生命周期和事件处理 Window只控制视图 一个Activity包含一个Window,如果Activity没有Window,那就相当于Service。

由于篇幅原因,以上完整学习笔记pdf如有需要,可以 点赞+评论 支持下我这个“光头强”,然后点击这里免费自取