Android5月7日题: 在使用 HashMap 的时候,用 String 做 key 有什么好处?

参考答案:

HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。


Android5月8日题: 请说一说OkHttp与Retrofit 的区别与联系是怎样的?

参考答案: OkHttp和Retrofit都是目前流行网络开源框架

封装不同:

  • Retrofit封装了具体的请求,线程切换以及数据转换。
    retrofit通过使用代理,外观,策略模式对okhttp进行了封装

  • OkHttp 是基于Http协议封装的一套请求客户端

职责不同:

  • Retrofit主要负责应用层面的封装,面向开发者,方便使用,比如请求参数,响应数据的处理,错误处理等等。

  • OkHttp主要负责socket部分的优化与封装,比如网络访问,多路复用,buffer缓存,数据压缩等等。


Android5月12日题: 谈谈你认为MVVM的一些特点?

**参考答案:**双向数据绑定 在双向数据绑定模式中数据流是双向的,当业务上的数据发生改变之后,ui上的数据得到实时更新。当用户通过交互改变了数据的时候,数据的改变也能够自动更新到业务代码的数据中去。在Android中数据绑定用的是DataDinding,谷歌官网推出的实现数据和ui绑定的框架。


Android5月13日题: 解释一下 JNI中全局引用和局部引用的区别和使用

参考答案:

全局引用

通过 NewGlobalRef 和 DeleteGlobalRef 方法创建和释放一个全局引用。全局引用能在多个线程中被使用,且不会被GC 回收,只能手动释放。

局部引用

通过NewLocalRef 和 DeleteLocalRef 方法创建和释放一个局部引用。

局部引用只在创建它的native 方法中有效,包括其调用的其它函数中有效。因此我们不能寄望于将一个局部引用直接保存在全局变量中下次使用(请使用全局引用实现该需求)。

我们可以不用删除局部引用,它们会在native 方法返回时全部自动释放,但是建议对于不再使用的局部引用手动释放,避免内存过度使用。

扩展:弱全局引用

通过 NewWeakGlobalRef 和 DeleteWeakGlobalRef创建和释放一个弱全局引用。弱全局引用类似于全局引用,唯一的区别是它不会阻止被 GC 回收。


Android5月14日题: Android JetPack之Compose到底是什么?

参考答案:

是安卓原生开发过程中,未来新的一种UI视图方式了,不像以前使用五大布局方式来完成UI视图方式,而以后会是用Kotlin来写UI视图了,其实Compose非常像Flutter。


5月15日题: Android多渠道打包有几种方式,区别是什么?

参考答案:

多渠道打包方案很多,总体来说主要就两种方式,一种是使用android gradle插件提供的flavor配置不同的变体,注入渠道信息,另一种是利用APK文件构成,注入渠道信息。两种方式,前者基于官方提供的插件,功能更全面,能够配置不同的包名、图标等各种资源,但是每一个渠道包都会经历完整的打包构建流程,因此在渠道包多的情况下会很慢;后者无法根据渠道修改资源,但是不需要重打包重签名。


Android5月18日题: Java实现热修复主要有哪几种?

参考答案: Java类替换:参照Multidex原理。因为需要进行类替换,所以如果类已经被加载过了,那就不能再被修复,因此需要重启生效。(Tinker)

Java代理重定向:参照Intsnt Run 原理。对每个类中在编译为class后插入逻辑控制执行代码时是否需要重定向到补丁中的代码(美团Rubost)


Android5月19日题: ViewPager缓存的页面为什么容易导致内存泄漏?

参考答案:

ViewPager 通过setOffscreenLimit来设置缓存的页面数量,一般默认会缓存2帧数据,而如果用户设置的值越大,缓存的数据就会越多,这些缓存的数据是用ArrayList保存的,这个时候这些缓存的页面就会一直存在于内存中,所以,这样的结果就是导致内存无法释放,因此,一般情况下重写fragmentStatePagerAdapter,然后在getItem中返回你需要的fragment来解决这个内存泄漏。具体可以看https://blog.csdn.net/k_hello/article/details/82996162,亲测有效


Android5月20日题: R文件中资源的整型数分别是什么意思,例如:0x7f060003

参考答案:

  1. 0x7f060003格式是:0xpptteeee,p代表的是package,t代表的是type,e代表的是entry。

  2. Package ID 包ID,系统为0x01,应用程序资源为0x7f。

  3. Type ID 资源的类型ID,资源的类型有animator、anim、color等等,每一种都会被赋予一个ID。

  4. Entry ID 资源在其所属的资源类型中所出现的次序。


