此刻已经到了 2024 年的 2 月初,快过年了,部分同事已经陆续请假回家了,趁着年底不忙,慢慢总结下 2023 这一年。
待了七年的公司,期间动过无数次离开的念头,而这次我终于勇敢地跨出了这一步。这七年里,我买了车、结了婚、还生了两娃,我把我最美好的青春都留在了这里。从刚进来时的 Android 开发,到后面的 .NET、Angular 以及 Vue, 实现了前后端一把梭,这几年不但经历了自身的成长,也见证了公司的兴衰。
记得 2016 年公司在 A 股上市,全体上下无不憧憬着美好的未来,新来的我也卯足了干劲。但好景不长,到了 2018 年,公司进行了一次相对大规模的裁员,历史上绝无仅有,一些“能力不足”的同事走了,而我侥幸逃过一劫。在接下来的几年里,可能是由于自己的努力和机遇,虽然经历了几次架构调整和产品线变更,但好在一切都在往好的方向发展,团队相处融洽,领导也青睐,我感觉似乎可以在这里一直干到退休了。
然而 2022 年底的一通电话突然拉起了“躺平”的我,电话那头是七年前的老东家领导,他问我最近有没有换工作的想法,他那边新成立了大前端部门,负责人岗位空缺,想让我过去带团队。这一刻,命运的齿轮开始转动。
时隔七年,再次回到原来的公司,早已物是人非,刚开始的一个月,我是极度不适应的,甚至萌生了退缩的念头。一是从开发转为基层管理的思维转变,团队二十多号人,很多东西都需要主动去识别和了解,否则无法支撑自己做好管理和决策;二是部门事项繁杂,累是真的累,不夸张得讲,在这里三个月的加班量比过去的七年都多;所以我不争气地怀恋起上家公司的躺平氛围。
熬过了这一年,现在回头看看,这期间的转变其实是巨大的,心态也和刚开始完全不一样了,对于这次的机会我是非常庆幸的,也不后悔。
由于换了工作,单程通勤距离由原来的 25 km 缩短为 6 km,虽然还是开车上下班,但是没了堵车,没了路怒症,带来的幸福感提升是巨大的。八月份过生日,老婆问我想要什么礼物,我说要么整辆自行车吧,我上下班骑。没想到买自行车却成了 2023 年做的最正确的一件事。为了兼顾山地车的舒适性和公路车的速度,最终选中了入门平把公路车-喜德盛极速 380。
从九月份开始,除非下雨天,几乎每天都坚持骑行通勤,6 km 骑行时间也从刚开始的 25 分钟,到后面能达到18分钟左右,体能的提升肉眼可见;每天迎着朝阳,骑到公司的大汗淋漓,运动带来的荷尔蒙提升,一扫清晨的疲惫,同时骑行带来的变化也会影响着身边的人,好几个同事也陆续加入了骑行队伍,于是我们组建了一个骑行车队,每个周末的集体骑行活动成了最大的期待。在过去的这几个月,月均骑行里程超过 300 km,2024 年,希望能有更大的挑战和突破。
聪明、乐观、皮实、自省、自律
有套路的问题,有标准答案的问题,容易造假的问题在面试时尽量避免,它们不能很好的让自己清楚得认识到候选人的真实情况,因为问完这些问题你可能还不能判断是否录用。
最重要的一点:业务面试官不要聊涉及薪资待遇话题。
一场有效的面试 = 充分准备 + 过程记录 + 跟进及时
可以围绕职业发展情况、过往业绩点以及疑惑点展开。
理念淮备
2 分钟氛围创设和自我介绍
15-60 分钟专业背景、过往行为、动力适配以及其他信息
2-5 分钟候选人提问,提供关于职位的补充信息
面试时直接在简历上做记录,圈好关键字,最后做好面试评价,为下一轮面试官做提供数据支持。
情景面试法
STAR 面试法
压力面试法
Probing 面试法
其目的是深入挖掘和了解面试者的经验、技能和适应性。这种方法通常涉及提出开放性问题,以激发详细的回答,以便更全面地评估候选人的能力和适应性。
3W 面试法
侧重于收集求职者的工作经历和能力。"3W" 代表 What(做了什么)、Why(为什么这么做)、和结果(取得了什么结果)。
2022 年初的一波疫情,让原本有序的生活变得一团糟,快递停摆、居家办公、全员核酸,搞得人心惶惶。然而回头看,竟有点怀念那种生活,谁又能想到,现在以这种方式结束,就像那轰轰烈烈的爱情,说散就散了。
年初爷爷意外摔倒,住进了医院,一待就是一个月,没有半点好转的迹象,临近春节,奶奶叮嘱我,今年无论如何一定要拍个全家福照片。大年初六,在姑姑家新房里,拍了最后一张满员的全家福,一个月后,爷爷与世长辞,我从苏州赶回去,送了他最后一程。
去年八月公司体检,发现右侧甲状腺结节,体检中心说问题不大,定期复查就行,于是没太放在心上。今年三月份,咽部突然有异物感,10 多天都没有好转,心里慌了,担心是不是结节长大了?好在几天后,异物感好转,加上疫情原因,就没有去医院,最终不了了之。时间一晃来到了今年六月初,咽部又突发异物感,这次没有犹豫了,直接去了医院,确诊 ACR TI-RADS:5 级,结节实质钙化。在咨询了医生后,决定手术切除。手术那天的场景我这辈子都不会忘记,去往手术室的路上,天花板和灯光在眼前飞速划过,不停变换,就像人生的一场幻灯片,而我从未看过。好在手术很成功,术后恢复也很好,休息了两周就回公司上班了。挨了一刀,带来了更多的感悟和思考,我觉得是幸运的,身体才是革命的本钱啊!
今年小橙子三周岁了,到了上幼儿园的年纪,然而对于一天早教和托班都没上过的他,我又是忐忑和紧张的。父母和孩子一样,都有分离焦虑,开学的第一个星期我们都过得很痛苦,每天老师发的照片里他都在哭,不合群,甚至连续三天尿湿裤子,想想又心疼,但又不得不放手成长。不过令人欣慰的是,一切都在第二个星期得到好转,他开始积极参与集体活动,吃饭睡觉都很乖,老师反馈互动表现都很棒,老父亲终于长舒了一口气。
来公司的第 7 个年头,今年没有了以往骚动的心,可能也是因为生了二胎的缘故,动不了也动不起。今年的工作内容没有任何变化,身边的一切也都是老样子,但好在领导看来,我是兢兢业业的,对得起自己,也对得起公司。我以为今年又这样趟过去时,年底的一封加薪邮件,让这阴冷的冬天多了一丝暖意和惊喜,明年好似又多了一份期待啊,加油,打工人。
今年业余时间捣鼓了两个新 App,《一剪没》以及《扫你码》,都是基于 Android 最新技术体系,比如 Jetpack Compose。明明工作内容已经不涉及 Android 了,但我还是怕把它弄丢了,这可能也是一种偏执。
今年最开心,最传奇的事莫过于帮老爸找回被偷的手机了,简直堪称奇迹,能吹几百年的牛逼。
2012 年大学毕业至今,一晃整整 10 年过去了,曾经的少年已是中年大叔,也被生活磨平了棱角,下一个 10 年又会怎样呢?
]]>一个可能让你在微信里更舒服地扫码小工具。
]]>一个可能让你在微信里更舒服地扫码小工具。
当我们在微信里吃瓜,或者查看朋友分享的一些好东西时:
长按识别二维码后,经常会遇到以下几种情况,这严重影响我们的使用体验:
此时我们只能保存图片到本地,然后再打开对应 App 去识别这些二维码。如此繁琐的操作背后,究其原因无非就是大厂的生态壁垒以及国内互联网的内容审查,有没有一种更加快捷的方式,实现即时在屏幕上扫码,也不局限于微信?答案是有的。
利用录屏 MediaProjection 获取到当前屏幕画面,然后 ZXing 识别其中的二维码,最后打开网页,一气呵成。理想和现实的差距就体现在:如何在微信里一触即发?
其实还有类似的“悬浮球”功能也能快速打开指定 App,每家手机系统可能实现不一,但是原理都是一致的。
各大 App 分享的图片二维码内容几乎都是 URL,我们只要调起外部浏览器打开就能突破微信的限制,实现吃瓜自由。由于 Android 11(API 30)调整了软件包可见性,当应用 targetSdkVersion >= 30 时,需要在清单文件中添加 <queries>
元素进行适配,否则无法调起外部浏览器。
最后把 Activity 的背景色改为透明,修改默认的进入和退出动画,这样在打开时就不会有明显的割裂感了,堪称完美,一个全新的“扫你码”App 就此诞生。
项目地址:https://github.com/li-yu/FuckWxScan
老爸用的手机是红米 K40,我依稀记得去年给他设置并登录了小米云服务,抱着试试的心态,我登录了小米云服务,值得庆幸的是,他的小米账号密码竟然是我常用的密码(其实我都忘了我设置的啥密码了),凭直觉一次就登录成功,然后便是查找设备,然而手机早已关机,最后一次定位显示在老爸上班的地方,时间为 8:57,最后我打开了丢失模式,留下了我的号码。
大概半小时后,接到了老爸电信卡打来的电话(身边有个旧的坚果手机备用),告知电信补卡成功,而移动的却补卡失败,移动异地补卡被要求提供三个月内通话记录,由于平时联系都是电信卡,移动的因为绑定了多张银行卡,遂改成8元套餐当副卡使用,根本没法提供通话记录。于是没办法,只能先打电话给归属地 10086,进行了紧急停机。根据客服指引,下载中国移动 App,进行了在线补卡操作,期间由于微信和支付宝都是绑定的移动卡,5 元补卡费的支付陷入了死循环,好在最后通过我的银联卡完成了支付。
一通操作后,我才让老爸进行了报警,警察来后,询问了丢失经过,便走了,其实这会儿已经不抱任何希望了。毕竟丢手机这件事,我觉得老爸也有责任,据他描述,早上接了老板一个电话,随手放在桌上,然后去倒了杯水的功夫(隔壁房间),前后不超过 5 分钟,回来就发现手机没了。由于事发楼层没有监控,人员也杂,一时也毫无头绪,我让他安心等警察破案。
说实话,我自己也对找回手机没有信心,身边太多这样的案例了。往后的几天,我时不时的就打开小米云服务网站看看手机定位,都魔怔了,倒不是心疼这 2000 多的手机,而是这件事让老爸慌得不行,担心银行卡的钱,担心微信里的钱,他觉得他辛辛苦苦赚的钱都会没有了,我说不会的。两天后,他收到了邮寄过来的移动 SIM 卡并完成了激活,这期间,小米云服务也一直没有显示新的定位信息,我以为这件事就这么过去了。
【小米】您丢失的M2012K11AC手机已于2022-08-31 12:04:21上线,可访问i.mi.com使用查找手机功能定位丢失的手机。
三天后的 31 号中午,我刚吃完午饭,突然一条短信让我血脉膨胀,本着警惕的原则,加上钓鱼短信很多,我随即登录了网站,确认了定位信息,然后立马打电话给老爸,告知了他位置,是一家手机店附近,距离事发地大约 12 公里,不算太远,我让他赶紧过去。卧槽,说实话,我这会儿激动到说话都是颤抖的,有种破案后仿佛胜利就在眼前的感觉。
大约 13 点左右,老爸赶到了这个手机店,不得不服小米的定位信息很准确的,营业员说刚才确实有个人过来解锁手机,说是刚买的手机,不知道怎么操作锁起来了,但是这家手机店最终解锁失败,说 10 几分钟前刚走,让其提供监控信息,营业员表示拒绝,我们也能理解,没再多废话,于是便报警。警察来后,顺利调取到监控,拿到了录像和嫌疑人的截图,由于摄像头是俯视,正面拍的不是很清楚,但是大概体貌特征是可以掌握了,男性,白色T血,年纪大概 40 左右。警察说,证据会交由事发地派出所继续处理,说完便走了。(后话:这家手机店其实明明知道手机是偷的,毕竟丢失信息都显示在屏幕上,不过大部分人都会选择无视的)
中午的亢奋劲头消去,下午整个人都昏昏沉沉的。17 点左右,一个归属地显示浙江金华的电话打了进来,对方表示是xx手机店老板,说刚才有个人来店里解锁手机,发现屏幕上留有我的丢失信息,疑似偷盗机,想进一步确认下,并表示已记录了“嫌疑人的信息”:名字和手机号码,并告知了店铺位置也表示会积极配合调查。我把掌握的信息发给老爸,让他直接去派出所,让民警处理,不要私自联系。不得不感慨,这世间还是有好人的。事已至此,直觉告诉我,快结案了。
接完手机店老板电话大约 20 多分钟后,一个电话打了进来,号码正是店主提供的“嫌疑人”的,一开口对方就表示前几天在万达广场捡到一个手机,问是不是我的,并问我现在在哪儿,要立马给我送过来。听得出来,对方很激动也很紧张,但是这番操作是我万万没想到的,我没多说什么,毕竟对方愿意归还手机,随即让他送到事发地派出所,对方表示半小时送到。
半个多小时后,老爸顺利拿到手机,钢化膜、手机壳以及 SIM 卡不见踪影,好在手机完好无损,顺利解锁后,发现已被刷机,资料全无。
回顾整个事件,最关键的一点就是遇到了一个好人店主,以及给老爸的手机开启了查找设备功能,最终能顺利拿回手机,简直堪称奇迹。至于对方为啥突然这么急的归还手机,竟然是被手机店主吓的。虽然用了一年多的 K40 值不了几百块,但是事后老爸还是买了点水果专程上门进行了感谢。最终从店主口中的得知了原委:小偷下午到达了这个手机店,拿出手机让解锁,店主看到锁屏丢失信息后表示这种丢失模式很难解锁,并委婉询问这个手机的来历,对方表示是自己的。因为解锁刷机需要时间,店主表示可以把手机留在店里,等解锁成功后通知对方来取,对方同意,留下了姓名和电话便离开了。谁知仅仅过了几分钟,对方竟折返取了回手机,表示不解锁了。等对方走后,店主根据锁屏上的电话信息联系到了我,在和我通话后,店主也联系了小偷,表示他这个手机是偷的,失主已经报警定位到了店铺位置,警察过来办案追回和自己主动归还性质是不一样的,估计会被判个半年几个月啥的,让对方考虑清楚,于是便有了后面小偷主动联系我的情节。
]]>谷歌从 Android 10 开始禁止后台应用读写剪贴板,这一定程度上改善了剪贴板的滥用情况,但是我们仍能看到,在打开某些应用时剪贴板被疯狂读写,除了塞一堆乱七八糟的进去,此外如果剪贴板里存在一些手机号、身份证号以及详细地址等个人隐私信息的话,无疑是会被其读取的,至于它们拿来干嘛只有鬼知道。
日常粘贴动作完成后立即清空剪贴板,防止被其他程序读取。
复制动作后,如果 15 秒内没有进行任何粘贴动作,同样执行清空操作。
借助无障碍服务 AccessibilityService 监听全局复制、剪切和粘贴的点击事件。
无障碍服务下不需要申请权限即可实现悬浮窗。
透明悬浮窗获取到焦点后(App 进入前台)即可进行剪贴板操作,这对于用户是无感知的。
另一种监听复制事件的方法:
// 和以前一样,App 同样需要实现以下方法监听剪贴板的变动事件
clipboardManager.addPrimaryClipChangedListener {
// 当 App 在后台时,Android 10 以后虽然无法正常回调此方法,
// 但是系统会产生报错日志,我们捕获这个报错日志即可
// 注意:需要赋予 android.permission.READ_LOGS 权限才能抓到日志(部分手机无效)
}
允许拥有通知权限,开启前台服务提高存活几率。
允许自启动,每家手机厂商设置方式不一样,但大同小异。
多任务列表 App 加锁也是提升存活率的好办法。
vivo 系手机一定务必开启:设置->电池->后台耗电管理->允许后台高耗电,否则服务无法正常运行。
执行 adb -d shell pm grant cn.liyuyu.oneclipwiping android.permission.READ_LOGS
,部分手机即使赋权后,也不能捕获到 logcat
,比如 vivo 系。
当发现无障碍服务已经开启,但还是无法正常工作时,请尝试重启手机,屡试不爽。
微信聊天界面的输入框以及聊天列表均重新实现了 ContextMenu,遗憾的是,无障碍服务竟然拿不到其复制和粘贴的点击事件,所以目前只能依赖于复制后系统 Toast 提示的 “已复制” 或者借助 READ_LOGS
来监听,然后等待指定时间后清空剪贴板。
今年小橙子两岁了,懂的越来越多,睡觉也越来越乖,带起来愈发省心。然而舒服的日子不长,3 月底,老婆意外怀孕,知道的那一刻我俩除了惊喜更多的是焦虑,刚度过小橙子最难熬的 2 岁,又来一个神兽,那画面不敢多想。没有了第一胎时的激动和喜悦,我们开始思考和权衡,二胎的意义是什么?万一又是个儿子怎么办?谁来带?我和老婆都是独生子女,很多时候都希望把全部的爱给小橙子一个人,独享的爱。
You can't have your cake and eat it.
我知道,不管怎么选,最终都会后悔。然而最后还是选择了一条最艰难的路:生二胎。没有任何悬念和意外,11 月底小儿子出生,直到现在我还是没法释怀,我竟然有了两个儿子。家里突然多了一个新成员,小橙子的敏感比我们预想的强烈些,如何正确处理他的情绪又成了一个头疼的问题。
今年参加了公司年度体检,发现了一堆小毛病,这些年都没怎么重视自己的身体状况,运动几乎没有,体重日益增加,带来的副作用也很明显。人有时就这样,不体检根本不知道身体的严峻形势,于是 9 月份体检完开始跑步和控制饮食,体重也从 80kg 降到现在的 77kg,效果还是有的,不过离目标还很远。体检带来的连锁反应还有对父母身体的担忧,下半年,也抽空带父母进行了一次体检,同样小毛病一堆,到了他们这个年纪,健康比什么都重要。
今年是来公司的第 6 个年头了,真没想到一待就是这么久。年初筹备了很久的面试学习,被意外的二胎打乱节奏,眼下公司的 955 和宽松的工作氛围能让我在家庭和公司间找到很好的平衡点,于是又又又撑了一年。今年整体的工作内容还是前后端一把梭,以及维护零星的几个 Android 项目,没有任何挑战性。呆久了真的有惰性,想动却又不敢动,顾及领导的想法,担心未来的变数,只能苟活在眼下,挺怂的。
今年利用空闲时间整体学习了下 Jetpack Compose,同时做了一个相册管理的 App,自己一直使用着。得益于 Kotlin 语言,Jetpack Compose 带来的编程体验是很棒的。虽然工作内容越来越远离 Android,但是初心不改,Android 依旧是我梦开始的地方。
今年依旧是想法多,行动少的一年。新的一年希望能有所改变吧,多陪陪家人,多读读书,少刷抖音。害!加油吧,中年人!
]]>所有书籍资源都存放在百度网盘里,想靠百度那点小水管不知道要下载到何年马月,于是充值了 SVIP,期间却因为各种文件名过长、违规资源等等导致了很多文件下载失败,修复路径以及在线解压再下载等手段,陆陆续续花了 2 天时间才下载好,但也舍弃了不少“违规”资源,多少还是有一点遗憾。
下载完后用 C# 写了个控制台应用递归遍历解压了各类 zip 以及清理了空文件夹和脏文件(比如百度网盘生成的 .downloading 文件),然后利用 dupeGuru 扫描清理了重复文件。
Calibre-Web 的运行依赖于 Calibre 生成 metatde.db 的数据库配置文件,所以先在电脑上安装 Calibre,然后在群晖里新建一个文件夹用于 Calibre 应用目录,最后作为远程文件夹挂载到本机供 Calibre 使用,切记赋予这个文件夹 Everyone 读写权限。
所有书籍导入 Calibre 是一个极度漫长的过程,耗时数十个小时,因为每本书都需要读取元数据生成封面等信息,暂时没有找到快速导入的方法。此外在以 从文件夹和子文件夹添加书籍 方式批量导入书籍时,提示 多文件图书?
对话框,不同的选项,结果也不同:
原始文件夹如下,共 6 本书籍,其中 3 本是包含多种格式(mobi + epub + azw3):
从结果看,选择“否”之后导入了全部书籍,是我们想要的结果,官方是这样描述这个功能的:
Calibre 假设每个文件夹包含一本书。一个文件夹中的所有电子书文件都假定是同一本书,只是格式不同。
网上流行的一些教程都是推荐 technosoft2000/calibre-web 这版 Docker 镜像,功能全面。但经过我安装测试后发现了一些问题,比如单独进行格式转换或者邮件推送 Kindle 是没问题的,但是两者一旦结合,转换并推送 Kindle 时就会失败,翻看了源码,发现在处理邮件发送时,获取待发送的书籍路径多了一层,导致找不到文件。此外还有豆瓣获取元数据的 API 失效,经常卡死,镜像作者也指出没有时间维护了,遂放弃。最终选择了 linuxserver/calibre-web,并完美解决了各种问题。
群晖 Docker 创建容器很简单,基本一路 Next 就可以跑起来了,也可以参考这篇教程。
linuxserver/calibre-web 前期使用正常,除了每次启动容器有点慢,整体还是可以的,后期随着 calibre 升级到 v6,群晖内核不支持了,导致格式转换报错,于是选择了 johngong/calibre-web,一个国人维护的版本,很多功能都集成了,开箱即用。
linuxserver/calibre-web 版本镜像没有书籍转换功能,需要在创建容器时新增环境变量 DOCKER_MODS=linuxserver/calibre-web:calibre
,切记一定是创建容器时添加,如果创建后再添加,大概率会失败。
启动后登录 Calibre-Web,在权限管理
-> 扩展程序配置
-> Calibre 电子书转换器路径
填写 /usr/bin/ebook-convert
,保存即可。
johngong/calibre-web 版本自带,无需额外设置。
新增环境变量 TZ=Asia/Shanghai
重启容器即可。
johngong/calibre-web 版本自带,无需额外设置。
新版 Calibre-Web(0.6.14)移除了 douban-api,国内不科学上网的话无法搜索书籍的元数据,网上找到一个解决方案:calibre-web-douban-api,复制 src/NewDouban.py
到 calibre-web/cps/metadata_provider/
目录下,重启项目即可。
也可以直接下载后通过 Docker 的卷映射挂载到 /app/calibre-web/cps/metadata_provider/NewDouban.py
目录即可,效果是一样的。
如果遇到搜索元数据时容器卡死,可以删除 /app/calibre-web/cps/metadata_provider/
下其他源,只保留我们新增的这个豆瓣源,然后重启容器即可。
Ps. johngong/calibre-web 版本设置 ENABLE_DOUBAN_SEARCH=true 环境变量即可。
最新版 johngong/calibre-web 需要把 usr/local/calibre-web/app/cps/metadata_provider
下所有搜刮器删除然后使用新的豆瓣搜刮器,执行下 wget -P /usr/local/calibre-web/app/cps/metadata_provider https://raw.githubusercontent.com/fugary/calibre-web-douban-api/main/src/NewDouban.py
或者也可使用上面提到的卷映射,效果是一样的,最后重启容器即可。参考
linuxserver/calibre-web 版本默认没有开启该功能,前往 权限管理
编辑对应用户权限,勾选 查看书籍
选项即可。
johngong/calibre-web 版本自带,无需额外设置。
首先进行 SMTP 邮件服务器设置,具体可以参考邮箱服务商的帮助文档,比如我用的 QQ。然后前往亚马逊,管理我的内容和设备
-> 首选项
,获取对应设备的 Kindle 邮箱地址,并设置发件人白名单。最后在 Calibre-Web 里 接收书籍的Kindle邮箱地址
填写即可。
Ps. 国内的推送服务还能使用 2 年,到时候估计得切到美区了。
所有版本的 calibre-web 都不推荐在网页内自动更新程序,可能会出现莫名其妙的问题。其实更新容器也很简单,我们只要导出容器设置文件(端口设置、环境变量等都会保留),然后删除容器,更新镜像后通过导入配置文件重新创建容器,所有资料和配置都还在,分分钟就搞定了,当然也可以使用 Watchtower 来自动更新 Docker 镜像与容器。
更新元数据时不当的操作可能会导致数据库损坏,后续所有的保存都会提示 database disk image is malformed ......
,此时可以尝试使用 SQLite Expert Professional 5 对 metadata.db
进行修复,然后使用修复后的 db 文件覆盖替换就行。
阅读受众:新人或者困惑者
文章涉及环境:Android Studio Arctic Fox | 2020.3.1 Patch 4
文字里提到的 Java 版本均为:JavaSE(Java Platform Standard Edition)Java 标准版
文章更新时间:2021-12-15 21:00
这个问题一直困惑着不少新手,其实可以简单地把它们理解为同一个东西(体系),由于历史原因,这种混乱的命名方式目前仍持续影响着:
比如 Gradle 7.0.2 源码中是这样描述 Java 版本的:
而 Kotlin 中是这样描述 JVM 的:
-jvm-target version
Specify the target version of the generated JVM bytecode. Possible values are 1.6 (DEPRECATED), 1.8, 9, 10, 11, 12, 13, 14, 15, 16, and 17. The default value is 1.8.
上图中的 Java 9,Gradle 称之为 VERSION_1_9
,也就是我们常说的 1.9
,而 Kotlin 直接成为 9
,其实都是同一个东西,不同的编译(构建)工具或者框架体系中别称不一样而已。
伴随着 Java 的迭代发展,这个问题也在逐步改善,目前从 Oracle Java 官网来看,命名已趋于统一,就连以前老的版本的名字都改过来了,变成了JDK7,JDK8 这种形式,不再是之前的 JDK1.7 以及 JDK1.8,至于新的,比如 Java 17,肯定再也不会出现 1.17
这种奇怪的名字了。
Android Studio 2.2 首次捆绑 OpenJDK8,也就是从那时候开始我们的电脑不需要额外安装 JDK 就能运行 Android Studio 了。
Oracle 起诉谷歌在 Android 上使用 Java 代码侵犯版权和专利权是谷歌参与 OpenJDK 项目以及捆绑 OpenJDK 到 Android Studio 的导火索,其实再看看 OpenJDK 和 Oracle JDK 的区别,就自然明白谷歌的心思了。
Gradle 是一个基于 JVM 的构建工具,不是编程语言!它见证和陪伴了 Android Studio 的成长,但由于 Gradle 不单单服务于 Android 的开发构建,因此谷歌开发了一个 AGP(Android Gradle Plugin) 插件,添加了几项专用于构建 Android 应用的功能。虽然 AGP 插件通常会与 Android Studio 的更新步调保持一致,但 AGP 插件(以及 Gradle 系统的其余部分)可独立于 Android Studio 运行并单独更新。
为了和 Gradle 的版本匹配,目前最新的 AGP 跳过版本 5 和 6 直接进入了 AGP 7.x 版本。
毋庸置疑, AGP 的运行肯定是需要 JDK 的,随着 AGP 的迭代,所需的 JDK 版本也随之变化。最新 Android Studio 使用 AGP 7.x 构建应用时,需要 JDK 11 或更高版本才能运行 Gradle。由于最新 Android Studio 捆绑了 JDK 11(OpenJDK 11),并将 Gradle 配置为默认使用 JDK 11,这意味着大多数 Android Studio 用户不需要对项目进行任何配置更改。
如果使用的是独立于 Android Studio 的 AGP,需要将 JAVA_HOME
环境变量或 -Dorg.gradle.java.home
命令行选项设置为 JDK 11 安装目录。
需要注意的是,上面所说的 JDK 版本是运行 AGP 所需的,不是我们开发编译业务代码所需的 JDK,两者是独立配置的。最新 Android Studio 也为了区别开,专门新增了一个 Gradle JDK 的配置项:
要知道,Java 17 都正式发布了,但根据调查显示,80% 的受访者仍然在使用 Java 8。目前受 Oracle LTS 的版本只有 Java 8,Java 11 和 Java 17,而 Java 8 的截至支持时间更是达到了惊人的 2030 年 12 月。
首先从 Oracle JDK 8u211 开始往后的版本,都需要商业收费,但我觉得这不是最重要的原因。Java 8 中终于引入了 Lambda 表达式,写过 C# 或者 Kotlin 的应该都知道,这东西写过就回不去了,除此之外,还有支持重复注解以及新增 Stream 和 Optional 类数据处理等等,这些 Java 8 开创性的语言特性还在持续渗透影响着,在 Java 8 之后的一些版本,新特性不痛不痒,也没有足够的说服力让我们去更新,要知道,生产环境越稳定越好。
目前在最新 Android Studio 新建工程时,无论选 Java 还是 Kotlin 语言,都是默认 Java 8 编译环境:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
Kotlin 是一种在 Java 虚拟机(JVM)上运行的静态类型编程语言,本质上和 Java 一样,都会编译成 Java 字节码运行。Koltin 和 Java 100% 互操作,且 Kotlin 开发之初就以兼容 JDK 6 为目标,因此很多老旧系统的设备都能运行,无须担心其兼容性。此外,Kotlin 在空安全、懒加载、高阶函数、协程、inline 操作符等等新特性以及语法糖的加持下,用过就真的就回不去了。
由于不同的 Android 版本所支持的 JVM 版本也不同,所以在使用不支持的高版本 Java 语法时,需要在编译期转换为其支持的低版本 Java 语法,这一过程称为 Desugaring(脱糖)。
Android 的脱糖发展史经历了早期的 javac&ProGuard 以及 Retrolambda 到后来的 Jack&Jill 编译器,再到最新的 D8&R8,其实脱糖的核心目的只有一个:让所有的 Java 语言新特性都能运行在所有设备上。
Android Studio 目前已支持大部分 Java 8+ APIs 且不需要指定 App 的 minSdk 最低版本,这就是通过 D8 脱糖实现的。
但是 D8 也不是万能的, 它只为我们提供了部分核心的语言特性支持。
很遗憾,截至目前,在我尝试前往 Project Structure -> SDK Location -> Gradle Settings -> Download JDK ,下载并设置最新的 JDK 发行版本(推荐 Oracle OpenJDK 17),然后设置 compileOptions
为 JavaVersion.VERSION_17
并且设置 compileSdkVersion
为 30 及以上,Kotlin 的工程还需要指定 jvmTarget = '17'
,一顿操作之后,编译报错,提示 Unsupported class file major version 61
。
目前 AGP 最新版为 7.0.4,其依赖的 Gradle 为 7.0+,而要支持 Java 17 则需要 7.3+,所以暂时没戏了,后期升级应该是可以的。
最后经测试 AGP 7.0.4 + Gradle 7.0.2 + Java 11 是没毛病的。
然而今天,我不得不又借助相册回顾了即将过去的这一年,这一年平淡无奇,除了小橙子带来的快乐,其他的就什么都没有了。
这一年小橙子从牙牙学语到蹒跚学步,每天嘻嘻哈哈,蹦蹦跳跳,作为父亲累并快乐着,能参与到孩子的成长过程我觉得是值得的。不过这也带来了一个问题,就是属于自己的空闲时间越来越少。刚刚过去的周末,原本打算趁着年底公司项目不忙,看看书敲敲代码,做做技术储备,然而事与愿违。溜娃、做饭、家务一顿操作下来,只想静静地躺在沙发上刷手机。
这一年原本计划了很多,但却很多都没有完成。年初公司组织架构又变动了,来公司快 5 年了,几乎年年一变,每次我的工作内容都会随之改变。这期间也有过无数次离职的念头,可能是受新冠疫情的影响,可能是公司 955 的舒适环境,也可能是领导贴心的关怀,我最终熬到了现在。这一年工作内容主打 B/S 架构产品的开发,新涉猎了诸如 AngularJS、Vue.js 以及 .NET Core 等框架,公司的销售和研发模式也决定了每个人都是前后端一把梭,虽然有点杂,但至少拓宽了自己的技术栈。从进公司的一个纯 Android 开发混成现在这样,我不知道是该哭还是笑。
这一年给家里人换了一圈的新手机,而自己还在坚持 64GB 的 8P,天才吧换了新电池,应该还能大战一年。这一年牺牲了不少周末时光在副业上,收获也还算可以。这一年新添置了面包机、智能门锁以及我心心念的 DeskMini,幸福指数当然有了。这一年,看似平淡普通,却又充满了遗憾和不甘。
我庆幸自己有着良好的学习能力,每次被动的改变,都能从容不迫。但是自己的主动改变却越来越少,或者说是害怕改变了,害怕换工作,害怕新的开始。很久没有那种感觉了,那种走路带风,那种充满未来可期的感觉。
年底了,一些奇奇怪怪的想法又冒了出来,这次又会是怎样的结果?
]]>