Home

如何查看Android Studio的错误信息

不知道是Google没有产品经理,还是Jetbrains没有产品,反正现在Android Studio里查看错误信息成了一个非常艰难的事。每次有人找我求助,我都得教一遍他们如何查看错误信息。

哪些窗口会有错误信息

在Android Studio的底部有一排的Panel,错误信息可能出现在 Build ,也可能出现在 Run 中。

不管是哪个Panel,都是有多个Tab的。最重要的是必须注意到,Build 总是有 Build OutputSync 两个Tab。

在本文中,我们用以下方式来表示这几个界面:

  • View | Tool Windows | Run

  • View | Tool Windows | Build | Build Output

  • View | Tool Windows | Build | Sync

什么情况下看哪个Panel

既然上面3个位置都可能有错误信息,你完全可以每个地方看一遍。

View | Tool Windows | Run

如图,通过 View | Tool Windows | Gradle | Run Gradle Task 这种方式执行的任意Gradle命令,输出都会出现在 View | Tool Windows | Run

同时,用这种方式执行过的gradle命令,idea会创建一个 Run Configurations,后续点击 Run 按钮执行这个的输出也还在同样的位置。

View | Tool Windows | Build

执行Android的Run Configurations就会出现在这个Panel。特别的是,IDE的Sync过程的输出,会在 View | Tool Windows | Build | Sync, 其他的输出都在 View | Tool Windows | Build | Build Output

更加迷惑的行为

Tab的两种视图

每个Tab,有两种视图,一种是树状视图,一种是纯文本视图。

默认会展示 树状视图。这个视图必须点击到具体某项,才会在右边显示错误信息。很多情况下,这里会展示一些警告(红色文字)而不展示最关键的错误信息。

使用这个按钮进行切换视图,可以到原始的文字错误信息。这里的输出就是Gradle的原始输出。

自动弹出 View | Tool Windows | Build

Android Studio有个傻缺行为是,执行任何Gradle的任务之后,都会附带一次自动的Sync操作。所以Studio会主动跳到 View | Tool Windows | Build | Sync 窗口。

你必须注意,如之前所说,如果你是通过 link::通过 View | Tool Windows | Gradle | Run Gradle Task 执行的[Run Gradle Task]调用的gradle,它的输出不会出现在这个窗口。

错误信息不够充分

如果你试着找过了上文所说的每一个窗口,试过了每一个Tab,也切换了Tab的视图分别查看过纯文本和树形视图。那就

这里给出一些获取更多信息的方法。

项目源码问题

项目源码编译过程中发现的语法错误、不正确引用等,这类项目里源码的问题,错误信息一般都在输出的日志里,并且都是以ERROR级别输出。

这类问题,因为都是由Gradle调用的外部程序发现的(如javac,aapt,dex,proguard),所以最后的Exception不会包含任何有用信息。 请不要只看最后的异常,你需要往前翻日志来发现问题 。 javac,aapt,dex,proguard等外部程序往往会将错误信息以ERROR级别输出到日志。

与很多人的常识相反的事,这类问题你应该尽可能的关闭Gradle的日志输出,而不是让gradle输入更详细的日志。如果你开启了--info参数,你应该删掉这个参数;你甚至可以使用 --quiet 参数来关闭任何干扰输出(ERROR级别在quiet也会输出)来定位问题。

使用--info之后的输出日志一般能达到数MB,你能在这么多信息里找到一行毫不起眼的aapt的错误信息吗?

Gradle Plugin问题或Gradle Bug

另一类问题是由于一些Gradle Plugin自身错误引起,有可能是build.gradle中配置的问题,也可能是plugin的bug。这类问题正好与前一节项目源码的问题相反。 定位问题的原因往往需要关注最后的Exception,如果Exception缺乏信息,就需要使用 '--info' 甚至 '--debug' 开启更详细的日志输出。

使用 --stacktrace 等参数

在使用 View | Tool Windows | Gradle | Run Gradle Task 执行的时候,你是可以直接增加参数 --stacktrace 的,最后输出的信息就会有出错栈信息。

但是对 下图的这种,以及 Sync,是不奏效的。