Android5月21日题: Android中主要的ClassLoader有哪些,他们分别是做什么的?

参考答案:

Android有两个主要的classloader,分别是PathClassLoader、DexClassLoader。它们都继承自于BaseDexClassLoader。PathClassLoader主要是用来加载系统类和主Dex中的类,而DexClassLoader主要是用来加载其他Dex文件的类。


Android5月22日题: 在MVP模式开发中,您是如何感知Activity或Fragment的生命周期的?

参考答案:

方法1:自己实现一个感知类,作为Activity或Fragment中的成员变量,在需要感知的其它类中传入该成员
方法2:使用Jetpack提供的Lifecycle框架实现。


Android5月25日题: 进程的回收策略是什么?

**参考答案:**Low memory killer:通过一些比较复杂的评分机制,对进程进行打分,然后将分数高的进程判定为bad进程,杀死并释放内存


Android5月29日题: CAS是什么

参考答案: CAS的全称是Compare And Swap,比较与交换,是Java保证原子性的一种重要方法,也是一种乐观锁的实现方式。

在更新值时,需要先比较当前的值是否与旧值相同,如果相同,则更新数据,否则自旋。


Android6月2日题 对象如何晋升到老年代?

参考答案 对象优先在新生代的 eden 区分配内存,但是也并不绝对,下面几种情况对象会晋升到老年代大对象直接进入老年代。比如很长的字符串,或者很大的数组等。

长期存活的对象进入老年代。在堆中分配内存的对象,其内存布局的对象头中包含了 GC 分代年龄标记信息。如果对象在 eden 区出生,那么它的 GC 分代年龄会初始值为 1,每熬过一次 Minor GC 而不被回收,这个值就会增加 1 岁。当它的年龄到达一定的数值时(默认是 15岁,cms默认为6),就会晋升到老年代中。

动态对象年龄判定。当 Survivor 空间中相同年龄所有对象的大小总和大于 Survivor 空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,而不需要达到默认的分代年龄。


Android6月3日题: Gradle构建的生命周期

参考答案: 任何Gradle的构建过程都分为三部分:初始化阶段、配置阶段和执行阶段。

1.初始化阶段的任务是创建项目的层次结构,并且为每一个项目创建一个Project实例。

2.配置阶段的任务是执行各项目下的build.gradle脚本,完成Project的配置,并且构造Task任务依赖关系图以便在执行阶段按照依赖关系执行Task。该阶段也是我们最常接触到的构建阶段,比如应用外部构建插件apply plugin: ‘com.android.application’,配置插件的属性android{ compileSdkVersion 25 …}等

3.在配置阶段结束后,Gradle会根据任务Task的依赖关系创建一个有向无环图,可以通过Gradle对象的getTaskGraph方法访问,对应的类为TaskExecutionGraph,然后通过调用gradle <任务名>执行对应任务。


Android6月4日题: OpenGL着色器是什么?

参考答案: OpenGL可编程管线技术,就是渲染管线的某些阶段可以通过编程来控制,而着色器就是这些可编程的程序片段,一段执行在GPU上的程序,使用GLSL语言来编写,用来替代原始管线的特定渲染阶段。


Android6月5日题: 您对OkHttp与Retrofit是如何理解的?

参考答案:

OkHttp和Retrofit都是目前流行网络开源框架

封装不同:

1 Retrofit封装了具体的请求,线程切换以及数据转换。

retrofit通过使用代理,外观,策略模式对okhttp进行了封装

2 OkHttp 是基于Http协议封装的一套请求客户端

职责不同:

3 Retrofit主要负责应用层面的封装,面向开发者,方便使用,比如请求参数,响应数据的处理,错误处理等等。

4 OkHttp主要负责socket部分的优化与封装,比如网络访问,多路复用,buffer缓存,数据压缩等等。

Android6月8日题: Message可以如何创建,哪种效果最好?为什么?

参考答案: 一共有3种方法:Message message = Message.obtain(); Message message = handler.obtainMessage(); Message message = new Message();需要说明的是:前两种都是从消息池中返回一个新的实例,能有效避免重复创建Message,因为Message内部采用了享元设计模式,避免了因为反复new Message而带来的内存抖动

