在今年年初的疫情中,成了失业人员之一,因而各类准备面试,发现面试题网上不少,可是都是很凌乱的,并且一个地方一点,没有一个系统的面试题库,有题库有的没有答案或者是答案很简洁,没有达到面试的要求。因此一直想系统的整理一份面试题。java
最近终于得闲花了将近一个月的时间整理了一份面试题库。这些面试题,包括我本人本身去面试遇到的,还有其余人员去面试遇到的,我都统一的整理了一下,但愿对你们有用。做者不易,若有错误望见谅。android
==是运算符,用来比较两个值、两个对象的内存地址是否相等;
equals是Object类的方法,默认状况下比较两个对象是不是同一个对象,内部实现是经过“==”来实现的。
若是想比较两个对象的其余内容,则能够经过重写equals方法,
hashCoed也是Object类里面的方法,返回值是一个对象的哈希码,同一个对象哈希码必定相等,但不一样对象哈希码也有可能相等。
一、若是两个对象equals,Java运行时环境会认为他们的hashcode必定相等。
二、若是两个对象不equals,他们的hashcode有可能相等。
三、若是两个对象hashcode相等,他们不必定equals。
四、若是两个对象hashcode不相等,他们必定不equals。git
Int:4字节 chat:2字节 long\double:8字节程序员
一、Integer是int的包装类,int则是java的一种基本数据类型
二、Integer变量必须实例化后才能使用,而int变量不须要
三、Integer实际是对象的引用,当new一个Integer时,其实是生成一个指针指向此对象;而int则是直接存储数据值
四、Integer的默认值是null,int的默认值是0github
多态是指:父类引用指向子类对象,在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。(同一消息能够根据发送对象的不一样而采用多种不一样的行为方式。面试
多态的做用:消除类型之间的耦合关系。算法
实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。数据库
实现多态的三要素:继承,重写,父类引用指向子类对象(即,声明是父类,实际指向的是子类的一个对象)浏览器
一、三者在执行速度上:StringBuilder > StringBuffer > String (因为String是常量,不可改变,拼接时会从新建立新的对象)。
二、StringBuffer是线程安全的,StringBuilder是线程不安全的。(因为StringBuffer有缓冲区)缓存
内部类:将一个类定义在另外一个类里面或者一个方法里面,这样的类称为内部类。
做用:1.每一个内部类都能独立的继承一个接口的实现,因此不管外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整,
2.方便将存在必定逻辑关系的类组织在一块儿,又能够对外界隐藏。
3.方便编写事件驱动程序
4.方便编写线程代码
相同:
一、都能被继承
二、继承的类都必须将未实现的函数实现
三、只关注方法的定义,不关注方法的实现
差别:
一、一个子类能够继承多个接口,可是只能继承一个父类
二、抽象类在对象中只能表示一种对象,接口能够被不少对象继承
若是你拥有一些方法而且想让它们中的一些有默认实现,那么使用抽象类吧。
若是你想实现多重继承,那么你必须使用接口。因为Java不支持多继承,子类不可以继承多个类,但能够实现多个接口。所以你就可使用接口来解决它。
若是基本功能在不断改变,那么就须要使用抽象类。若是不断改变基本功能而且使用接口,那么就须要改变全部实现了该接口的类。
抽象类专用于派生出子类,子类必须实现抽象类所声明的抽象方法,不然,子类还是抽象类。
包含抽象方法的类必定是抽象类,但抽象类中的方法不必定是抽象方法。
抽象类中能够没有抽象方法,但有抽象方法的必定是抽象类。因此,java中 抽象类里面能够没有抽象方法。 抽象类的做用在于子类对其的继承和实现,也就是多态;而没有抽象方法的抽象类的存在价值在于:实例化了没有意义,由于类已经定义好了,不能改变其中的方法体,可是实例化出来的对象却知足不了要求,只有继承并重写了他的子类才能知足要求。因此才把它定义为没有抽象方法的抽象类
一、< extends T>限定参数类型的上界:参数类型必须是T或T的子类型
限定参数类型的下界:参数类型必须是T或T的超类型
二、 只能用于方法返回,告诉编译器此返参的类型的最小继承边界为T,T和T的父类都能接收,可是入参类型没法肯定,只能接受null的传入
只能用于限定方法入参,告诉编译器入参只能是T或其子类型,而返参只能用Object类接收既不能用于入参也不能用于返参
不能,父类的静态方法可以被子类继承,可是不可以被子类重写,即便子类中的静态方法与父类中的静态方法彻底同样,也是两个彻底不一样的方法。
进程是cpu资源分配的最小单位,线程是cpu调度的最小单位。
进程之间不能共享资源,而线程共享所在进程的地址空间和其它资源。
一个进程内可拥有多个线程,进程可开启进程,也可开启线程。
一个线程只能属于一个进程,线程可直接使用同进程的资源,线程依赖于进程而存在。
final:修饰类、成员变量和成员方法,类不可被继承,成员变量不可变,成员方法不可重写
finally:与try...catch...共同使用,确保不管是否出现异常都能被调用到
finalize:类的方法,垃圾回收以前会调用此方法,子类能够重写finalize()方法实现对资源的回收
Serializable Java 序列化接口 在硬盘上读写 读写过程当中有大量临时变量的生成,内部执行大量的i/o操做,效率很低。
Parcelable Android 序列化接口 效率高 使用麻烦 在内存中读写(AS有相关插件 一键生成所需方法) ,对象不能保存到磁盘中。
可继承 不可重写 而是被隐藏
若是子类里面定义了静态方法和属性,那么这时候父类的静态方法或属性称之为"隐藏"。若是你想要调用父类的静态方法和属性,直接经过父类名.方法或变量名完成。
java中内部类主要分为成员内部类、局部内部类(嵌套在方法和做用域内)、匿名内部类(没构造方法)、静态内部类(static修饰的类,不能使用任何外围类的非static成员变量和方法, 不依赖外围类)
使用内部类最吸引人的缘由是:每一个内部类都能独立地继承一个(接口的)实现,因此不管外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
由于Java不支持多继承,支持实现多个接口。但有时候会存在一些使用接口很难解决的问题,这个时候咱们能够利用内部类提供的、能够继承多个具体的或者抽象的类的能力来解决这些程序设计问题。能够这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。
String —>integer Intrger.parseInt(string);
Integer—> string Integer.toString();
原理:
parseInt(String s)--内部调用parseInt(s,10)(默认为10进制)
正常判断null,进制范围,length等
判断第一个字符是不是符号位
循环遍历肯定每一个字符的十进制值
经过*= 和-= 进行计算拼接
判断是否为负值 返回结果。
1.全部实例都没有活动线程访问。
2.没有被其余任何实例访问的循环引用实例。
3.Java 中有不一样的引用类型。判断实例是否符合垃圾收集的条件都依赖于它的引用类型。
要判断怎样的对象是没用的对象。这里有2种方法:
1.采用标记计数的方法:
给内存中的对象给打上标记,对象被引用一次,计数就加1,引用被释放了,计数就减一,当这个计数为0的时候,这个对象就能够被回收了。固然,这也就引起了一个问题:循环引用的对象是没法被识别出来而且被回收的。因此就有了第二种方法:
2.采用根搜索算法:
从一个根出发,搜索全部的可达对象,这样剩下的那些对象就是须要被回收的
由程序员建立或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。动态代理类:在程序运行时,运用反射机制动态建立而成。
场景:著名的Spring框架、Hibernate框架等等都是动态代理的使用例子
Throwable,Error,Exception
解析:Java中方法调用的目标方法在Class文件里面都是常量池中的符号引用,在类加载的解析阶段,会将其中的一部分符号引用转化为直接引用。这种解析的前提是:方法在程序真正运行以前就有一个能够肯定的调用版本,而且这个方法的调用版本在运行期是不可改变的,即“编译期可知,运行期不可变”,这类目标的方法的调用称为解析(Resolve)。
只要能被invokestatic和invokespecial指令调用的方法,均可以在解析阶段中肯定惟一的调用版本,符合条件的有静态方法(invokestatic指令)、私有方法、实例构造方法、父类方法(这3个是invokespecial指令),它们在类加载的的解析阶段就会将符号引用解析为该方法的直接引用。
分派:分派是多态性的体现,Java虚拟机底层提供了咱们开发中“重载”(Overload)“和重写”(Override)的底层实现。其中重载属于静态分派,而重写则是动态分派的过程。
解析调用必定是个静态的过程,在编译期就彻底肯定,在类加载的解析阶段就将涉及的符号引用所有转变为能够肯定的直接引用,不会延迟到运行期再去完成。
答:方法的重写Overriding和重载Overloading是Java多态性的不一样表现
重写Overriding是父类与子类之间多态性的一种表现
重载Overloading是一个类中多态性的一种表现.
JAVA反射机制是在运行状态中, 对于任意一个类, 都可以知道这个类的全部属性和方法; 对于任意一个对象, 都可以调用它的任意一个方法和属性。 从对象出发,经过反射(Class类)能够取得取得类的完整信息(类名 Class类型,所在包、具备的全部方法 Method[]类型、某个方法的完整信息(包括修饰符、返回值类型、异常、参数类型)、全部属性 Field[]、某个属性的完整信息、构造器 Constructors),调用类的属性或方法本身的总结: 在运行过程当中得到类、对象、方法的全部信息。
元注解
元注解的做用就是负责注解其余注解。java5.0的时候,定义了4个标准的meta-annotation类型,它们用来提供对其余注解的类型做说明。
1.@Target
2.@Retention
3.@Documented
4.@Inherited
因为篇幅有限,只能分享部分面试题,更多面试题及答案能够个人【Github】阅读下载哦~无偿分享给你们,算是一个感恩回馈吧
Android四大组件有Activity,Service服务,Content Provider内容提供,BroadcastReceiver。
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注销广播。
Intent
借助类的静态变量
借助全局变量/Application
借助外部工具
借助SharedPreference
使用Android数据库SQLite
赤裸裸的使用File
Android剪切板
借助Service
分两种状况:
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,不会回调),其余状况都会调用,来保存界面信息。
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()
有 Dialog 和 无 Dialog 按 Home 键效果同样:
正常启动: onCreate() -> onStart() -> onResume()
按 home 键: onPause() -> onStop()
再次启动: onRestart() -> onStart() -> onResume()
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 中的同样。
此处延伸:栈(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。
当 Activity 在异常状况( 系统内存不足或者系统配置发生了改变等 )被销毁重建后, 在销毁的时候 Activity 会调用 onSaveInstanceState() 方法用于保存 Activity 相关的状态和数据,而后在重建后的 Activity 的中咱们能够经过 onCreate() 或者 onRestoreInstanceState() 方法恢复数据,这里咱们须要注意的是若是经过 onCreate() 方法恢复,那么得先判断它的 intent 参数 是否为空,若是在 onRestoreInstanceState() 方法恢复就不会,由于只要 onRestoreInstanceState() 方法被调用就说明必定有数据,不会为空。Google 推荐使用 onRestoreInstanceState() 方法。
将Fragment与viewpager绑定,经过viewpager中的touch事件,会进行move事件的滑动处理。
一、在fragment中设置一个方法,而后进行调用
二、采起接口回调的方式进行数据传递。
三、广播或者是使用三方开源框架:EventBus
一、activity能进行绑定得益于Serviece的接口。为了支持Service的绑定,实现onBind方法。
二、Service和Activity的链接能够用ServiceConnection来实现。须要实现一个新的ServiceConnection,重现onServiceConnected和OnServiceDisconnected方法,一旦链接创建,就能获得Service实例的引用。
三、执行绑定,调用bindService方法,传入一个选择了要绑定的Service的Intent(显示或隐式)和一个你实现了的ServiceConnection的实例
1.经过 broadcast:经过广播发送消息到 activitry
2.经过 Binder:经过与 activity 进行绑定
(1)添加一个继承 Binder 的内部类,并添加相应的逻辑方法。
(2)重写 Service 的 onBind 方法,返回咱们刚刚定义的那个内部类实例。
(3)Activity 中建立一个 ServiceConnection 的匿名内部类,而且 重 写 里 面 的 onServiceConnected 方 法 和onServiceDisconnected 方法,这两个方法分别会在活动与服务成功绑定以及解除绑定的时候调用(在onServiceConnected方法中,咱们能够获得一个刚才那个 service 的 binder 对象,经过对这个 binder 对象进行向下转型,获得咱们那个自定义的 Binder 实例,有了这个实例,作能够调用这个实例里面的具体方法进行须要的操做了)。
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对象
广播,是一个全局的监听器,属于Android四大组件之一。Android 广播分为两个角色:广播发送者、广播接收者。做用是监听 / 接收 应用 App 发出的广播消息,并 作出响应
可应用在:
Android不一样组件间的通讯(含 :应用内 / 不一样应用之间)
多线程通讯
与 Android 系统在特定状况下的通讯
如:电话呼入时、网络可用时
Broadcast广播,注册方式主要有两种.
第一种是静态注册,也可成为常驻型广播,这种广播须要在Androidmanifest.xml中进行注册,这中方式注册的广播,不受页面生命周期的影响,即便退出了页面,也能够收到广播这种广播通常用于想开机自启动啊等等,因为这种注册的方式的广播是常驻型广播,因此会占用CPU的资源。
第二种是动态注册,而动态注册的话,是在代码中注册的,这种注册方式也叫很是驻型广播,收到生命周期的影响,退出页面后,就不会收到广播,咱们一般运用在更新UI方面。这种注册方式优先级较高。最后须要解绑,否会会内存泄露
广播是分为有序广播和无序广播。
BroadcastReceiver是针对应用间、应用与系统间、应用内部进行通讯的一种方式
LocalBroadcastReceiver仅在本身的应用内发送接收广播,也就是只有本身的应用能收到,数据更加安全广播只在这个程序里,并且效率更高。
1、应用场景不一样
一、BroadcastReceiver用于应用之间的传递消息;
二、而LocalBroadcastManager用于应用内部传递消息,比broadcastReceiver更加高效。
2、使用安全性不一样
一、BroadcastReceiver使用的Content API,因此本质上它是跨应用的,因此在使用它时必需要考虑到不要被别的应用滥用;
二、LocalBroadcastManager不须要考虑安全问题,由于它只在应用内部有效。
(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退出,程序才会向下执行。
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)
(1) 对任意对象的属性执行动画操做:属性动画容许对任意对象的属性执行动画操做,由于属性动画的性质是经过反射实现的。
(2)可改变背景颜色。
(3)真正改变 View 自己:由于是经过反射改变其属性,并刷新,如改变width,他会搜索getWidth(),反射获取,再经过进行某种计算,将值经过setWidth()设置进去并更新。
RelativeLayout的onMeasure过程
根据源码咱们发现RelativeLayout会根据2次排列的结果对子View各作一次measure。
首先RelativeLayout中子View的排列方式是基于彼此的依赖关系,在肯定每一个子View的位置的时候,须要先给全部的子View排序一下,因此须要横向纵向分别进行一次排序测量
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。
接口回调就是指: 能够把使用某一接口的类建立的对象的引用赋给该接口声明的接口变量,那么该接口变量就能够调用被类实现的接口的方法。实际上,当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法,这一过程称为对象功能的接口回调。
View:显示视图,内置画布,提供图形绘制函数,触屏事件,按键事件函数;必须在UI线程中更新画面,速度较慢。
SurfaceView:基于View视图进行拓展的视图类,更适合2D游戏的开发;是View的子类,相似双缓机制,在新的线程中更新画面,因此刷新界面速度比View快。(双缓机制:即前台缓存和后台缓存,后台缓存计算场景、产生画面,前台缓存显示后台缓存已画好的画面。)
GLSurfaceView:基于SurfaceView视图再次进行扩展的视图类,专用于3D游戏开发的视图;是SurfaceView的子类,OpenGL专用。(OpenGL:是一个开放的三维图形软件包。)
做用:java序列化主要有2个做用:
对象持久化,对象生存在内存中,想把一个对象持久化到磁盘,必须已某种方式来组织这个对象包含的信息,这种方式就是序列化;
远程网络通讯,内存中的对象不能直接进行网络传输,发送端把对象序列化成网络可传输的字节流,接收端再把字节流还原成对象。
Serializable Java 序列化接口 在硬盘上读写 读写过程当中有大量临时变量的生成,内部执行大量的i/o操做,效率很低。
Parcelable Android 序列化接口 效率高 使用麻烦 在内存中读写(AS有相关插件 一键生成所需方法) ,对象不能保存到磁盘中
差值器: 根据时间流逝的百分比计算当前属性改变的百分比。
估值器: 根据当前属性改变的百分比计算改变后的属性值
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()方法
一、postInvalidate() 方法在非 UI 线程中调用,通知 UI 线程重绘。
二、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等。
Activity与Window:
Activity只负责生命周期和事件处理
Window只控制视图
一个Activity包含一个Window,若是Activity没有Window,那就至关于Service。
因为篇幅有限,只能分享部分面试题,更多面试题及答案能够个人【Github】阅读下载哦~无偿分享给你们,算是一个感恩回馈吧