android开发1

、主要分为以下几部分:

(1)java面试题

(2)Android面试题

(3)高级开发技术面试题

(4)跨平台Hybrid 开发


一、java面试题

熟练掌握java是很关键的,大公司不仅仅要求你会使用几个api,更多的是要你熟悉源码实现原理,甚至要你知道有哪些不足,怎么改进,还有一些java有关的一些算法,设计模式等等。

(一) java基础面试知识点

java中==和equals和hashCode的区别

equals是Object的方法可以重写 ,仅仅用来判断两个对象的值

==是操作符,主要用来判断两个对象的地址

hashCode用来获取对象的哈希码,用于确定对象在哈希表中的位置。

int、char、long各占多少字节数

一个字节占8位:

char:1个字节,8位

short:2字节,16位

int:4个字节,32位

long:8个字节, 64位

int与integer的区别

int是值类型,Integer是引用类型

Integer必须实例化后才能使用,而int不需要

int默认是0,Integer默认是null

探探对java多态的理解

多态的定义:同一消息可以根据发送对象的不同而采用多种不同的行为方式

多态的好处:消除类型之间的耦合关系

多态的条件:要有继承,要有重写,父类引用指向子类对象

String、StringBuffer、StringBuilder区别

1:是否从可变的角度

String是final类既不允许继承也不允许改变对象

StringBuffer、StringBuilder 都继承AbstractStringBuilder,没有final修饰,对象可变

2、从线程安全角度来看

String因为被final修饰因此不可变,自然也就是线程安全的

StringBuffer 内部append方法添加了同步锁synchronized ,因此它也是线程安全的

StringBuilder内部append方法没有同步锁,因此它不是线程安全的

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

定义:可以把一个类定义到另一个类的内部,当作外部类的成员,这个类就叫做内部类

作用:根据内部类的分类说一下各个内部类的作用

        成员内部类:可以访问外部类的所有方法、属性、甚至包括私有方法属性。

        局部内部类:定义在某个方法或者一个作用域里面的类,只能访问该方法或者作用域里面的对象

        静态内部类:不依赖于外部类而存在,只能访问外部类的静态成员

        匿名内部类:无名内部类,常见于定义控件事件中

抽象类和接口区别

默认方法实现:抽象类可以有默认方法实现,接口没有

访问修饰符:抽象类public、protected;接口只能public

构造器:抽象类可以有构造器,接口没有

抽象类的意义

1、为子类提供一个公共的类型

2、封装子类中重复的方法和属性

3、定义有抽象方法,子类虽然有不同的实现,但该方法的定义是一致的

抽象类与接口的应用场景

如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。

如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。

如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类

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

可以

接口的意义

使用接口可以达到一定的解耦和作用,比如:我们在接口中定义一个变量,所有继承它的子类,都用到这个变量,那么当需求改变时只需要修改着一个变量即可;

解决java中不能多继承的缺点

泛型中extends和super的区别

限定参数类型的上界:参数类型必须是T或T的子类型

限定参数类型的下界:参数类型必须是T或T的超类型

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

父类的静态方法可以被子类继承,但是不能被重写

进程和线程的区别

进程是指一个执行单元,一般指一个程序或者应用

线程是cpu调度的最小单元,主要用于执行耗时操作,一个进程可以有多个线程

final,finally,finalize的区别

final:修饰符,使用final修饰的类、方法、属性不能被继承、重写和改变变量的值

finally:作为异常处理的一部分,通常配合try catch一起使用,标识最终被执行的意思

finalize:Object的一个方法,意为假定该对象被回收,什么意思呢?我们先了解一下java中垃圾回收器(GC)的工作原理,我们都知道java中的GC只回收JVM分配的内存,如果对象使用jni底层c、c++来进行分配的内存那么finalize就是负责回收这部分内存的,在GC工作时先调用finalize()方法,并在下一次垃圾回收发生,才真正回收该对象占用的内存。

Serializable 和Parcelable 的区别

                                    Serializable                                 Parcelable                   

          平台:               java自带                                        Android自带

序列化原理:               将对象转化为可存储的状态         将对象进行分解,分解的部门都是传递可支持的数据类型

       优缺点:               简单但是效率低                           高效但是使用复杂

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

可以被继承,但是不能被重写,静态属性和方法只属于当前类。通过类名.属性,类名.方法()调用

静态内部类的设计意图

非静态内部类在创建的时候会持有外部的引用,而静态内部类没有

因此非静态内部类有两个重要的作用:

1、它的创建不需要外围,不支持外部类的引用

2、静态内部类不能访问外部任何非静态属性和方法

谈谈对kotlin的理解

1、kotlin是一门静态语言,支持多种平台 移动端、服务端、以及浏览器端

2、空安全的语言,支持泛型,空指针的判断,支持与java进行完全的交互

3、代码末尾没有分号、被调用的方法放在上边等特点

闭包和局部内部类的区别

闭包是一个可调用的对象,它包含了一些信息,这些信息来自创建它的作用域,就是我们常见的lambda 表达式()=>{ 作用域 };

局部内部类是定义在某个方法或者某个局部中的类,它只能访问该方法中的变量

string 转换成 integer的方式及原理

1、循环调用string的每个字符的十进制数值

2、通过*=或/=进行计算拼接

3、最后判断是否为正负值,返回结果


(二) java深入源码级的面试题(有难度)

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

GC确定哪些对象回收有两种算法:

1、引用计数法

对象头处维护了一个引用计数去counter一个对象被引用一次计数器就会+1,不会引用就会-1,为0的时候GC工作的时候就会被回收,但是它不能解决循环引用带来的问题

2、可达性算法

java默认的垃圾回收算法,虚拟机会先将一些对象定义为 GC Roots,沿着GC Roots向下寻找,如果对象不能通过GC Roots寻找到,那么虚拟机就认为该对象是被回收的


讲一下常见编码方式?

ASCII:我理解为中文中的GB2312,使用8为二进制来表示字母和字符

UTF-8:英文一个字符一个字节,中文占用3/4字节

UTF-16:定长编码,所有字符占两个字节

