深踩 AndroidStudio 缓存的坑_cannot lock build output cleanup cache (/android/.-程序员宅基地

技术标签: AndroidStudio  缓存  Gradle  Android笔记  

本文记录的是今天在群里提到的昨天所踩的一个坑,有关 AndroidStudio 缓存的。

先说一下背景。
我负责的一个项目,对一个图表库有外部依赖。这个图表库是我在维护的,由于新功能在开发中,所以我就使用了 SNAPSHOT 版本发布到 OJO(oss.jfrog.org) 上。我在项目中刚更新了依赖,忽然想到还少几个 API,于是发布了 SNAPSHOT 版本。
故事就这样开始了。

这时候回到 AndroidStudio 再去 Sync Project with Gradle Files 肯定是拉不下来的。众所周知,Gradle 的缓存策略中,对于 SNAPSHOT 版本默认的缓存周期是 24 小时,也就是从我上次更新之后,24小时内都会使用上次的缓存。

不周知的也没关系,我在这里补充说明一下,在 Gradle 用户指南的依赖管理一章中,有提到 Gradle 对于动态版本和变化模块的缓存时间默认是 24 小时。
何为动态版本?你见过的像 3.+ 这种就是动态版本,它会取检查到的最高的版本号。又比如 latest.integration,它也是动态版本。
而变化模块,就是像 0.2-SNAPSHOT 这种后面带 SNAPSHOT 的版本了。
这两者的区别就是,前者尽管你代码中的版本号写法不变,但实际上它仍然是去取仓库的最新版本。而后者它在仓库中的版本号还是一样,仍然是 xxx-SNAPSHOT,但实际上这个版本所对应的内容已经变了。

这里再多说几句,缓存周期也是可以修改的,在 Gradle 用户指南中同样有详细说明,就是添加如下配置:

configurations.all {
    resolutionStrategy.cacheDynamicVersionsFor 10, 'minutes' // 动态版本
    resolutionStrategy.cacheChangingModulesFor 10, 'minutes' // 变化模块
}

只是这里我一开始就贪省事,在更新依赖懒得去改。

既然如此,那怎么办?把 ~/.gradle/caches 整个给干掉?
不不不,那样太小题大做。其实这个问题我早已遭遇过,并且对于“汉化”过一遍 Gradle 用户指南的我来说太简单了。命令行下执行:

./gradlew aTD --refresh-dependencies

这里啰嗦一下,aTD 是项目中一个 Gradle 任务的缩写,全名是 assembleTestingDebug,其中 Testing 是项目里的一个 ProductFlavor。这并不重要,重点是后面的参数 --refresh-dependencies,加上这个参数,表示强制刷新依赖。
但是回到 AndroidStudio 写代码,发现代码提示中新的 API 还是没有出来。看来是 Android Studio 没有更新。不过没关系,这事我也有经验。点开右边的 Gradle 面板,找到 androidDependencies 任务,右键,Create xxxxx Configuration,然后在弹出的面板的 Arguments 一栏中输入前面提到的参数 --refresh-dependencies,添加完,在运行那里选择它执行。
这里写图片描述
等执行完,按照几年前的经验,这时候应该出来了吧?

然而,实际上并没有。
这时候我忽然想起,我们公司在阿里云服务器上搭建了一个 maven 私服,去年的时候我在上面配置了对 OJO 的代理,这时候拉取的是私服上的版本,是它没有更新?
没关系,解决方法很简单,删!
于是我登录到 nexus 上,找到缓存的这个库,右键,整个版本删掉。删了服务器上的之后,还觉得不放心,于是再把 .gradle 里的缓存给找出来删掉,我当时应该是这样子的:
这里写图片描述

使用 nexus 搭建 maven 私服有几种好处,一是可以放公司内部的库;二是配置对其他 maven 仓库的代理,当有人去访问某一个依赖时它就会缓存下来,下次其他人再访问同一个依赖的话它就会直接取缓存,对于一些在国内访问不是很友好的仓库如 jcenter,能有效减少等待时间。当然如果公司内部局域网部署一个的话,提升效果会更显著。

最后再执行前面步骤。命令行中已经可以看到重新下载了这个依赖了,并且我也检查了 .gradle/caches/modules-2 下对应的源码 jar 包,确实是更新了。
再回到 Android Studio,发现依然没有更新。
这什么情况?
我疑惑了一下,心中一个声音响起:
啊(这里应读四声)!
这时候我想到了,新版的 Android Studio 为了提速,多了一层缓存:对于第三方依赖会把它们解压出来,放到 ~/.gradle/caches/transforms-1 目录中。
于是继续:
删!

find . -name "hichart*" |xargs rm -rf

然后再构建,让它重新缓存,这时候应该就可以了吧。
在 Android Studio 中执行了构建,然后发现它确实重新缓存了。但是——
悲剧就此发展,深坑就此塌陷!

这时候,我发现不单是新加的 API 没有出来,编辑器里有关这个库的代码全都变红了!尽管!项目还是能跑起来!当时的屏幕是这样的:
这里写图片描述
不对不对。咋回事?

这时候我又机智地想到,这里缓存的路径有包含 hash 作为名称的文件夹,更新了之后,hash 值也不同了,所以应该是哪里的索引没有对应上。于是找啊找,就在 transforms-1/metadata-1.1 中发现了一个叫 results.bin 的文件。再搜一下里面有没有包含那个库的内容:

cat results.bin| grep "hichart"

提示是二进制文件。哦,那就加个参数:

cat results.bin| grep -a "hichart"

结果出来了,果然有。那好,那就再删!
等等——我这时谨慎了一下,还是重命名一下好了。于是重命名,然后再执行构建,然后看到这个文件重新生成了,看起来正朝预料中的发展。然而,有关这个库的引用还是报错。

这时候的我陷入了一番沉思,再试其他方法:

  • Sync with File System
  • Sync Project with Gradle Files
  • File -> Invalidate Caches / Restart

还是无效。带着郁闷,我下班了。


虽然这问题此刻表现得如此顽固,但是最终它还是被我解决了。
早上一来,我觉得我应该是有点急了,毕竟项目的开发时间由此被我拖多了一天了,但是作为一名有着一颗运维的心的程序员,自己踩陷的坑无论怎样也要把它踩平。
于是我开始往其他缓存方面上考虑,也没有去想合不合逻辑。我想到了 Gradle 在构建时会对一个任务的输入做快照,于是找到项目里的 .gradle/buildOutputCleanup 目录,删!
还不行,那就 .gradle/4.4(当前使用的 Gradle 版本),删!
还不对,那就整个 .gradle,删!
甚至,~/.gradle/caches/transforms-1/,删!
依然不对,那就 Android Studio 的配置文件夹,~/.AndroidStudio3.1,删!
删完重新打开 Android Studio 导入配置,这时候发现已经不是之前的问题了,你以为问题解决了吗?不!是问题升级了!这时候已经不是那个库报红了,而是所有引用第三方库的地方都报红了!!!尽管,还是可以运行起来!!

百般无奈之下,继续 google,看到的还是前面提到的 Invilate Cache 的方法。忽然在 Stackoverflow 中看到了一个看起来不是很常见的回答:

退出 Android Studio,删除所有的 .iml 文件以及 .idea 目录,打开 Android Studio 重新导入项目。

咦?这方法没试过。那就试试吧:

find . -name "*.iml" |xargs rm
find . -name ".idea" |xargs rm -rf

然后重新打开 Android Studio,点 Sync with File System,这时候奇迹终于出来了,应该说,Android Studio 终于正常了,编辑器不报红了!

压抑着心中的万分激动,有着打破沙锅问到底精神的我,对此问题仍不放弃思考。
所以,究竟是什么原因呢?
我看了一下 .iml 文件,没什么异常。那就再看.idea 目录。

find .idea -type f |xargs grep "hichart"

结果如下:
这里写图片描述
原来是在 .idea/libraries 里会记录每一个第三方库的 classes, javadoc 以及 sources 所对应的路径。其中 classes 对应的正是前面所提到的 transforms-1 里的目录,同样也正如前面所说,其中包含的路径是有 hash 值的,更新了依赖之后,hash 值不同,新的缓存路径也就不同了,而这里还是用的原来被删的那个路径,找不到对应的文件当然编辑器里就提示 cannot resolve symbol 了。所以正确而直接的解决方案应该是删除 .idea/libraries/ 里对应该第三方库的 xml 文件让它重新生成,或者是直接修改该 xml 文件的内容,改为更新依赖之后的路径。

写于 2018-03-07 17:20:11。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/maosidiaoxian/article/details/79480148

智能推荐

最新电信,网通路由表(200701日更新)-程序员宅基地

文章浏览阅读4.1k次。说明:ROS2.9.27用的网通,电信路由脚本操作方式: 添加脚本方式请,将你的正确的电信或网通的网关,使用用编辑-替换掉脚本里的“网关”,然后打开winbox,点击Terminal(控制终端)然后复制脚本,并在Terminal(控制终端)中点右键选择“paste”粘贴脚本,粘贴完后敲回车,即可完成!电信的路由表如下:/ip routeadd dst-address=

Navicat Premium 12.0.23安装与激活-程序员宅基地

文章浏览阅读517次。本文介绍Navicat Premium 12.0.24的安装、激活与基本使用。说明:博主所提供的激活文件理论支持Navicat Premium 12.0.16 - 12.0.24简体中文64位,但已测试的版本为Navicat Premium 12.0.22、12.0.23和12.0.24简体中文64位。 说明:博主所提供的压缩包格式均为RAR5,即WinRAR 5.0以上的版本才能正常解压,...

STM32标准库移植RT-Thread Nano添加FinSH与控制台_标准库实现rt_hw_console_getchar-程序员宅基地

文章浏览阅读1.6k次,点赞6次,收藏15次。添加过shell后首先要在 rtconfig.h中定义#define RT_USING_FINSH为了方便,串口相关函数添加在board.c中使用串口中断实现命令的接收/* * Copyright (c) 2006-2019, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2017-0_标准库实现rt_hw_console_getchar

chapter 4.3 cache -- 主存的地址映射和替换算法_映射替换,地址流格式-程序员宅基地

文章浏览阅读1.6k次,点赞3次,收藏4次。cache – 主存的地址映射和替换算法映射(3)1.直接映射原理主存块以cache长度分区,映射时cache缓存块仅接受各区中相对应的块号,tag仅需保存t位区号eg: cache[0] 中仅可以存放 主存[0,2c,2c+1,3*2c…]每个缓存块i(cache) 可以和 若干个主存块对应每个主存块j只能和 一个 缓存块(cache)对应地址块号直接与cache对应块标记..._映射替换,地址流格式

最长上升子序列&&最长不下降子序列-程序员宅基地

文章浏览阅读99次。百练2757: 题目描述: 对于给定的序列,求出最长上升子序列的长度。题目链接:http://bailian.openjudge.cn/practice/2757解题思路一、动态规划 1. 找子问题错误找法: “求序列的前n个元素的最长上升子序列的长度”是个子问题,但这样分解子问题,不具有“无后效性” 假设F(n) = x,但可能有多个序列满足F(n)..._. s,c; xm,xadnn/ or 0

NetWork——描述一次完整的网络请求过程_浏览器network发起请求历程-程序员宅基地

文章浏览阅读4.9k次。想拥有自己的服务器?价钱太贵,便宜的配置太低。。。总是处于各种原因,现在特大好消息,阿里云服务器活动,价钱低到爆,快来了解下,2核4G,3年低至699,时间有限,还剩10天,快来选购吧,地址:https://promotion.aliyun.com/ntms/act/vm/aliyun-group/buy.html?group=IAq264WFLl当我们在浏览器的地址栏输入 www.lin..._浏览器network发起请求历程

随便推点

对前端页面的边框设置_前端斜的边框-程序员宅基地

文章浏览阅读6.5k次。二·如何对边框设置:1.<div style="text-align:center; vertical-align:middel;"><input type="text"></div>这样你试试,应该就是左右 上下都居中了2.如果是让内容显示的居中:<html><head><style>_前端斜的边框

Springboot2中修改tomcat参数支持请求特殊符号 解决:java.lang.IllegalArgumentException: Invalid character found in ..._springboot内置tomcat放宽http请求头特殊字符-程序员宅基地

文章浏览阅读929次。使用Springboot2中内置的tomcat启动项目时候,前端发来的请求报错:java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986 at org.ap..._springboot内置tomcat放宽http请求头特殊字符

SHOW STATUS语句查看MySQL数据库的性能参数_show status like threads-程序员宅基地

文章浏览阅读1k次。SHOW STATUS语句查看MySQL数据库的性能参数1.SHOW STATUS like 'Slow_queries' //慢查询的次数 查看日志 1.配置 centos下 my.cnf log-slow-queries = /tmp/mysql-slow.log long_query_..._show status like threads

matlab如何解不等式,如何用MATLAB求解不等式组的所有可能解-程序员宅基地

文章浏览阅读2k次。太多了吧:No. a b c d1 4 86 17 652 13 96 20 873 5 97 56 544 4 32 14 ..._matlab 不等式组求解

2022年09月 Scratch图形化(三级)真题解析#中国电子学会#全国青少年软件编程等级考试_2022年9月scratch三级真题-程序员宅基地

文章浏览阅读273次,点赞4次,收藏4次。所以,答案D是错误的。两个角色小猫和小狗,给小猫创建一个仅适用于当前角色的变量“奔跑速度”,给小狗也创建一个仅适用于当前角色的变量“奔跑速度”,小猫和小狗程序如下图所示,点击绿旗,按下两次空格键,小猫和小狗的奔跑速度都变为7。运行程序后角色将从(0,0)点开始移动,x和y坐标的增加值均在1至10之间,因此,移动后的位置为点(1,1),(1,10),(10,1)和(10,10)所围成的四边形中。D:“我的变量”和计时器一起增加,当“我的变量”大于15时,计时器会归零,“我的变量”会随着计时器重新开始增加。_2022年9月scratch三级真题

Spring Security 如何实现身份认证和授权?_spring security认证和授权流程-程序员宅基地

文章浏览阅读2.7k次,点赞5次,收藏6次。Spring Security 是一个非常强大的安全框架,可以为 Spring Boot 应用提供完整的身份认证和授权功能。本文介绍了 Spring Security 如何实现身份认证和授权,并提供了示例代码。使用 Spring Security 可以非常方便地保护应用程序,防止恶意攻击和数据泄露。_spring security认证和授权流程

推荐文章

热门文章

相关标签