自我介绍
项目经历,重点介绍工作经历和内容
Android基础
4种启动模式和应用场;Service启动方式
Activity和Fragment如何通信?
ViewModel; 接口回调;getActivity()和FragmentManager
Android和H5如何通信?
android调用js: webview.loadurl()
js调用android: addJavascriptInterface()
Service如何增加权限
IPC进程间通信
Binder
Binder意外死亡了?
1.给Binder设置DeathRecipient监听,当Binder死亡时,我们会收到binderDied方法的回调,在binderDied方法中我们可以重连远程服务
2.在onServiceDisconnected中重连远程服务
Bundle,共享内存
Messenger
底层实现是AIDL
服务端进程:创建一个Service来处理客户端的连接请求,创建一个Handler并通过它来创建一个Messenger对象,然后在Service的onBind中返回这个Messenger对象底层Binder即可
客户端进程:绑定服务端的Service,绑定成功后用服务端的IBinder对象创建一个Messenger,通过这个Messenger就可以向服务端发送消息了,发消息类型为Message对象
AIDL, Socket,
ContentProvider
ContentProvider是Android中提供的专门用于不同应用间进行数据共享的方式,底层实现同样也是Binder; onCreate运行在main线程中,query,update,insert和delete方法运行在Binder线程中; android:authorities是Content Provider的唯一标识,通过这个属性外部应用就可以访问我们的ContentProvider;
线程间通信Handler
1.Handler工作机制
2.一个线程有几个handler,looper,如何区分不同handler发送的消息(荣耀负一屏面试题)
3.Handler如何让子线程和子线程通信? Looper#prepare(); Looper#loop()
4.Handler导致的内存泄漏如何分析解决?
5.为什么Android刷新UI只能在主线程?
因为Android的UI控件不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可预期的状态
6.子线程可以刷新UI吗?
其实是可以的,比如在Activity#onCreate方法里,在ViewRootImpl创建之前可以在子线程中操作UI;
ViewRootImpl是在Activity#onResume流程里创建,通过WindowManager.addView->WindowManagerImpl#addView->WindowManagerGlobal#addView->new ViewRootImpl
如果在子线程进行UI操作,ViewRootImpl#checkThread会抛出一个异常,only the original thread that creates a view hierarchy can touch its view只有创建View层级的线程才能操作UI
自定义View
自定义下载进度按钮
绘制背景圆形矩形,绘制进度,绘制文字,加入动画ValueAnimator,执行View.invalidate方法
自定义View,两行左对齐,一行中间对齐(华为车载面试)
View的事件体系
View的滑动;
使用scrollTo/scrollBy;使用动画;改变布局参数
弹性滑动;
使用Scroller;通过动画;使用延迟策略:使用Handler或View的postDelayed方法,线程的sleep方法
事件分发;
滑动冲突:
性能优化
1.内存优化:
- ANR (多地使用CPU资源,一般是指做大量的耗时任务,会导致手机变得卡顿甚至出现程序无法响应的情况)
当一个进程发生ANR以后,系统会在data/anr目录下常见一个文件traces.txt, 导出anr: adb pull /data/anr/traces.txt
anr分析?如果没有app堆栈信息如何分析?(荣耀负一屏面试)
结合trace.txt和Event Log/android_log主日志文件
1.anr时间点 2.主线程状态 3.问题类型
堆栈信息,内存信息和CPU负载
确认是否是系统环境影响:
整机负载:搜索ANR in关键字
低内存:内存紧张的时候,内存回收线程如kswapd,HeapTaskDaemon会变得活跃,搜索lowmemorykiller关键字,可以看到问题时间区域会有较多的查杀行为
主线程处于BLOCK(waiting to lock held by xxx,其他线程持有了锁,并尝长时间未释放,主线程等待锁超时),WAITING,TIME_WAITING状态,基本就是函数阻塞导致的anr,
若主线程无异常,则排查下CPU负载,各个进程占用CPU的详细情况,是否有其他应用抢占了CPU资源导致的ANR
如果CPU和堆栈都很正常,考虑是否内存紧张,系统日志里搜索下
am_meminfo,onTrimMemory
- OOM(过多的使用内存会导致程序内存溢出)
- 内存泄漏,
分析工具:Android Profiler和MAT,LeakCanary - 内存抖动
Android Studio Profiler:
CPU->Record Java/Kotlin Method trace ->生成trace文件->分析卡顿
Memory->Capture Heap Dump ->生成hprof文件(内存切片)->分析内存泄漏
- 布局优化:
尽量减少布局文件的层级,布局中的层级减少了,意味着Android绘制时的工作量少了
<include>标签:可以将一个指定的布局文件加载到当前的布局文件中
<merge>标签:merge标签一般和include标签一起使用从而减少布局的层级,eg:当前布局是一个竖直方向的LinearLayout,如果被包含的布局文件中也采用了竖直方向的LinearLayout, 那么显然被包含的布局文件中的LinearLayout是多余的,通过merge标签可以去掉多余的一层LinearLayout
ViewStub:按需加载所需的布局文件,eg:网络异常时的界面,这个时候没有必要在整个界面初始化的时候将其加载进来,通过ViewStub就可以做到在使用的时候再加载
- 绘制优化:
View的onDraw方法要避免执行大量的操作;onDraw中不要创建新的局部变量,因为onDraw方法可能会被频繁调用 - 内存泄漏优化:
静态变量导致的内存泄漏:持有了Activity Context
单例模式导致的内存泄漏:单例模式的特点是其生命周期和Applicaiton保持一致,如果使用了Activity,会导致Activity对象无法被及时释放
属性动画导致的内存泄漏:在onDestroy中调用animator.cancel来停止动画
2.绘制优化
Tools->Layout Inspector
卡顿分析 Perfetto和Systrace
3.启动优化
动画
View动画,帧动画和
- 属性动画
ValueAnimator,ObjectAnimator和AnimationSet,其中ObjectAnimator继承自ValueAnimator,AnimationSet是动画集合
TypeEvaluator决定了动画如何从初始值过渡到结束值
TimeInterpolator决定了动画从初始值过渡到结束值的节奏
属性动画和view动画区别?(荣耀商城面试)
图片加载
ImageLoader的实现:
1、图片压缩(BitmapFactory.Options按照一定的采样率加载缩小后的图片),内存缓存(LruCache,内部LinkedHashMap以强引用的方式存储外界的缓存对象)和磁盘缓存(DiskLruCache)
2、Glide加载图片,如果这时候按了Home键,Glide还会继续加载图片吗?
如果Glide.with传的context是Activity的context,那么Glide的生命周期和Activity是一致的;如果传的context是Application的Context,那么Glide的生命周期和应用一致;Glide内部会创建一个空白的Fragment,用来管理Glide的生命周期
Jetpack
Lifecycle
让某个类实现LifecycleObserver接口;方法添加OnLifecycleEvent注解;在Activity#onCreate中调用getLifecycle().addObserver()方法
WorkManager任务调度
Room
ViewModel+LiveData
DataBinding
其他
1.热流和冷流的区别?
热流:数据来了立即发出,不管有没有订阅者
冷流:数据准备好了,有订阅者了,才会发送数据
2.adb命令
adb shell ps | grep 包名
导出anr: adb pull /data/anr/traces.txt
adb shell pm clear 包名
adb install -r -d xxx
3.git命令
git commit; git push; git pull;
git log
git reset xxx
android gradle编译引用下载的三方aar包保存的电脑本地位置
android spannablestring设置文字圆角背景
android spannablestring实现textview不同文字大小文字居中显示
1.一个横向的LinearLayout下有两个TextView, 如果内容过长,挤压截断第一个TextView, 第二个TextView内容完全展示: LinearLayout宽度wrap_content, 第一个TextView设置width=0,layout_weight=1,lines=1,ellipsize=end
2.折叠屏旋转180度, fragment的onConfigurationChanged方法没有走,View的onConfigurationChanged方法执行了
3.自定义SpannableString, 继承RelativeSpan,实现getSize和draw方法
4.镜像语言下,文字没有右对齐,TextView需要设置android:textDirection="locale"
5.RecyclerView是指圆角矩形背景,outlineProvider, 设置clipToOutline=true;
不让RecyclerView可以自己滑动,可以重写一个类继承LinearLayoutManager,重写canScrollVertically和canScrollHorizontally设置为false