utf-8编码中的中文占几个字节;int型几个字节?

中文少数占3个字节,多数占4个字节,int型数字占1个字节

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

静态代理:在程序运行前已经存在的,提前写好的。代理类和委托类的关系提前确定好的。

优点:业务只关注业务本身,专一性

缺点:代理对象只能服务一种类型的对象,代理需要新的方法,每个委托都要实现

动态代理:源码在运行期间JVM根据反射等机制动态的生成

Java的异常体系

最近在看java编程思想,根据自己编码经历,谈谈对异常的理解:

首先我们都知道java每个对象都有一个异常的超类Throwable,它由两个子类Error(错误)和Exception(异常)

Error:严重的不可处理的异常,会导致程序直接挂掉,比如内存溢出、类定义错误等

Exception:可处理异常,可以捕获并处理,比如对象空指针,文件找不到路径等

            运行时异常:时在程序运行前编译前检查语法错误来提醒

            编译时异常:主要是程序在运行后出现的逻辑错误或者内存溢出而导致的异常, 

1、除非你能解决处理异常,否则不要捕获它,如果是记录错误消息,别忘了把它在抛出去

2、异常即代表一种错误 也代表一种消息

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

多态的实现有三个必要条件:

继承:再多态中必须有继承关系的子类、父类

重写:子类重写父类中的方法,调用这些方法就会调用子类的方法

向上转型:将子类的引用赋给父类,这样可以调用父类中的方法,和父类中没有,子类中有的方法

如何将一个Java对象序列化到文件里?

FileOutputStream fileOutputStream = new FileOutputStream("d://test.out");

ObjectOutputStream objectOutputStream= new ObjectOutputStream(fileOutputStream);

objectOutputStream.writeObject("object");

objectOutputStream.close(); 

说说你对Java反射的理解

定义:反射就是程序运行时动态的获取类和对象的方法或者属性

作用:通过反射,我们可以获取相应的属性和方法或者资源,比如我们在程序中想获取第三方的资源文件,就不能通过R.id的方式获取,必须通过反射才能拿到资源文件

使用:可以通过对象.getClass()、类.class、Class.forName("")

说说你对Java注解的理解

定义:注解也称为元数据,是一种代码的级别说明,声明在包、类、字段、方法、局部变量、方法参数等前面,来对这些元素进行说明,注释等

作用:

 1)编写文档:通过代码里的标识的元数据生成文档【生成文档doc文档】

2)代码分析:通过代码里的标识的元数据对代码进行分析【使用反射】

3)编译检查:通过代码里的标识的元数据让编译器能过实现基本的编译检查

java提供了四种元注解:

1.@Target,:规定注解所修饰的对象范围

2.@Retention:表示注解的生命周期

3.@Documented:用于描述

4.@Inherited:主要说明了一种继承性,子类可以继承父类注解

说说你对依赖注入的理解

我理解的依赖注入是你不需要关心对象的生命周期,什么时候调用、销毁等过程,只需要关注,调用它的外部类即可:

代码举例说明:对象注入、属性注入

说一下泛型原理,并举例说明

泛型的本质是参数化类型,它可以用在接口,方法和类中,泛型接口、泛型方法、泛型类

比如List:

1、它的好处就是在编译时期就帮我们检查类型是否安全,不需要运行,并且所有的强转都是自动和隐士的,效率高

Java中String的了解

String为什么要设计成不可变的?

final修饰,不可被继承,不可被重写,类型安全,

Object类的equal和hashCode方法重写,为什么?

1、如果两个对象的equal相同,那么hashCode一定相同,

2、如果hashCode相同。equal并不一定相同

如果equal重写,hashCode没有被重写,可能会导致两个没有关系的对象equal相同。

(四) 线程、多线程和线程池

开启线程的三种方式?

继承Thread类,调用run()或start()方法

实现Runnable接口,调用run()方法     没有返回值,不能进行容错处理

Callable接口实现类,调用call()实现      有返回值,并且能容错处理,抛出错误信息

线程和进程的区别?

进程是程序的执行单元,一般指一个应用或程序

线程是cpu调度的最小单元,是一种有限的系统资源,分为UI线程和子线程

一个进程可以有多个线程。

为什么要有线程,而不是仅仅用进程?

进程的缺点:

    进程在同一时间只能干一件事,如果同时干多件事就无能为力

    进程在处理任务一旦遇到阻塞,当前程序就会挂起,下一步操作就无法继续进行

线程的优点:

    减少程序的响应时间,同时执行多个耗时操作,充分利用系统资源,避免闲置浪费。

run()和start()方法区别

我们首先来了解一下线程的五个状态:

创建:new Thread(new Runnable);这是线程的创建阶段,等待被执行

就绪:调用线程的start()方法,当前线程就会告知虚拟机我已准备就绪,由JVM进行调度

运行:线程会调用实现runnable的run()方法,此时线程才真正执行

阻塞:执行过程中的暂停等操作。sleep

死亡:run方法执行完毕,线程死亡

总结:start()方法只是让线程处于就绪状态,告诉cpu我已准备好了,请开始执行,然后调用run方法按顺序执行。

如何控制某个方法允许并发访问线程的个数?

java中有一个叫做信号量的类Semaphore,负责控制线程的载入、释放以及最大并发访问的个数,只需要在构造函数中传入一个最大的并发数就可以。

在Java中wait和sleep方法的不同;

sleep:睡眠,一直持有锁,事件过后任务继续执行,Thread方法

wait:等待,会释放锁,需要notify()唤醒才能继续持有,Object方法

什么导致线程阻塞?

Thread.sleep() 线程睡眠

Object.wait() 线程等待

Thread.yeild() 线程礼让

Thread.join() 线程自闭

线程如何关闭?

通常情况下线程运行完毕会自动结束,但是有时候需要提前让用户取消操作等。

1、通过退出标识,自定义一个isFlag标识,在Run方法中进行判断

2、 线程提供interrupted()方法判断线程是否已经中断来停止

讲一下java中的同步的方法

