黑骑士的博客

也许不止是博客


  • 首页

  • 分类

  • 归档

  • 标签

  • 摄影

  • 关于

  • 站点地图

【Java面试题】Java类对象都是在堆上分配的内存吗?

发表于 2019-12-22 | 分类于 Java面试题 |
Java 的类对象都是在堆上分配内存吗,这是虚拟机面试中的一道经典题目,答案其实是否定的。文章先回顾标准虚拟机的内存划分:栈内存、堆内存、程序计数器、方法区与本地方法栈,其中每个线程都拥有独立的调用栈,方法调用依靠栈帧的创建与销毁来完成,引用变量与基础类型在栈帧内分配,而对象则在堆上分配。随后作者通过一个只在方法内部创建并使用的对象提出假想:既然它的生命周期与方法一致,如果直接在栈上分配内存,就能省去堆内存的寻址开销,也不必再依赖垃圾回收来释放。这个假想是成立的,其技术基础正是逃逸分析:当对象没有逃逸出所在方法时可以启用栈上分配甚至标量替换,没有逃逸出线程时则可以消除不必要的同步锁。文章列举了不同逃逸范围与对应的优化策略,并给出 HotSpot 的实现参考。
阅读全文 »

Timer/TimerTask 源码分析

发表于 2019-12-17 | 分类于 JDK源码分析 |
定时器是工具包中一个使用非常方便的定时任务工具,配合对任务进行封装的 TimerTask,可以轻松实现延迟执行与周期性重复执行。本文从一段典型的使用代码入手——定义一个继承自定时任务的任务、创建具名定时器对象、调用 schedule 安排任务延迟执行并按固定周期重复——由此切入对底层实现的源码分析。文章先给出整体概述,梳理出这套机制涉及的四个关键类型:对外提供接口的定时器类、实现了 Runnable 的任务抽象类、继承 Thread 的自定义线程类,以及存放全部任务的任务队列,后者内部使用二叉堆实现,以便高效地取出最近到期的任务。随后分别对这四个类逐一深入源码,分析它们的字段设计与协作方式,最后对整体设计与使用过程中的注意事项做出了总结。
阅读全文 »

静态使用 SimpleDateFormat 的线程安全问题

发表于 2019-12-16 | 分类于 Android实践问题 |
在项目开发中,为了避免反复创建对象,很多人会把日期格式化对象声明为静态成员,再提供一个静态工具方法供各处调用。然而这种做法在多线程环境下会产生意想不到的结果,本文专门分析其中的原因并给出解决方案。作者翻开源码指出,格式化方法内部会调用共享日历对象的设置时间方法,把本次待处理的时间写入这个成员变量,然后再依据它计算出各个字段并拼装结果。由于静态实例被所有线程共用,多个线程并发调用时会互相覆盖其中的状态,导致格式化出来的日期错乱甚至抛出运行时异常。文章顺着这条线索完整还原了问题发生的过程,并在最后一节给出了针对多线程场景的具体解决办法。
阅读全文 »

后台HandlerThread 使用的问题

发表于 2019-12-15 | 分类于 Android实践问题 |
本地文件读写、计算密集的运算、网络请求以及耗时第三方 SDK 的初始化,放到主线程会造成界面卡顿,但这些操作往往低频、零散且没有规律,每次单独创建线程又会带来额外的性能开销,HandlerThread 配合 Handler 是处理这类问题的常见选择。本文记录了一个非常反直觉的现象:向后台 Handler 投递出去的任务竟然有时完全没有执行。文章顺着这一现象深入源码,提出了一个关键疑问——当 HandlerThread 这个关联线程因异常而退出之后,再向它的消息队列投递消息,这些消息还会被处理吗。在得出结论后,文中给出了三种替代或加固方案:改用后台线程池以保证线程异常退出后有新的线程补充、使用 WorkManager,或者在运行方法外层加上异常捕获以免线程意外退出。
阅读全文 »

Android 模块解耦和的实践

发表于 2019-12-13 | 分类于 Android解决方案 |
当 App 需要新增一个人脸识别登录这类功能时,通常会遇到三个特点:功能本身相对独立、只有少部分设备能够支持、需要引入体积较大的第三方 SDK。这引出两个必须回答的问题:如何做好不同设备之间的兼容性,以及不支持的设备能否干脆不带这个功能。文章指出问题的本质是功能解耦与按需分发,并对比了两条技术路线——插件化配合动态下载,以及模块化配合多渠道构建分发;考虑到插件化缺少官方支持、对新版系统的跟进越来越慢,最终选择了后者。文中进一步围绕 Gradle 中的模块概念讨论解耦的具体做法,让新功能成为一个可裁剪的独立模块,从而在打包时选择性地引入,避免让用不到的用户白白承担包体积。
阅读全文 »