你如果想这种情况也有栈信息,需要在 link::jetbrains://idea/settings?name=Build%2C+Execution%2C+Deployment—​Compiler[Preferences | Build, Execution, Deployment | Compiler] 中增加参数。只有这里的是对Sync以及Android Build Configurations生效的。

远程调试

TBD

Read more

Git Tips

Git Proxy

Git Over HTTP(s)

想让Git使用代理拉取代码,通过设置http.proxy变量来实现目的。可以通过环境变量,也可以使用git config来让它生效。

可以参考:https://gist.github.com/evantoli/f8c23a37eb3558ab8765

在诊断git的网络问题时,可以通过设置 GIT_CURL_VERBOSE 变量来开启网络请求的详细日志输出,如:

GIT_CURL_VERBOSE=2 git pull
env GIT_CURL_VERBOSE=2 git pull

不过要知道的是,git一般有https和ssh两种访问方式,上述的配置代理以及诊断的方法都只适用于https协议的remote。

Git Over ssh

在git的remote是通过ssh方式访问的时候,既不使用http.proxy变量,也不使用curl进行网络请求。ssh协议(应用层协议为ssh)无法使用http代理(仅支持应用层协议为http的数据)来代理。要想代理ssh协议的请求,就必须:

通过ssh协议在应用层代理

既然http代理能代理http,那ssh代理也能代理ssh,也就是ssh tunnel。可参考:https://askubuntu.com/questions/311447/how-do-i-ssh-to-machine-a-via-b-in-one-command

通过socks协议在TCP层代理

socks协议(应用层协议)具备代理任何传输层(tcp,udp等)层数据的能力。所以如果代理服务器支持socks协议,就可以代理ssh请求。这时候需要拦截tcp请求,转发到socks代理。一般转发tcp数据是通过一个virtual network interface及iptable规则实现。更高级的实现可以直接使用netcat(nc)。上面的通过ssh协议实际上也是通过nc把数据从tcp转发到ssh tunnel.

Read more

Gradle实现Task没有源码时强制报错

Gradle Slack中有人提问,如何实现,在task因为没有源码输入(即NO—SOURCE)时,强制报错,而不是跳过执行task。

这个可以通过 org.gradle.api.execution.TaskExecutionListener 来实现。范例如下:

gradle.taskGraph.addTaskExecutionListener(new TaskExecutionListener() {
    @Override
    void beforeExecute(Task task) {

    }

    @Override
    void afterExecute(Task task, TaskState state) {
        if (state.noSource && task.name == "foo") {
            throw new IllegalArgumentException("task foo has no source!")
        }
    }
})

Read more

Annotations Processing in Gradle Multi-Project Build

在通常情况下,一个gradle项目往往由多个project组成,也就是multi-project build。

以一个android项目为例:

Example Multi-project Build
├ app/
├ build.gradle
├── feature/
├── build.gradle
└ settings.gradle

在使用一些注解处理工具时,如dagger2、room等,注解的使用可能存在于任意的project中。但最终注解处理,需要在最顶层的app项目中,一些特定的类必须在app中生成,并且生成时也必须能获取到依赖的project feature中的注解。

但实际上,JSR 269描述的注解处理并不能处理如此复杂的场景。编译时 注解处理是运行在代码编译(javac)阶段,而在Gradle的multi-project build中,多个project之前的依赖传递,使用的是已经编译的classes.jar。这在根本上造成了gradle multi-project build与APT的不兼容。

Read more

如何清理Mac磁盘空间

清理的原因

  1. 硬盘不够用

  2. 电脑运行时会产生大量的垃圾,并且其中很大部分不会被自动删除

下面是典型的几种产生不会自动被删除的数据的原因:

.1. App被卸载了,但配置、数据和缓存没有被删除

Read more

如何使用Gradle API获取项目的依赖信息

有时我们会想开发一个插件或者gradle script获取当前项目的依赖。在不了解gradle的api的情况下,可能会用解析build.gradle文件的笨办法方式去分析,但其实这种方式很不靠谱。

Gradle本身提供了全面的API获取项目的依赖信息,利用这个API,你可以查询:

  1. 用户在build.gradle里声明的显式依赖

  2. 因为传递依赖(transitive dependency)被隐式引入的依赖

  3. 经过解析后,最终被采用的依赖

  4. 经过解析后,解析失败的依赖

Read more