Android6月9日题: 主线程中的Looper的轮询死循环为何没有阻塞主线程?

参考答案: 因为Android 的是由事件驱动的,looper.loop() 不断地接收事件、处理事件,每一个点击触摸或者说Activity的生命周期都是运行在 Looper.loop() 的控制之下,如果它停止了,应用也就停止了。只能是某一个消息或者说对消息的处理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它。


Android6月10日题: DNS域名解析的过程?

参考答案: 网络客户端就是我们平常使用的电脑,打开浏览器,输入一个域名。比如输入www.163.com,这时,你使用的电脑会发出一个DNS请求到本地DNS服务器。本地DNS服务器一般都是你的网络接入服务器商提供,比如中国电信,中国移动。

查询www.163.com的DNS请求到达本地DNS服务器之后,本地DNS服务器会首先查询它的缓存记录,如果缓存中有此条记录,就可以直接返回结果。如果没有,本地DNS服务器还要向DNS根服务器进行查询。

根DNS服务器没有记录具体的域名和IP地址的对应关系,而是告诉本地DNS服务器,你可以到域服务器上去继续查询,并给出域服务器的地址。

本地DNS服务器继续向域服务器发出请求,在这个例子中,请求的对象是.com域服务器。.com域服务器收到请求之后,也不会直接返回域名和IP地址的对应关系,而是告诉本地DNS服务器,你的域名的解析服务器的地址。

最后,本地DNS服务器向域名的解析服务器发出请求,这时就能收到一个域名和IP地址对应关系,本地DNS服务器不仅要把IP地址返回给用户电脑,还要把这个对应关系保存在缓存中,以备下次别的用户查询时,可以直接返回结果,加快网络访问。

Android6月11日题: 常见的屏幕适配方案有哪些?

参考答案:

  1. 使用dimens

  2. 使用谷歌的自动布局或百分比布局·

  3. 自定义适配布局文件

对于手机与平板的适配,使用Layout目录

Android6月15日题: 谈谈你对 JNIEnv 和 JavaVM 理解

参考答案:

a.JNIEnv: JNIEnv 表示 Java 调用 native 语言的环境,封装了几乎全部 JNI 方法的指针。作用有点类似与activity中的context, JNIEnv 只在创建它的线程生效,不能跨线程传递,不同线程的 JNIEnv 彼此独立。

b. JavaVM:

JavaVM 是虚拟机在 JNI 层的代表。

一个进程只有一个 JavaVM。(重要!)

所有的线程共用一个 JavaVM。(重要!)


Android6月16日题: 常用设计模式及应用场景,用两种方式实现单例模式,要求线程安全

参考答案:

常用设计模式:

单例模式: Calendar 实例的获取

适配器模式: Adapter 为 ListView GridView 等添加数据

工厂模式: Spring IOC 反转控制

代理模式: Spring AOP 面向切面编程

观察者模式: ContentObserver 监听内容改变

(懒汉式)程序执行过程中需要这个类的对象时再实例化该类的对象

步骤

  1. 定义静态私有对象

  2. 构造方法私有化保证在类的外部无法实例化该类的对象

  3. 定义对外开放的静态方法在调用方法是判断对象是否为空,为空再创建对象返回

public class Singleton {

private static Singleton singleton;

// 构造方法私有化,保证在类的外部无法实例化该类的对象

private Singleton() {

}

public static synchronized Singleton getSingletonInstance() {

if (singleton == null) {

singleton = new Singleton();

}

return singleton;

}

}

(饿汉式)类加载的时候就实例化该类的对象

public class Singleton {

private static Singleton singleton = new Singleton();

// 构造方法私有化,保证在类的外部无法实例化该类的对象

private Singleton() {

}

public static Singleton getSingletonInstance() {

return singleton;

}

}


Android6月17日题: Gradle的插件的三种打包方式是什么?

参考答案:

主要是按照复杂程度和可见性来划分:

Build script:把插件写在 build.gradle 文件中,一般用于简单的逻辑,只在该 build.gradle 文件中可见

buildSrc 项目:将插件源代码放在 rootProjectDir/buildSrc/src/main/groovy 中,只对该项目中可见,适用于逻辑较为复杂,但又不需要外部可见的插件,可以参见img-optimizer-gradle-plugin