异步多条件依赖模型解决方案-条件仓库模式

发表于 2017-02-23 | 分类于 编码经验 |
开发中常遇到这样的场景:一段目标代码必须等待多个异步条件全部满足后才能执行。文章从一个真实的登录页案例讲起——头像图片加载成功与用户点击登录按钮这两个彼此异步的事件都发生之后,才允许发起登录请求,由此抽象出异步多条件依赖模型。文中先分析了几种常见做法的不足:使用全局变量做标记会让代码迅速变得臃肿且不优雅,引入事件总线或响应式框架在该场景下同样显得别扭,而且还可能受到项目对第三方依赖的严格限制。为此作者提出条件仓库模式,设计了条件仓库与建议以单例实现的仓库管理员两个核心角色,把条件的增删、判断与通知集中统一管理,从而优雅地支撑多条件下的异步依赖。
阅读全文 »

为第三方依赖中的View添加自己的监听器

发表于 2016-11-19 | 分类于 Android解决方案 |
在集成第三方开源库时,拿到的对外接口常常并不能完全满足实际需求。作者的真实场景是:使用谷歌的 ExoPlayer 时需要监听播放器上一个、下一个按钮的点击事件,但公开的接口里找不到对应的方法,只能另想办法。本文把这个方案整理记录下来:目标是既能获取到第三方库中某个 View 的点击、触摸等事件回调,又不能破坏该库自身原有的监听逻辑。直接调用设置监听器的方法是行不通的,文章结合 View 源码说明新的监听器会被赋值给保存所有监听器的那个内部对象,从而把原有监听器覆盖掉使其再也收不到事件。在此基础上作者给出一种非常规但可行的处理思路,在保留原有监听的前提下把事件再转发出去,并在最后做了总结。
阅读全文 »

android 中输入事件分发详解

发表于 2016-08-22 | 分类于 android基础 |
本文系统讲解 Android 的输入事件分发机制。开篇先把事件定义为设备所接收到的输入信息,并梳理其完整产生链路:用户操作引起硬件状态改变,底层将其封装成对象后交给 Framework 层,再一路传递到应用层开发者编写的 View 子类;值得注意的是,每一次用户动作都会产生一组有序的事件序列而非单个事件。文章列出按输入来源划分的几类事件,重点剖析最常用的触摸屏事件,说明它由按下、移动、抬起等基础动作组合而成,例如一次点击就是按下与抬起的组合。随后结合 View 源码介绍分发过程中的几个关键方法,逐层分析事件在不同类之间以及容器与控件内部的传递顺序并总结出若干结论,最后补充了按键事件的处理路径。
阅读全文 »

android 中 uses-feature 和 uses-permission的作用 关系和区别

发表于 2016-08-14 | 分类于 android基础 |
在 Android 的清单文件中,uses-feature 与 uses-permission 是两个经常成对出现、职责却完全不同的标签,本文专门厘清它们各自的作用、相互关系与区别。前者用于声明 App 运行时会用到的硬件或软件功能,它只是向外界描述 App 的依赖清单,本身并不向系统申请任何权限,例如仅仅声明相机功能仍然需要通过权限标签去真正申请拍照;其中是否必需这一属性尤为关键,取值为真时若设备不具备该功能,应用商店会直接对该设备隐藏此 App,取值为假则依然可见。而后者的职责是明确告知系统需要向用户申请哪些权限。文章最后通过一个典型例子说明这两个标签在实际项目中应当如何配合使用。
阅读全文 »

关于android 中采用 Intent 进行组件间通信的技术

发表于 2016-08-13 | 分类于 android思考 |
在阅读官方文档关于标准启动模式的描述时,作者注意到了这样一个用词:系统会在 Activity 被启动的任务中创建新的 Activity 实例,并把 Intent 对象路由进去,这里的路由一词颇有意思。由此展开一个类比:典型的 MVC Web 框架处理 HTTP 请求的模型,与 Android 中通过 Intent 完成组件间通信的模型,在结构上高度一致。在这一模型里,Intent 扮演的角色相当于 HTTP 请求,而路由器的角色则由 Android 系统自身承担;当然图中的 Activity 也可以替换为 Service 或广播接收器,它们使用的是完全相同的传递机制。文章最后得出结论:Android 组件间的通信机制在设计之初就在一定程度上参考了 HTTP 的通信模型,区别只在于前者的整个过程都在本地完成,中间并不涉及真正的网络请求。
阅读全文 »
<i class="fa fa-angle-left"></i>1234<i class="fa fa-angle-right"></i>

35 日志
21 分类
81 标签
GitHub E-Mail Instagram 知乎
© 2026 黑骑士
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.4
本站访客数 人次 本站总访问量 次