java允许多线程并发操作,在多线程并发中同时操作一个可共享的变量是容易造成数据不准确,比如数据库增删查改,java引入同步来保持数据的一致性final:变量的唯一性,不可变synchronized:作用域代码块,方法,通过线程互斥,同一时间只允许一个线程操作。Volatile:修饰变量变化保证立即对线程可见

数据一致性如何保证?

java允许多线程并发操作,在多线程并发中同时操作一个可共享的变量是容易造成数据不准确,比如数据库增删查改,java引入同步来保持数据的一致性

final:变量的唯一性,不可变

synchronized:作用域代码块,方法,通过线程互斥,同一时间只允许一个线程操作。

Volatile:修饰变量变化保证立即对线程可见

如何保证线程安全?

java中死锁和脏数据就是典型的线程安全问题,只有存在共享数据时才需要考虑线程安全问题

synchronized:作用域代码块,方法,通过线程互斥,同一时间只允许一个线程操作。Volatile:修饰变量变化保证立即对线程可见

如何实现线程同步?

三种方式:

synchronized 同步代码块,同一时间只允许一个线程操作

Lock,手动获取锁,释放锁

synchronized  通过方法。

两个进程同时要求写或者读,能不能实现?如何防止进程的同步?

线程间操作List

多线程操作list容易引起并发操作导致数据的不一致性,

Java中对象的生命周期

1.      创建阶段(Created) New一个对象,有jvm分配内存

2.      应用阶段(In Use)  至少被一个强引用持有

3.      不可见阶段(Invisible)   是指该对象不在当前作用域中被访问,编译直接报错

4.      不可达阶段(Unreachable)  不再持有,但是会被静态变量或者jni底层引用

5.      收集阶段(Collected) 

6.      终结阶段(Finalized)  对象运行完finalize()等待被回收

7.      对象空间重分配阶段(De-allocated) 对象彻底消失了

Synchronized用法

Synchronized(this){代码块}:其他想要访问此处代码时,会被阻塞

public syncchronized void method(){...} 修饰一个方法,表示其他任务访问该方法会被阻塞

synchronize的原理

Java对象头和monitor是实现synchronized的基础

对象头:通过对象头来确定对象是哪个类的实例

monitor:对象监视器,用来监视对象状态,它是一种同步机制

谈谈对Synchronized关键字,类锁,方法锁,重入锁的理解

Synchronized是同步的一种机制,主要用来解决并发访问同一对象所造成的安全问题。

Synchronized 修饰静态方法获取到的就是类锁,修饰整个类

Synchronized 修饰代码块修饰一个方法获取到的就是方法锁,修饰当前方法

冲入所:子类继承父类的方法,子类父类都有方法锁,

static synchronized 方法的多线程访问和作用

static  synchronized标识当前锁的整个类的静态方法,修饰的是整个类,也成为类锁。

作用:它可以对类的所有对象实例起作用,

同一个类里面两个synchronized方法,两个线程同时访问的问题

不能同步执行,多线程同时访问同一个类的两个synchronized方法时,jvm会检测到当前类对象前面的synchronized关键字,会对对象ID加锁,因此,两个线程同时访问,会等待一个执行完成才能执行另一个。

谈谈volatile关键字的作用

禁止指令重排,修饰变量变化立即对线程可见,线程每次使用的时候都会使用修改后的值

synchronized 和volatile 关键字的区别

synchronized 作用于方法,代码块,volatile只能修饰变量

synchronized 会造成线程阻塞,volatile不会

synchronized只要用于并发操作是保证数据的唯一性,volatile主要是变量变化时立马对其他线程可见。

synchronized与Lock的区别

synchronized 时java内置锁,Lock不是java内置

synchronized不需要用户去手动的释放锁,使用完后会自动释放,Lock需要用户手动释放,不手动释放会造成死锁现象

ReentrantLock 、synchronized和volatile比较

ReentrantLock的内部实现

lock原理

死锁的四个必要条件?

互斥:某个资源一次只能有一个进程访问,其他进程需要先等待

占有且等待,当前进程本身占有着一种资源,同时也需要其他进程正在访问的其他资源,需要等待

不可抢占:别人已经占有,不可使用

循环等待:

怎么避免死锁?

1、避免一个线程同时获取多个锁;

2、避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源

对象锁和类锁是否会互相影响?

类锁和对象锁不是同1个东西,一个是类的Class对象的锁,一个是类的实例的锁。也就是说:1个线程访问静态synchronized的时候,允许另一个线程访问对象的实例synchronized方法。反过来也是成立的,因为他们需要的锁是不同的

什么是线程池,如何使用?

线程池就是将任务添加到队列中顺序或并发执行的一个集合,android线程池一般有这几个参数:核心线程数,缓冲线程数,最大线程数

Java的并发、多线程、线程模型

谈谈对多线程的理解

优点:多线程可以处理耗时操作,方便多任务同时执行,比如网络操作,后台下载等。

缺点:线程是一种有限的系统资源,因此,需要避免大量线程的开销以及内存泄漏

多线程有什么要注意的问题?

多线程是一种有限的系统资源,大量的创建会导致资源消耗,尽量使用线程池

Android中容易引起内存泄漏:持有外部类的引用。

谈谈你对并发编程的理解并举例说明

cpu在同一时间只能处理一件事,因此并发看似是同时执行,实际上实在不停的切换进程

谈谈你对多线程同步机制的理解?

线程同步是一种安全机制,它主要是解决多线程同时访问统一资源导致的数据安全问题。

synchronized;volatile

如何保证多线程读写文件的安全?

多线程 同时访问同一个文件回导致数据安全问题,因此可以使用同步锁来解决这种问题。

可以使用synchronzied来保证在同一时间只能由一个线程来操作

断点续传原理及实现

断点续传分为单线程断点续传和多线程断点续传,

单线程断点续传:比较简单,至开启一个线程下载某一个文件起始位置是0-文件总大小,网络断开记住当前所下载的位置,下次下载重新定义http的Range

多线程断点续传:开启多个线程同时下载某个文件中的某一个部分,举例说明

实现:

不管是单线程还是多线程都要用到:

1、断点续传需要指定http的Range和Content-Rang

2、如果检测到网络断开则要记录当前下载的位置也就是Range,等待下次重新连接的时候,指定当前Range 


二、Android面试题

Android面试题包括Android基础,还有一些源码级别的、原理这些等。所以想去大公司面试,一定要多看看源码和实现方式,常用框架可以试试自己能不能手写实现一下,锻炼一下自己。

(一)Android基础知识点

四大组件是什么

Activity:Service:BoradcastReceiver:ContentProvider:

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

Activity之间的通信方式

1、通过Intent传递,大小限制1Mb

2、通过类静态变量

3、通过全局变量

4、通过SharedPreferences、文件等用的较少

Activity各种情况下的生命周期

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

横屏:onSaveInstanceState->onPause()->onStop->onDestroy()->onCreate()->onStart()->onRestoreInstanceState()->onResume()

竖屏:横屏*2

对android:configChanges属性,一般认为有以下几点:

1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次

2、设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次

3、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法 

Activity与Fragment之间生命周期比较

Activity:onCreate、onStart、onResume、onPause、onStop、onDestroy、onRestart

Fragment:

onAttach(与Activyty关联时调用)、 onCreate、onCreateView(创建Fragment视图时调用)、onActivityCreated(Activity 的Create方法调用时调用)

onStart、

onResume、

onPause、

onStop、

onDestroyView(Fragment视图被移除时调用)、onDestroy、onDetach(与Activity取消关联时调用)

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

onPause()、onStop()

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

A:onPause、B:onCreate、onStart、onResume、A:onStop

前台切换到后台,然后再回到前台,Activity生命周期回调方法。

A->B:

A:onPause、B:onCreate、onStart、onResume、A:onStop

B返回A:

B:onPause、A:onRestart、onStart、onResume、B:onStop、onDestroy

弹出Dialog,生命值周期回调方法。

A:onPause、B:onCreate、onStart、onResume

Activity的四种启动模式对比

standard:默认模式,每次都会创建一个新的页面

singleTop:栈顶模式,创建时优先检查栈顶是否存在相同的活动,有展示,没有创建

singleTask:栈内模式,创建时优先检查栈内是否存在相同的活动,有展示并清除当前活动以上所有页面,没有创建

singleInstance:单利模式,存在于单独的栈中,且只有一个实例

Activity状态保存于恢复

一般我们指的状态保存和恢复是指的非正常状态下的activity生命周期

onSaveInstanceState

onRetoreInstanceState

如何实现Fragment的滑动?

Fragment和Viewpager配合使用

给Viewpager设置setAdapter和setOnPageChangeListener即可

fragment之间传递数据的方式?

调用getFragmentManager()的findFragmentById()获取fragment对象,根据对象调用方法来实现

Activity 怎么和Service 绑定?

Activity-Intent-Service

bindService(new Intent(Activity,Service.class),)

怎么在Activity 中启动自己对应的Service?

startService(new Intent(...))

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

通过Intent进行传值

Service的开启方式 以及Service 的生命周期

startService:

startService、onCreate、onStart、service running、onStop、onDestroy

bindService、onCreate、onBind、service running,onUnBind,onDestroy

谈谈你对ContentProvider的理解

定义:

ContentProvider它是一种数据共享性组件,用户向其他组件乃至其他应用共享数据,和广播一样无法被用户感知,他内部需要实现增删查改方法,内部维护了一个数据集合,通过数据库来实现

日常开发:自定义类继承ContentProvider,实现增删查改方法,处理好线程同步,对外实现URL来实现。

说说ContentProvider、ContentResolver、ContentObserver 之间的关系

ContentProvider 内容提供者,向外提供共享数据

ContentResolver:内容解析者,对内容提供者提供的数据进行分析

ContentObserver:内容观察者,观察内容在各个阶段的状态

请描述一下广播BroadcastReceiver的理解

1、BroadcastReceiver 时一种消息型组件,在不同组件乃至不同应用之间传递消息,无法被用户感知,因为它工作在系统内部,

2、广播有两种注册方式:静态注册和动态注册。生命周期也根据注册不同

3、广播默认运行在主线程中,不支持耗时操作。

广播的分类

有序广播:消息的照发送的顺序接收

无序广播:所有设备几乎在同一时刻接收到广播

本地广播:只能在当前应用中接收到广播

粘性广播:先发送,后注册

在manifest 和代码中如何注册和使用BroadcastReceiver?

静态注册:mainfest中action

动态注册:regeisterReceiver(new MyReceiver(),filter);

广播发送的原理:

1、首先自定义一个广播接收者BroadcastRecevier,并重写onReceiver();

2、通过Binder机制像AMS进行注册;

3、广播发送者通过Binder机制向AMS发送广播;

4、AMS查找符合条件的广播,并发送到消息循环队列中;

5、消息循环拿到此广播并回调onReceiver()方法。

Application 和 Activity 的 Context 对象的区别

生命周期不同:

Application的Context代表的是整个应用程序的生命周期,Activity的Context代表的是当前Activity的生命周期。

Android属性动画工作原理

在一定时间间隔内,通过不断对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在该属性上的动画效果

如何导入外部数据库?

1、将外部数据库放到文件目录assets中,

2、通过InputStream读取外部数据库,通过FileOutputStream导入内部数据库

3、需要注意外部数据库与我们新建的数据库属性和数据类型要一致

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

RelativeLayout 会横向,纵向进行两次测量,也就是执行两次measure,效率肯定相对底

LinearLayout 线性布局,从上往下的顺序绘制元素,如果LinearLayout 有weight属性,也会执行两次measure

FrameLayout 无法控制子元素的位置,全部堆在左上角,无法改变。

谈谈对接口与回调的理解

接口的实现很简单, 

1、定义接口,编写回掉方法,给接口赋值

我们想象平时为什么需要接口

1、传值,利用接口传值,我们不关心过程只关心结果,

2、接口回调可以理解为一种设计模式,类似于观察者,程序负责项目大的时候,有利于页面之间的解耦

介绍下SurefaceView

