Android

2022-10-28  本文已影响0人  android小菜鸡一枚

自我介绍
项目经历,重点介绍工作经历和内容

Java

多线程和并发编程

a.线程和进程
线程:调度CPU资源的最先单位

b.线程状态
新建-》运行-》阻塞-》等待-》终止
New-》Runnable-》Blocked-》Waiting-》Timed_Waiting-》Terminated

c.wait和sleep

d.synchronized

e.volatile

f.死锁
两个线程互相等待的现象

线程池

线程复用,减少线程创建,销毁的开销,提升性能

java基础面试题

android基础面试题

进程间通信binder
线程间通信handler

原理:
子线程Hanlder#sendMessage(),将消息发送到UI线程的MessageQueue消息队列中,Looper#loop()不断轮询消息,最后Handler#dispatchMessage()
1.一个线程有几个handler,looper,如何区分不同handler发送的消息(荣耀负一屏面试题)

2.handler让子线程和子线程通信
Looper#prepare()
Looper#loop()

3.handler导致的内存泄漏如何分析解决?
分析:
当使用内部类创建handler,handler会隐式持有外部类对象,通常是一个activity引用

解决:handler#removeCallbacks(),将handler声明为静态类+activity弱应用

4.Looper#loop()死循环为什么没有阻塞主线程
android是基于事件驱动模型的
循环内部会调用nativePoolOnce的native方法,这是一个C/C++方法,利用了Linux中的管道机制epoll,在没有消息的时候会调用epoll_wait进行等待,会释放CPU, 应用会处在休眠状态

自定义View

自定义下载进度按钮
绘制背景圆形矩形,绘制进度,绘制文字,加入动画ValueAnimator,执行View.invalidate方法

View事件分发和滑动冲突

1.事件的传递顺序:
Activity->PhoneWindow->DecorView->ViewGroup->View
对于一个根ViewGroup,点击事件产生后,首先会传递给它,这时它的dispatchTouchEvent方法被调用,如果这个ViewGroup#onInterceptTouchEvent方法返回true就表示拦截当前事件,接着事件就交给这个ViewGroup处理,即它的onTouchEvent方法就会被调用,如果返回false就表示它不拦截当前事件,这时事件就会传递给它的子元素,接着子元素的dispatchTouchEvent方法就会被调用,如此反复直至事件最终被处理

2.滑动冲突
外部拦截法:
ViewGroup#onInterceptTouchEvent方法,在ACTION_MOVE中根据需要进行拦截返回true,ACTION_DOWN和ACTION_UP需要返回false
内部拦截法:
父ViewGroup#onInterceptTouchEvent方法,不拦截ACTION_DOWN返回false,其他返回true; 子View#dispatchTouchView方法,在ACTION_MOVE如果父View需要处理事件,调用parent#requestDisallowInterceptTouchEvent(false),让父容器拦截事件

性能优化

1.卡顿优化
android系统每隔16ms发送vsync垂直同步信号,对UI进行渲染,
在一个vsync到来前,新的帧并没有生成完成,只能显示上一帧的画面,这时就出现了卡顿现象,系统运算资源比较紧张;

原因:
1.层级和过渡绘制
2.内存引起:
内存抖动,gc频繁对内存进行回收,暂停其它线程,除了gc的线程, ui线程也被暂停,ui线程要求16ms进行一次更新,影响ui渲染
3.线程引起

定位:
systrace
查看UI线程状态
紫色:有大面积生产对象的代码(事件和draw)
灰色:有锁问题
蓝色:系统资源不足
橙色:有IO问题
blockcanary

2.崩溃优化
anr分析?如果没有app堆栈信息如何分析?(荣耀负一屏面试)
结合trace.txt和mainlog主日志文件
1.anr时间点 2.主线程状态 3.问题类型
堆栈信息,内存信息和CPU负载

主线程处于BLOCK,WAITING,TIME_WAITING状态,基本就是函数阻塞导致的anr,
若主线程无异常,则排查下CPU负载,是否有其他应用抢占了CPU资源导致的ANR
如果CPU和堆栈都很正常,考虑是否内存紧张,系统日志里搜索下am_meminfo,onTrimMemory

