
Android - app - 面试题 架构 (mvvm 常见架构区别livedata/databinding四大组件 acitivity两种启动方式区别应用场景例子四种启动模式区别应用场景 java版flag模拟实现四种启动模式例子常用10种 FLAG 区别与应用场景例子taskAffinity应用场景及例子acitivity传参(Intent/BundleParcelable/Serializable 区别应用场景传大数据单例共享缓存 /ViewModel/LiveData/EventBus/ 文件 / 数据 / 共享内存等方式区别应用场景例子)Frament(概述打开跳转等例子场景问题)acitivity 和 Fragment (生命周期)其他组件 (ViewPagerScrollViewRecyclerViewsurfaceview 等组件常见问题及解决方法)布局 (相对布局约束布局动态布局等区别应用场景常见问题)view 刷新 (常见问题)自定义 view (流程常见问题)事件 (常见问题)图片 (例子常见问题为啥要手动回收)弹窗 (toast,dialogdialogFragment, 悬浮窗等区别应用场景例子常见问题及解决方法)弹窗类型windowType概述例子常见问题handler (原理主线程和子线程实现例子复用例子常见问题及解决方法)倒计时器(例子)多线程 (多线程线程安全线程休眠等各种实现方式区别应用场景例子常见问题)数据持久化 (sp,sqllite各种实现方式区别应用场景例子常见问题)aidl (原理,和socket区别客户端监听服务端die和服务端监听客户端die例子常见问题及解决方法)网络 (常见问题)gc (内存架构gc原理gc日志常见问题)adb 常见调试命令(看cpu,memiowindowaudio,wifi等)性能优化大全(ui后台内存cpu iobinder启动耗时丢帧卡顿 等分析解决方法), 稳定性分析优化 大全anr/java和native的crash/内存泄漏等分析解决方法单例 (静态内部类优点)设计模式 (区别应用场景)还有其他问题Android中高级APP面试题库完整版‑Java含考点代码坑点一、架构 MVC‑MVP‑MVVM、LiveData、DataBinding1、三种架构对比MVCM‑Model(数据层)、V‑View(布局)、C‑Controller一般由Activity/Fragment充当控制器缺点Activity业务逻辑与UI代码高度耦合、代码臃肿单元测试困难适用场景简单老旧项目新项目不推荐MVPM‑ModelV‑View接口Activity实现P‑Presenter中间人缺点Presenter双向持有View引用页面销毁极易内存泄漏接口数量爆炸适用场景遗留老项目维护逐步迁移MVVMMVVMJetpack主流M‑数据源V‑Activity/FragmentVM‑ViewModelViewModel不持有View强引用依靠LiveData实现数据驱动UI、单向数据流优点UI与业务解耦、屏幕旋转数据自动保留、生命周期安全、便于单元测试适用场景绝大多数新项目2、LiveData生命周期感知宿主处于STARTED/RESUMED活跃状态才下发数据页面销毁自动解绑天然防泄漏黏性数据新观察者可收到历史缓存数据事件场景会重复回调解决方案SingleLiveEvent、一次性Event包装类默认主线程回调不能跨进程通信3、DataBinding编译期自动生成绑定类实现xml布局绑定Java对象单向绑定{data}双向绑定{data}LiveData 可观察数据容器DataBinding 视图绑定工具二者经常搭配使用互不替代坑点双向绑定循环调用、空指针、layout标签编译报错二、Activity1、两种启动方式显式启动直接指定目标Activity类Intent intentnew Intent(this,TestActivity.class); startActivity(intent);场景APP内部页面跳转优先推荐2.隐式启动通过action、category、data匹配目标页面不写类名Intent intentnew Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(https://www.baidu.com)); startActivity(intent);场景跳转系统页面、调用第三方APP需要配置清单intent‑filter2、四种启动模式启动模式行为典型业务场景standard每次打开都新建实例任务栈跟随启动方商品详情、资讯页面singleTop栈顶已有目标Activity就复用回调onNewIntent()不新建首页防止双击重复打开页面singleTask栈内存在实例则清除它上层所有Activity目标页面回到栈顶回调onNewIntent()登录页、主页登录成功清栈回到首页singleInstance全局唯一实例独占一个独立任务栈来电界面、闹钟弹窗⚠️ FLAG无法完全模拟singleInstance只能在AndroidManifest清单配置。3、FLAG模拟启动模式代码示例//1、模拟 singleTop Intent intentnew Intent(this,TestActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); startActivity(intent); //2、模拟 singleTask intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); //3、模拟 singleInstance无法100%复现仅新开任务栈 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent);singleInstance 只能清单配置android:launchModesingleInstance4、10个高频FLAG详解FLAG_ACTIVITY_NEW_TASK开启新任务栈子线程启动Activity必须添加该标记FLAG_ACTIVITY_CLEAR_TOP清除目标页面上方所有Activity实例FLAG_ACTIVITY_SINGLE_TOP栈顶复用FLAG_ACTIVITY_NO_HISTORY页面不入任务栈返回键直接跳过该页面FLAG_ACTIVITY_CLEAR_TASK清空整个任务栈必须配合NEW_TASK一起使用FLAG_ACTIVITY_REORDER_TO_FRONT栈内已有页面挪至栈顶不清上层页面FLAG_ACTIVITY_FORWARD_RESULT传递Activity返回结果给下一页FLAG_ACTIVITY_PREVIOUS_IS_TOP标记上一个Activity作为栈顶FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS页面不在最近任务列表显示FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY从最近任务列表唤起页面5、taskAffinityandroid:taskAffinitycom.xxx.task默认值等于应用包名生效条件singleTaskFLAG_ACTIVITY_NEW_TASK使用例子推送跳转首页返回键不回到APP首页独立业务进程页面坑点会开启全新任务栈返回栈逻辑混乱6、Parcelable vs SerializableSerializableJava原生序列化性能较差适合持久化存储少量数据ParcelableAndroid内存序列化速度快仅用于Intent内存传递不能存磁盘Binder缓冲区上限1MB大数据抛出TransactionTooLargeException7、大数据传递方案对比方案优点缺点适用场景例子单例静态缓存速度快代码简单易内存泄漏进程重启丢失临时传递大图对象ViewModelLiveData生命周期安全无泄漏仅限同一个Activity内部Activity‑Fragment通信EventBus跨组件解耦无生命周期感知易泄漏全局小事件通知本地临时文件无大小上限IO开销用完需要手动清理视频、大图文件传递共享内存‑NDK零拷贝高性能开发复杂、需要JNI跨进程音视频数据流三、Fragment1、概述Fragment依附于Activity拥有独立生命周期模块化UI组件一个Activity可以承载多个Fragment。2、打开添加例子xml静态添加fragment android:idid/fragment android:namecom.demo.HomeFragment/代码动态添加推荐HomeFragment fragmentnew HomeFragment(); getSupportFragmentManager().beginTransaction() .add(R.id.container,fragment,home) .commit();3、跳转切换例子replace销毁重建Fragment适合低频页面切换getSupportFragmentManager().beginTransaction() .replace(R.id.container,new MineFragment()).commit();add‑hide‑show实例常驻内存底部导航首选保存页面状态transaction.hide(homeFragment).show(mineFragment).commit();addToBackStack(null)加入回退栈返回键回到上一个Fragment4、高频场景坑点commit()在onSaveInstanceState后调用崩溃 →commitAllowingStateLoss()允许丢失状态屏幕旋转Fragment重叠判断savedInstanceStatenull才新建FragmentgetActivity()空指针异步回调Fragment已经解绑宿主使用getContext()判空setUserVisibleHint()已废弃新版懒加载方案使用setMaxLifecycle四、Activity Fragment生命周期Activity完整生命周期onCreate→onStart→onResume(前台交互) →onPause→onStop→onDestroy后台切回前台重启路径onRestart→onStart→onResume默认配置屏幕旋转Activity销毁重建Fragment完整生命周期onAttach→onCreate→onCreateView→onViewCreated→onStart→onResume→onPause→onStop→onDestroyView→onDestroy→onDetach重点考点hide/show不会触发onPause/onResume五、UI组件ViewPager、ScrollView、RecyclerView、SurfaceViewRecyclerView1.卡顿onBindViewHolder耗时、大图加载解决异步加载图片、DiffUtil局部刷新2.ScrollView嵌套RecyclerView高度wrap‑content失效、滑动冲突3.notifyDataSetChanged()全局刷新造成item闪烁 → DiffUtil局部刷新4.嵌套RecyclerView卡顿recyclerView.setNestedScrollingEnabled(false)ScrollView只能包含一个直接子View嵌套列表极易出现滑动冲突ViewPager / ViewPager2‑ViewPager默认预加载左右两侧Fragment懒加载难以控制‑ViewPager2底层RecyclerView实现真正懒加载支持横竖双向滑动新项目优先选用SurfaceView-原理拥有独立绘图缓冲区子线程绘制画面不会阻塞UI主线程-场景例子视频播放器、相机预览、游戏画面、车载视频画面SurfaceView svfindViewById(R.id.sv); sv.getHolder().addCallback(new SurfaceHolder.Callback(){ Override public void surfaceCreated(SurfaceHolder holder) { //开启绘制子线程 } Override public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {} Override public void surfaceDestroyed(SurfaceHolder holder) { //停止绘制线程释放资源 } });坑点Surface销毁绘制线程未停止造成死循环崩溃锁屏切后台Surface被销毁实现透明效果需要setZOrderOnTop(true)六、布局相对布局、约束布局、动态布局RelativeLayout相对布局两次测量性能较差新项目逐步淘汰适合简单控件依赖布局ConstraintLayout约束布局扁平化单层布局减少布局嵌套复杂页面首选性能优秀动态布局addViewLayoutParams类型必须和父布局一致否则布局失效七、View刷新机制invalidate()主线程调用仅执行onDraw不走onMeasure、onLayoutrequestLayout()触发完整测量‑布局‑绘制onMeasure‑onLayout‑onDraw宽高、位置变化调用postInvalidate()子线程刷新View坑点频繁调用invalidate引发过度绘制View还未添加到Window刷新无效八、自定义View绘制流程构造函数xml布局加载走第二个构造onMeasure测量控件宽高onLayout摆放子View仅ViewGrouponDrawCanvas绘制图形onTouchEvent接收触摸事件###常见坑wrap_content不生效需要手动测量宽高padding失效绘制内容留出padding边距动画未cancel页面销毁内存泄漏部分Canvas绘图API不支持硬件加速九、事件分发传递顺序Activity.dispatchTouchEvent→ViewGroup.dispatchTouchEvent→onInterceptTouchEvent(拦截)→子View.dispatchTouchEvent→onTouchEvent‑return true消费事件终止事件向下传递‑return false事件向上冒泡滑动冲突两种解决方案1.外部拦截父ViewGroup重写onInterceptTouchEvent2.内部拦截子View调用requestDisallowInterceptTouchEvent(true)禁止父布局拦截事件十、图片‑Bitmap-Android 8.0以前像素数据放在Native堆8.0像素数据放到Java堆‑recycle()作用主动释放Native内存Glide等图片框架自动管理Bitmap不要手动recycle自己new创建的Bitmap建议手动回收防止Native内存泄漏‑OOM解决方案例子采样压缩、inBitmap内存复用、三级缓存十一、弹窗Toast、Dialog、DialogFragment、悬浮窗1.Toast系统弹窗Android11后后台不能弹出Toast连续弹出排队延时2.Dialog依附ActivityActivity销毁未dismiss弹窗引发崩溃生命周期不安全3.DialogFragment弹窗首选方案屏幕旋转弹窗不会消失生命周期安全4.悬浮窗WindowManager.addView需要悬浮窗权限Android8.0后窗口类型强制改为TYPE_APPLICATION_OVERLAYWindowType窗口类型‑TYPE_APPLICATION普通APP窗口依附Activity‑TYPE_APPLICATION_DIALOG对话框窗口‑TYPE_APPLICATION_OVERLAY新版悬浮窗坑点Activity销毁弹窗Token失效直接崩溃十二、Handler###原理四大组件Handler、Message、MessageQueue、Looper‑Looper线程唯一loop()死循环阻塞读取消息‑MessageQueue消息队列存放Message‑Handler发送消息、处理回调消息###主线程示例Handler handlernew Handler(Looper.getMainLooper()); handler.post(()-{ //更新UI操作 });###子线程创建Looper完整例子new Thread(){ Override public void run() { Looper.prepare(); Handler handlernew Handler(Looper.myLooper()); Looper.loop(); } }.start(); Thread mThread new Thread(); mThread.start(); Handler mHandlernew Handler(mThread.myLooper());###防内存泄漏写法静态Handler弱引用static class MyHandler extends Handler{ WeakReferenceMainActivity ref; MyHandler(MainActivity activity){ refnew WeakReference(activity); } Override public void handleMessage(NonNull Message msg) { MainActivity activityref.get(); if(activity!null){ //业务代码 } } }坑点非静态Handler持有Activity延时消息引发内存泄漏子线程默认没有Looper不能直接new Handler十三、CountDownTimer倒计时例子new CountDownTimer(5000,1000){ Override public void onTick(long millisUntilFinished) { Log.d(cd,剩余millisUntilFinished/1000); } Override public void onFinish() { Log.d(cd,倒计时结束); } }.start();坑点后台计时不准页面销毁调用cancel()防止内存泄漏十四、多线程、线程安全、线程休眠###多线程实现方式对比1.Thread/Runnable简单一次性任务频繁创建销毁开销大2.ThreadPoolExecutor线程池线程复用并发任务首选方案3.AsyncTask已经废弃极易产生生命周期泄漏4.HandlerpostDelayed主线程延时任务5.RxJava链式异步任务6.Kotlin协程轻量级异步方案新项目推荐###线程休眠代码例子try{ Thread.sleep(2000); //休眠2秒**不会释放锁** }catch (InterruptedException e){ e.printStackTrace(); }sleep()‑Thread静态方法wait()‑Object方法调用wait释放锁###线程安全方案对比1.synchronized悲观锁保证原子性、可见性、有序性阻塞性能较差2.volatile仅保证可见性不保证原子性适合布尔标记位场景3.ReentrantLock显式锁支持公平/非公平锁手动加锁解锁4.AtomicXXX原子类CAS无锁适合简单计数高并发场景存在ABA问题###常见坑嵌套锁顺序不一致引发死锁子线程更新UI直接崩溃线程未关闭造成内存泄漏十五、数据持久化‑SP、SQLite、Room1.SharedPreferences轻量xml键‑值存储apply()异步提交commit()同步阻塞主线程禁止存储大数据多次apply偶发丢失数据2.SQLite本地关系数据库适合大量结构化本地数据原生手写SQL繁琐3.RoomJetpack封装SQLite的ORM框架编译期校验SQL语法官方推荐十六、AIDL跨进程通信###原理基于Binder实现Android跨进程通信###Binder vs Socket‑Binder一次内存拷贝仅限本机进程通信高性能Android专属IPC方案‑SocketTCP/IP通信两次拷贝支持跨设备网络通信开销较大###客户端监听服务端死亡代码示例IBinder.DeathRecipient recipientnew IBinder.DeathRecipient(){ Override public void binderDied() { //服务端死亡回调释放资源、开启重连逻辑 } }; mBinder.linkToDeath(recipient,0);Android没有原生API监听客户端死亡解决方案例子客户端定时心跳上报服务端超时判定客户端断开连接###AIDL坑点远程调用放在主线程超时引发ANRoneway关键字实现异步调用跨进程传递对象必须实现Parcelable序列化十七、网络高频问题1.主线程禁止发起网络请求2.Android9.0默认禁止明文HTTP清单配置cleartextTrafficPermitted开启3.OkHttp连接池复用、拦截器、超时重试、熔断策略4.HTTPS证书校验、证书锁定、双向认证5.离线缓存策略十八、 ART内存架构GC-内存架构:线程私有区线程共享区native堆‑GC算法标记‑清除、标记‑复制、标记‑整理‑GC日志查看命令adb logcat | grep GC‑Concurrent GC后台并发回收Full GCSTW暂停所有线程极易造成卡顿‑内存泄漏对象无用但仍然存在有效引用GC无法回收内存持续上涨最终OOM十九、ADB调试命令#查看CPU adb shell top adb shell dumpsys cpuinfo #查看内存mem adb shell dumpsys meminfo 包名 #查看IO adb shell iotop #窗口window信息 adb shell dumpsys window displays #音频audio adb shell dumpsys audio #wifi adb shell dumpsys wifi #导出ANR日志 adb pull /data/anr/traces.txt ./二十、性能优化大全###UI卡顿、丢帧优化1.布局优化ConstraintLayout减少嵌套include、merge、ViewStub懒加载2.绘制优化降低过度绘制移除无用背景3.监控工具Systrace、Choreographer线上丢帧监控###内存优化减少临时对象创建图片三级缓存资源及时释放LeakCanary检测泄漏###CPU优化主线程移除耗时任务减少无效循环降低后台唤醒频率###IO优化批量读写文件异步IO增加内存缓存###Binder跨进程优化减少跨进程调用次数批量传输参数###启动耗时优化冷启动Application不要执行耗时任务懒加载App‑Startup区分冷/温/热启动二十一、稳定性优化 ANR、Crash、内存泄漏###ANR触发条件输入事件5s无响应广播10sService20s排查traces.txt日志常见原因主线程IO、死锁、Binder阻塞###Crash‑Java Crash全局异常捕获UncaughtExceptionHandler‑Native Crashso库崩溃addr2line解析堆栈日志###高频内存泄漏场景Handler延时消息未移除静态变量持有Activity单例持有Context匿名内部类定时器、广播未注销二十二、静态内部类单例public class Singleton{ private Singleton(){} private static class Holder{ private static final Singleton INSTANCEnew Singleton(); } public static Singleton getInstance(){ return Holder.INSTANCE; } }优点懒加载、JVM类加载天然线程安全、无锁高性能缺点反射、反序列化可以破坏单例二十三、高频设计模式应用场景例子1.单例模式全局管理器、图片加载框架2.工厂模式对象创建、网络请求工厂3.Builder建造者OkHttpClient、AlertDialog4.观察者模式LiveData、EventBus5.适配器模式RecyclerView.Adapter6.策略模式动态切换业务算法7.装饰模式Context8.中介者模式FragmentManager二十四、拓展高频面试题1.WebView全套坑内存泄漏、JS交互、缓存、HTTPS适配2.多进程优缺点Application多次创建静态变量不共享3.Binder完整原理一次拷贝4.WorkManager、Navigation原理5.线上卡顿监控方案6.字节码插桩 AOP7.Android权限适配8.车载Android AVM、Audio、Framework专项如果你需要我可以再输出一份纯考点精简背诵版无代码用来快速复盘。