1、SurefaceView主要在被动的情况下更新,

2、SurefaceView主要在子线程中进行,常用于平凡刷新以及刷新是数据量大的情况下

3、SurefaceView底部采用了双缓存机制,常见的视频播放。

RecycleView的使用

recyckeView.setLayoutManager(设置布局管理器,支持三种:横/纵向,流式布局,瀑布流);

recyckeView.setAdapter(设置适配源)

//也可以设置分割线、动画等

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

序列化是指将对象转化为文件存储在本地存储中的操作,主要是为了保存对象的状态

Serializable:java自带,使用简单,但是要重复读写内存,效率低

Parcelable:android自带,使用复杂,重复利用内存,效率高。

插值器

android中的插值器主要是为了实现动画的非线性需求而定义的,例如加减速等

估值器

协助插值器 实现非线性运动的动画效果

Android中数据存储方式

sharedpreferences:android提供的基于key、value保存在xml文件中的存储方式,基本数据类型等。非线程安全

文件存储:将对象采用序列化的方式保存到本地

sqlite:数据库存储

contentprovider:通过程序之间共享数据存储:

网络云存储:

(二)Android源码相关分析

invalidate和postInvalidate的区别及使用

invalidate在主线程中使用,通知UI更新View

postInvalidate在子线程中调用,通知UI更新View,底层通过Handler来通知UI更新

Activity-Window-View三者的差别

1、Activity 创建时通过attach()初始化了

2、一个 Window 一个 Window 持有一个 DecorView 的实例,DecorView 本身是一个 FrameLayout,继承于View, 3、Activty通过setContentView将xml布局控件不断addView()添加到View中,最终显示到Window于我们交互;

谈谈对Volley的理解

google推出的异步网络框架,还能加载图片,适合请求量小

使用:

1、将网络请求添加到RequestQueue中

2、RequestQueue中有两个分发器:CacheDispatch(缓存分发器)和NetworkDispatch(网络分发器),其实就是开启两个线程

3、网络请求会有优先从缓存中获取,如果缓存中没有就开启一个networkdispatch,并且将请求添加到cachediapatch中,

4、将请求结果传递到主线程。

如何优化自定义View

优化自定义view可以从两个方面考虑:

1、减少invaildate调用次数,invaildate在主线程中运行,调用它会执行view的onDraw方法,造成UI卡顿

2、requestLayout操作非常耗时,因为执行requestLayout会使android Ui系统遍历整个view层级来计算view大小

3、如果UI复杂,可以考虑使用ViewGroup,与view不同的是,自定义view仅仅测量一部分

低版本SDK如何实现高版本api?

低版本使用高版本的api最常见的是编译报错,android为开发者提供了避免编译报错的解决方案,那就是注解:

@SuppressLint(newApi)

让编译器忽略所有对新api版本的调用检查

@TargetApi(11)

让编译器忽略对特定版本的便宜检查

描述一次网络请求的流程

1、通过url找到IP

2、根据IP简历TCP连接(三次握手)

3、向服务器发送数据

4、服务器解析并返回结果

5、对结果进行处理

Bitmap对象的理解

Bitmap核心思想有三个:高效加载,缓存策略,性能优化;

高效加载:在不影响图片显示的情况下,使用采样率对图片就行高效加载;流程

   1、将BitmapFactory.Options的inJustDecodeBounds设为true并加载图片;

   2、从BitmapFactory.Options获取图片的信息,outHeight和outWidth参数

   3、根据采样率的规则结果目标view的大小,计算出inSampleSize采样率

   4、将BitmapFactory.inJustDecodeBounds设为false,然后重新加载图片

缓存策略:在实际开发中我们经常用bitmap进行图片缓存,使用缓存策略,我们不用每次都从网络下载图片,缓存策略一般是指缓存的添加、获取和删除,因此实际开发中配合LRUCache能更高效的加载图片

性能优化:bitmap加载图片所占用内存一部分来自jvm分配,另一部分来自native也就是底层分配,jvm的分配的内存有gc来回收,而native非配的内存可以由recyle()进行回收,因此如果我们当前如果确定对象不是用可以调用recyle进行释放底层分配的内存,实际上android可以不用我们调用这个方法,如果gc检测到当前bitmap没有引用,会自动释放recycle,因此手动调用也没有关系

ActivityThread,AMS,WMS的工作原理

自定义View如何考虑机型适配

合理使用warp_content,match_parent.

使用RelativeLayout 减少层级布局

尽量使用点9图片

针对不同的机型,使用不同的布局文件放在对应的目录下,android会自动匹配

自定义View的事件

一个touch事件由,down事件、move事件、up事件组成,当一个时间产生以后,系统会将这个点击事件传递到某个具体的view上,传递的顺序是activity、viewgroup、view,传递的过程中经过三个过程。

AsyncTask 工作流程?重要方法?

AsyncTask内部封装了线程池和Handler,便于执行后台任务和在子线程中更新UI

工作流程:

1、耗时操作之前准备 (Main Thread)

2、处理耗时操作 & 向主线程发送更新进度的 message(Work Thread)

3、获取进度的回调并处理 (Work Thread)

4、耗时操作结束的处理 (Main Thread)

5、(如果调用cancel),则要处理取消后的相应操作 (Main Thread)

主要涉及到的四个核心方法

onPreExecute(): 在主线程处理一些准备工作。

doInBackground(Params…params): 在子线程中处理异步耗时任务,可以通过 publishProgress 方法来更新任务的进度。

onProgressUpdate(Progress…values): 在主线程中执行,当后台任务进度改变触发回调。

onPostExecute(Result result): 在主线程中,异步任务结束触发回调,其中 result 就是后台任务的返回值。


SparseArray原理

1,SpareArray用两个数组存储key和value,保持相同索引,int数组和Object数组。key键是int基本数据类型,不需要hash计算,直接返回索引。

2,HashMap的key键必须是引用类型,SpareArray可以避免key的自动装箱,数据量不大时可以代替HashMap,更省内存。

3,采用二分查找算法获取数据value作者:光晨子链接:https://www.jianshu.com/p/3dba26007242来源:著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