案例:

3.启动优化
4.内存优化
OOM
内存抖动
内存泄漏
内存泄漏分析?如何分析一份内存快照?
首先Android Profiler抓取内存快照,capture heap dump点击record,选择arrange by class生成hprof文件,查看到内存泄漏的是哪个activity;在platform-tools下hprof-conv.exe转换hprof文件,打开MAT,点击Histogram柱状图,搜索内存泄漏的activity, 右键排除虚软弱应用,结合堆栈和代码,可以分析activity被哪些对象引用了

Android Profiler->Memory Allocations-》Allocation Call Stack
Heap Dump->xxx.hprof

5.存储优化
6.UI渲染优化
7.图片加载优化
8.Apk瘦身

MVP,MVC,MVVM
http和https
动画

帧动画
补间动画(淡入淡出,位移,缩放,旋转)
属性动画ObjectAnimator继承自ValueAnimator
TypeEvaluator决定了动画如何从初始值过渡到结束值
TimeInterpolator决定了动画从初始值过渡到结束值的节奏

  1. android中有哪些动画?
  2. 属性动画和view动画区别?(荣耀商城面试)
android中设计模式
jetpack
kotlin
变量

属性在声明的同时需要初始化,kotlin的变量没有默认值

函数

以 fun 关键字开头
返回值写在了函数和参数后面
没有返回值,kotlin里返回Unit

对象
when (x) {
    1 -> { println("1") }
    2 -> { println("2") }
    else -> { println("else") }
}

val value: Int = when (x) {
    1 -> { x + 1 }
    2 -> { x * 2 }
    else -> { x + 5 }
}

Kotlin 中多种情况执行同一份代码时,可以将多个分支条件放在一起,用 , 符号隔开
when (x) {
    1, 2 -> print("x == 1 or x == 2")
    else -> print("else")
}

使用 in 检测是否在一个区间或者集合中
when (x) {
    in 1..10 -> print("x 在区间 1..10 中")
    in listOf(1,2) -> print("x 在集合中")
    // not in
    !in 10..20 -> print("x 不在区间 10..20 中")
    else -> print("不在任何区间上")
}

使用 is 进行特定类型的检测
val isString = when(x) {
    is String -> true
    else -> false
}

省略 when 后面的参数,每一个分支条件都可以是一个布尔表达式
when {
    str1.contains("a") -> print("字符串 str1 包含 a")
    str2.length == 3 -> print("字符串 str2 的长度为 3")
}

for:

val array = intArrayOf(1, 2, 3, 4)
for (item in array) {
    ...
}
如果左侧表达式 str?.length 结果为空,则返回右侧的值 -1
val str: String? = "Hello"
val length: Int = str?.length ?: -1
泛型

<? extends> 协变 out 只能读取不能修改,只用来输出,不用来输入,你只能读我不能写我
<? super> 逆变 in 只能修改不能读取,只用来输入,不用来输出,你只能写我不能读我

class Monster<T> where T : Animal, T : Food
协程Coroutines

协程是轻量级的线程
用同步的方式写异步的代码
闭包:当函数的最后一个参数是 lambda 表达式时,可以将 lambda 写在括号外

协程三种写法:

1.runBlocking顶层函数, 线程阻塞的
2.GlobalScope.launch
3.
val coroutineScope = CoroutineScope(context)
coroutineScope.launch {
    getImage(imageId)
}

//withContext切换到指定线程
//supend关键字
suspend fun getImage(imageId: Int) = withContext(Dispatchers.IO) {
    ...
}

4.async函数
返回的 Coroutine 实现了 Deferred 接口

启动一个协程可以使用 launch 或者 async 函数,协程其实就是这两个函数中闭包的代码块
挂起:launch ,async 或者其他函数创建的协程,在执行到某一个 suspend 函数的时候,这个协程会被「suspend」,也就是被挂起,所谓的被挂起就是切了线程,挂起就是线程调度操作

上一篇 下一篇

猜你喜欢

热点阅读