独立项目:一个独立的 Groovy 和 Java 项目,可以把这个项目打包成 Jar 文件包,一个 Jar 文件包还可以包含多个插件入口,将文件包发布到托管平台上,供其他人使用


Android6月18日题: 如何停止一个正在运行的线程

**参考答案:**使用共享变量的方式 在这种方式中,之所以引入共享变量,

是因为该变量可以被多个执行相同任务的线程用来作为是否中断的信号,通知中断线程的执行。

使用interrupt方法终止线程 ,如果一个线程由于等待某些事件的发生而被阻塞,

比如当一个线程调用Thread.join()方法,或者Thread.sleep()方法,

在网络中调用ServerSocket.accept()方法时,都有可能导致线程阻塞,即使主程序中将该线程的共享变量设置为true,但该线程此时根本无法检查循环标志,当然也就无法立即中断。

使用Thread提供的interrupt()方法,该方法不会中断一个正在运行的线程,但是它可以使一个被阻塞的线程抛出一个中断异常,从而使线程提前结束阻塞状态,退出堵塞代码


Android6月19日题: Java实现的热修复主要有哪几种?

参考答案:

Java类替换:参照Multidex原理。因为需要进行类替换,所以如果类已经被加载过了,那就不能再被修复,因此需要重启生效。(Tinker)

Java代理重定向:参照Intsnt Run 原理。对每个类中在编译为class后插入逻辑控制执行代码时是否需要重定向到补丁中的代码(美团Rubost)


Android6月22日题: 如何设计一个日志模块?

参考答案:

一个优秀的日志模块必须做到:
1、不能把用户的隐私信息打印到日志文件里,不能把日志明文打到日志文件里。
2、不能影响程序的性能。最基本的保证是使用了日志不会导致程序卡顿。
3、不能因为程序被系统杀掉,或者发生了 crash,crash 捕捉模块没有捕捉到导致部分时间点没有日志, 要保证程序整个生命周期内都有日志。
4、不能因为部分数据损坏就影响了整个日志文件,应该最小化数据损坏对日志文件的影响。

如果可以通过引入 mmap 既能保证高性能又能保证高可靠性,对于需要记录的数据先压缩再加密既可以保护隐私也能减少所占用的 mmap 的大小,进而减少 mmap 所占用内存的大小。


Android6月23日题: 怎么定位 NDK 中的问题

参考答案:

一般在开发阶段的话,我们可以通过log 来定位和分析问题。

如果是上线状态(即关闭了基本的log),我们可以借助 NDK 提供的 addr2line 工具和

objdump工具来定位错误。详情:

so动态库崩溃问题定位(addr2line与objdump),详细使用参考 链接

其它还可以使用 C/C++ 的一些分析工具。


Android6月24日题: 简述Activity的启动流程

参考答案: Activity的启动过程,我们可以从Context的startActivity说起,其实现是ContextImpl的startActivity,然后内部会通过Instrumentation来尝试启动Activity,它会调用ams的startActivity方法,这是一个跨进程过程,当ams校验完activity的合法性后,会通过ApplicationThread回调到我们的进程,这也是一次跨进程过程,而applicationThread就是一个binder,回调逻辑是在binder线程池中完成的,所以需要通过Handler H将其切换到ui线程,第一个消息是LAUNCH_ACTIVITY,它对应handleLaunchActivity,在这个方法里完成了Activity的创建和启动。


转载自 安卓2020年5月每日一题

转载自 安卓2020年6月每日一题

更多相关文章

  1. android 兼容API的检查
  2. 【Android】下拉刷新实现
  3. android AsyncTask使用总结
  4. 将Android通讯录导入iphone的方法
  5. Android中AsyncTask(异步执行任务)的使用
  6. IntelliJ IDEA Export to Eclipse Android工程不能正常被Eclipse
  7. Android(安卓)TextView 展开动画
  8. AIDL基本用法
  9. Android与服务器通信的方法之一(json)效率不高安全性不好

随机推荐

  1. 关于Go SQL中的Query、Exec和Prepare使用
  2. 教你使用Golang和lua实现一个值班机器人
  3. gin框架有什么优势
  4. windows10下编译go项目为linux可执行文件
  5. 分享一些为PHPer准备的Go入门知识
  6. 关于 golang 的接口介绍
  7. 教你使用golang实现redis服务器
  8. 分享Go命名规范小记
  9. go语言grpc环境搭建的方法详解
  10. 关于Golang GC 垃圾回收机制的详解