请介绍下ContentProvider 是如何实现数据共享的?

1、自定义一个ContentProvider类,继承ContentProvider,

2、实现它的增删查改方法

3、在配置文件中进行注册,并未这个Contentprovider制定一个URL供外部访问/

Android Service与Activity之间通信的几种方式

1、Activity传递数据到Service,通过startService或者BinderService传递Intent传递数据通信

2、Service传递数据到Activity,通过Binder来传递

3、通过广播来传递数据,

4、通过接口回调

IntentService原理及作用是什么?

IntentService继承Service,它是一个异步自动停止的高级服务类,优先级比线程高,不容易被杀死,内部封装了可供外部使用HanderThread.

原理:内部封装了HandlerThread和Handler,

作用:因为它内部的onHandleIntent是一个异步线程,因此可以执行耗时操作,并将结果通过Handler通知给UI

SP是进程同步的吗?有什么方法做到同步?

android中进程之间不支持内存共享,每个进程访问sp都有一个单独的实例,因此多进程访问sp容易造成数据丢失,不安全等因素。

配合ContentProvider 使用

谈谈多线程在Android中的使用

android中ui线程不允许执行耗时操作,因此我们平常都来开启多线程等操作来解决网络请求,后台下载,耗时操作的问题,同时利用Handler来解决UI线程和子线程之间的通信问题,这就解决了UI更新,

asyncTask、headerThread、interService

RecycleView原理

RecyclerView拥有四级缓存:

屏幕内缓存 :指在屏幕中显示的ViewHolder,这些ViewHolder会缓存在mAttachedScrap、mChangedScrap中 。mChangedScrap表示数据已经改变的ViewHolder列表

mAttachedScrap未与RecyclerView分离的ViewHolder列表

屏幕外缓存:当列表滑动出了屏幕时,ViewHolder会被缓存在 mCachedViews,其大小由mViewCacheMax决定,默认DEFAULT_CACHE_SIZE为2,可通过Recyclerview.setItemViewCacheSize()动态设置。

自定义缓存:可以自己实现ViewCacheExtension类实现自定义缓存,可通过Recyclerview.setViewCacheExtension()设置。通常我们也不会去设置他,系统已经预先提供了两级缓存了,除非有特殊需求,比如要在调用系统的缓存池之前,返回一个特定的视图,才会用到他。

缓存池 :ViewHolder首先会缓存在mCachedViews中,当超过了2个(默认为2),就会添加到mRecyclerPool中。mRecyclerPool会根据ViewType把ViewHolder分别存储在不同的集合中,每个集合最多缓存5个ViewHolder。

(三)常见的一些原理性问题

Handler机制和底层实现

定义:负责跨线程通信,这是因为在主线程不能做耗时操作,而子线程不能更新UI,所以handle用于接收子线程的数据,配合UI线程更新界面

Handler包括Handler在内有四大要素:handler、message、messageQueue、Looper

工作机制:异步通信准备->消息入列->消息循环->消息处理

1、初始化Handler,主线程会默认创建Looper,Looper会自动创建一个MessageQueue,并开启自动循环,

2、Handler通过sendMessage/post两个方法发送消息到消息队列中。

3、Looper通过无限循环从消息队列中取出消息,并交由Handler处理,如果MessageQueue为null,当前会阻塞,不会继续执行。

4、Handler接收Looper发来的消息并处理

Handler 引起的内存泄露原因以及最佳解决方案

 泄露原因:

Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄露。 这个泄露是因为 Message 会持有 Handler,而又因为 Java 的特性,内部类会持有外部类,使得 Activity 会被 Handler 持有,这样最终就导致 Activity 泄露。

 解决方案:

 将 Handler 定义成静态的内部类,在内部持有Activity的弱引用,并在Acitivity的onDestroy()中调用handler.removeCallbacksAndMessages(null)及时移除所有消息。 

ThreadLocal原理,实现及如何保证Local属性?

ThreadLocal 不是 Thread,是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,对数据存储后,只有在线程中才可以获取到存储的数据,对于其他线程来说是无法获取到数据

请描述一下View事件传递分发机制

1、事件分发的机制就是手指触摸屏幕后所产生的一些列事件,这些事件包括:action_down、action_move、action_up

2、当一个点击事件产生以后系统会将这个点击事件传递到某个具体的view上,传递顺序是:activity、viewgroup、view

3、传递过程中有三个重要事件:

diapatchTouchEvent:

    对事件进行分发,标识是否消耗当前事件

onInterceptTouchEvent:

    在上述方法内部调用,标识当前事件事件是否被拦截;

onTouchEvent:

    在第一个方法内部调用,表示用来处理点击事件

对于一个根ViewGroup来说,当点击事件产生以后,首先会传递给它,这时它的diapatchTouchEvent就会被调用,如果这个viewgroup的onInterceptTouchEvent方法返回true,表示它要拦截当前事件,接着这个事件就会交给viewgroup处理,即它的TouchEvent方法会被调用,如果不拦截,那么事件就传递给它的子元素,接着子元素的diapatchTouchEvent就会被调用,如此反复

View和ViewGroup分别有哪些事件分发相关的回调方法

View刷新机制

在Android的View刷新机制中,父View负责刷新(invalidateChild)、布局(layoutChild)显示子View。而当子View需要刷新时,则是通知父View刷新子view来完成。

View绘制流程

View的绘制是从根节点开始,是一种自上而下的过程,分别经历测量、布局、绘制,即:measure、layout、draw

mesasure:负责确定view四个顶点的位置;

layout:确定view最终四个顶点的位置和宽高

draw:将view绘制到界面中

AsyncTask机制

 一些方法:

execute串行执行(一次只能执行一个任务)

executeOnExecutor并行执行(多个任务同时执行)

onPreExecute 运行在主线程中

doInBackground工作线程

publishProgress工作线程,通过Handler通知更新UI

工作原理: AnsycTask执行任务时,内部会创建一个进程作用域的线程池来管理要运行的任务,也就就是 说当你调用了AsyncTask.execute()后,AsyncTask会把任务交给线程池,由线程池来管理创建Thread和运行Therad。最后和UI打交道就交给Handler去处理了

接着问线程池问题:线程池可以同时执行多少个TASK

3.0以前核心线程池5个,缓冲线程池10个,最大线程池128个,面试时画图描述

AsyncTask任务是串行还是并行?

3.0以前是并行执行,3.0以后是串行执行,默认定义了一个串行调度。可以根据设置来调用串行或者并行方法。

使用AsyncTask遇到过哪些问题? 定义过AsyncTask为Activity的非静态内部类导致内存泄漏,java特性,内部类持有外部类的引用导致的。 解决办法:定义为静态内部类持有activity的弱引用

如何取消AsyncTask?

AsyncTask.cancle()

为什么不能在子线程更新UI?

android中的UI控件都是非线程安全的,子线程中并发访问可能会导致控件处于不可预期的状态

ANR产生的原因是什么?

ANR只会发生在主线程中,产生的原因主要是主线程进行了耗时操作超过固定时间得不到响应:

1、耗时的网络操作

2、界面绘制得不到相应

3、大量的数据读写操作

ANR定位和修正

ANR产生时, 系统会生成一个traces.txt的文件放在/data/anr/下. 开发人员可通过adb命令将其导出到本地 ($adb pull data/anr/traces.txt .)通过分析,我们可以根据具体的日志查看Anr原因( 如: 普通阻塞,CPU满负荷,内存泄露 )

oom是什么?

内存溢出

当一个对象分配内存,当前系统没有内存可供非配时会导致内存溢出,常见的有图片加载

什么情况导致oom?

1、图片加载过大;

2、重复创建view

3、一些常见的内存泄漏也引起内存溢出的原因之一,比如:单例、静态变量、属性动画、Handler等

有什么解决方法可以避免OOM?

1、使用bitmap的inSampleSize采样率加载大图,

2、重复创建view不仅会造成内存溢出,还会造成界面卡顿,因此重复的利用view,比如在listview中

3、规范代码编程,尽可能少使用静态变量,

Oom 是否可以try catch?为什么?

oom不能被try catch,会直接挂掉

我们都知道Java中异常超类时Throwable,Throwable派生两个子类Error和Exception,Error是不会被捕获得,Exception会被捕获,oom继承Error因此它不会被try catch

内存泄漏是什么?

内存泄漏是指当前程序申请内存,申请的内存得不到释放,这就是内存泄漏

什么情况导致内存泄漏?

1、静态变量引起的内存泄漏

2、单例引起的内存泄漏

3、属性动画引起的内存泄漏

4、handler引起的内存泄漏

如何防止线程的内存泄漏?

1、避免使用静态变量引用当前activity上下文,引文静态变量会始终常驻内存得不到释放

2、避免过多的使用单例,单例的实现也会用到static

3、属性动画中有一类无限循环的动画,如果当前页面退出要机制停止

4、Handler在进行跨线程通信中,如果在子线程中持有了外部类的引用就得不到及时释放,将handler定义为静态内部类并持有外部类的弱引用,及时执行removeCallbackAndMessage方法

Android中缓存更新策略 ?

Android的缓存策略是指缓存的添加、获取和删除这三类操作,但不管是内存缓存还是存储设备缓存,它们的缓存容量是有限制的,因此针对这种限制android为我们提供了LRU算法。

LRU的原理 ?

为减少流量消耗,可采用缓存策略。常用的缓存算法是LRU(Least Recently Used):当缓存满时, 会优先淘汰那些近期最少使用的缓存对象。主要是两种方式:

LruCache(内存缓存):LruCache类是一个线程安全的泛型类:内部采用一个LinkedHashMap以强引用的方式存储外界的缓存对象,并提供get和put方法来完成缓存的获取和添加操作,当缓存满时会移除较早使用的缓存对象,再添加新的缓存对象。

DiskLruCache(磁盘缓存): 通过将缓存对象写入文件系统从而实现缓存效果

ContentProvider的权限管理(解答:读写分离,权限控制-精确到表级,URL控制)

如何通过广播拦截和abort一条短信?

1、自定义一个SmsReceiver继承Receiver

2、重写onReciver方法,

3、在onReceiver中监听系统短信,如果监听到来了短信,判断intent.getAction()和系统的广播action是否相等,如果相等就拦截,调用abourboardCast()

广播是否可以请求网络?

不可以,广播默认执行在主线程中,不能进行耗时操作

广播引起anr的时间限制是多少?

10s

计算一个view的嵌套层级

public void getParents(ViewParent parent) {

    if (parent == null) {

    Log.w("parent", "没有啦!!!");

    return;

}

    Log.w("parent", parent.toString());

    getParents(parent.getParent());

}

Android线程有没有上限?

线程是cpu的最小执行单元,同时也是一种有线的资源,相对于系统来说,只要系统有足够的cpu资源,线程就能无限的开启

线程池有没有上限?

有,

核心线程:5个

缓冲线程:10个

最大线程:128个

Android为什么引入Parcelable?

我们来看一下android两种序列化的方式,Serializable和Parcelable

Serializable 序列化利用反射的原理,过程需要大量的I/O操作,性能低

Parcelable 原理是将对象进行分解,分解的部门都是传递可支持的数据类型,操作不需要用反射,数据也存放在 Native 内存中,效率要快很多

有没有尝试简化Parcelable的使用?

kotlin使用Parcelize注解简化Parcelable的书写

(四)开发中常见的一些问题

ListView 中图片错位的问题是如何产生的?

图片错位的问题 原因是使用了缓存,当ListView从底网上滑动的时候,当最顶部的view移出当前屏幕的时候,底部的进入的屏幕的view就复用了顶部的view,因此如果当前view数据源没有及时清空就会导致图片错位问题。

解决办法:给convertView绑定viewHolder,利用viewHodler的tag机制解决,预先给图片设置一张默认加载图,同时也减少重复创建view的问题

混合开发有了解吗?

混合开发就是在app中嵌套一个轻量级的浏览器,一部分功能采用html 5来开发,好处就是在不升级app的情况下就能实现动态更新,同时也能在其他客户端使用。

混合开发最主要的功能就是实现html5 和native的交互

mWebView.addJavascriptInterface(new JsBridge(), "bxbxbai")

知道哪些混合开发的方式?说出它们的优缺点和各自使用场景?(解答:比如:RN,weex,H5,小程序,WPA等。做Android的了解一些前- 端js等还是很有好处的);

屏幕适配的处理技巧都有哪些?

动态布局的理解

动态布局相对静态布局xml相比,它不是可视化,需要运行起来才能看见效果,但它忽略了将xml转化为布局代码,提高了效率;

动态布局使用较为灵活,但是需要技巧,需要掌握常见的集中布局的属性设置。

怎么去除重复代码?

项目越大,activity或者fragment就会越多,因此难免会有一些重复的代码,

1、设置Base(基)activity和fragment

2、采用提炼技巧,提炼方法,抽象基类,提炼常量

3、使用include减少布局重复,原理:引用其他布局,id要相同,

4、用ViewStub减少整体的布局的重复,适合整体相同,局部不同的情况

画出 Android 的大体架构图

Linux内核:

        Android是基于Linux内核开发

        Linux提供了安全、内存管理、进程管理等服务。

系统库和Android运行时:

        系统库是一个C/C++库的集合,包含OpenGL,SQlite等,在开发过程中,开发者通过框架层来调用这些库

        Android虚拟机位于Android运行时

框架层:

        框架成提供了日常开发所用的API包管理器、内容提供者等位于此层

应用程序层:

        包含了一些原生应用程序,如日历、短信等

Recycleview和ListView的区别

布局:

    Recycleview 支持横向/纵向布局、流式布局、瀑布流;ListView仅支持横向布局

点击事件:

      Recycleview不支持itemClick事件,ListView支持

动画:

        Recycleview 支持item动画,ListView不支持

ViewHolder:

        我们都知道ViewHolder是保存视图引用的类,在ListView中ViewHolder可用可不用,用需要自定义,而RecyclerView中则必须使用,RecyclerView.ViewHolder

缓存机制:ListView缓存机制是RecyclerBin,RecyclerView是Recycler和ViewHolder配合使用

动态权限适配方案,权限组的概念

我们每个程序机会都会用到用户权限,权限提醒分为,系统弹窗和自定义弹窗,自定义弹窗一般用于用户拒绝系统弹窗的提醒窗口后并不再提醒后,我们为了用户体验,自己后台检测比较人性化的一种弹窗体验。

Android系统为什么会设计ContentProvider?

如果我们项目中有需求要使用通讯录、短信等内容,假如说:我们读取内容后将内容以数据库、SP或者xml的形式保存到本地,当数据来源发生改变时,那么我们保存的内容也需要修改,这就造成了很大的关联性的问题,因此系统为开发者提供了用于不同程序之间共享数据(跨境成通信)的一种方式ContentPrivoder;

ContentProvider厉害的地方在于:

1、封装、对数据进行了封装、提供统一接口,当数据来源改变时,程序不需要做任何修改

2、提供了一种跨进程数据共享的方式

既然是对外提供数据共享,那么如何限制对方的使用呢?

答:android:exported属性非常重要 true可以交互,false不能交互,同一app组件可以使用

ContentProvider接口方法运行在哪个线程中呢?

答:配置文件中有一个叫android:multiprocess,false为单例,true为每个进程创建一个实例

ContentProvider和调用者在同一个进程,ContentProvider的增删查改方法和调用者在同一线程中;

ContentProvider和调用者在不同的进程,ContentProvider的方法会运行在它自身所在进程的一个Binder线程中。 

ContentProvider是如何在不同应用程序之间传输数据的?

答:

下拉状态栏是不是影响activity的生命周期

不会

Bitmap 使用时候注意什么?

内存溢出:

使用缓存

Bitmap的recycler()

Bitmap对象占用的内存分为两部分:JVM分配和native分配,jvm分配的由GC自动回收,native分配的执行recycler()方法才能回收,recycler()并不会立即回收掉,等待下一次GC工作之前才会被回收掉,当前目前的android版本即使不调用这个方法,系统也会自动执行recycler回收native部分内存

Android中开启摄像头的主要步骤

1、配置文件中添加权限

2、 要将摄像头捕获的图像实时地显示在手机上,使用surfaceView

3、设置窗口的显示方式

LRUCache原理

LRUCache是一个线程安全的泛型类,它内部维护了一个LinkHashMap以强引用的方式对外缓存对象,并提供get和put方法用来获取和添加缓存,它内部原理是删除掉最近最少使用的缓存,添加新的缓存。

MVC、MVP、MVVM

MVC:Model(数据模型层)、View(视图展示层)、Controller(业务逻辑层)

MVP:Model(数据模型层)、View(视图展示层)、Presenter(业务逻辑层)

MVP可以降低代码耦合度,提高代码的结构清晰度、可读性更高、复用性更强。

具体些来说(参考JessYan的例子):

现在有这么一个需求:Activity中从网络获取数据然后展示在A控件上。

如果不用MVP的话,那就直接把获取展示等代码都写在Activity中,很快便可以写完。

但现在需求变动了:

1.要求加入缓存功能,如果本地有数据,则先从本地获取数据,然后再从网络获取最新数据进行替换

2.要求数据展示在B控件上而不是A控件。

如果代码都是你自己写的,那改起来还比较轻松,但假如是团队开发,代码不是你写的,你需要花时间把逻辑重新看一遍再开始改,而且如果改错的话,会影响之前已经写好的功能。

但使用MVP模式进行开发就不同了。由于它的分工结构清晰,V层仅负责数据展示,P层仅负责业务逻辑,M层仅负责数据获取/处理。所以改动起来就轻松很多。

对于变动的需求1:我们只需在P层加入逻辑判断(先从本地获取,再网络获取),然后M层增加一个从本地获取数据方法。

对于变动的需求2:我们只需在V层修改获取到数据后的展示方式,从控件A改成控件B。

你可能感兴趣的:(android开发1)