如何在 Android 项目中使用 Kotlin 工作表
我想在我的 Android 项目中使用 Kotlin 工作表 ,以便添加如下代码草稿:
draft.ws.kts
package com.example.app
val a = 1 + 1
a
工作表本身可以正常工作:
val a: Int
2
但是构建我的 Android 应用失败,并显示以下输出:
> Task :appicals:compileDebugKotlin FAILED
e: org.jetbrains.kotlin.util.KotlinFrontEndException: Front-end Internal error: Failed to analyze declaration Draft_ws
File being compiled: (1,43) in /Users/me/secretproject/app/src/main/java/com/example/app/draft.ws.kts
The root cause org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException was thrown at: org.jetbrains.kotlin.resolve.lazy.BasicAbsentDescriptorHandler.diagnoseDescriptorNotFound(AbsentDescriptorHandler.kt:18)
at org.jetbrains.kotlin.resolve.ExceptionWrappingKtVisitorVoid.visitDeclaration(ExceptionWrappingKtVisitorVoid.kt:43)
at org.jetbrains.kotlin.psi.KtVisitorVoid.visitDeclaration(KtVisitorVoid.java:453)
at org.jetbrains.kotlin.psi.KtVisitorVoid.visitDeclaration(KtVisitorVoid.java:21)
at org.jetbrains.kotlin.psi.KtVisitor.visitScript(KtVisitor.java:78)
at org.jetbrains.kotlin.psi.KtVisitorVoid.visitScript(KtVisitorVoid.java:73)
at org.jetbrains.kotlin.psi.KtVisitorVoid.visitScript(KtVisitorVoid.java:519)
at org.jetbrains.kotlin.psi.KtVisitorVoid.visitScript(KtVisitorVoid.java:21)
at org.jetbrains.kotlin.psi.KtScript.accept(KtScript.java:69)
at org.jetbrains.kotlin.psi.KtElementImplStub.accept(KtElementImplStub.java:59)
at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer$analyzeDeclarations$1.registerDeclarations(LazyTopDownAnalyzer.kt:78)
at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer$analyzeDeclarations$1.visitKtFile(LazyTopDownAnalyzer.kt:96)
at org.jetbrains.kotlin.psi.KtVisitorVoid.visitKtFile(KtVisitorVoid.java:513)
at org.jetbrains.kotlin.psi.KtVisitorVoid.visitKtFile(KtVisitorVoid.java:21)
at org.jetbrains.kotlin.psi.KtFile.accept(KtFile.kt:242)
at org.jetbrains.kotlin.psi.KtFile.accept(KtFile.kt:229)
at org.jetbrains.kotlin.resolve.ExceptionWrappingKtVisitorVoid.visitElement(ExceptionWrappingKtVisitorVoid.kt:27)
at org.jetbrains.kotlin.com.intellij.psi.PsiElementVisitor.visitFile(PsiElementVisitor.java:34)
at org.jetbrains.kotlin.psi.KtVisitor.visitKtFile(KtVisitor.java:73)
at org.jetbrains.kotlin.psi.KtVisitorVoid.visitKtFile(KtVisitorVoid.java:69)
at org.jetbrains.kotlin.psi.KtVisitorVoid.visitKtFile(KtVisitorVoid.java:513)
at org.jetbrains.kotlin.psi.KtVisitorVoid.visitKtFile(KtVisitorVoid.java:21)
at org.jetbrains.kotlin.psi.KtFile.accept(KtFile.kt:242)
at org.jetbrains.kotlin.psi.KtFile.accept(KtFile.kt:229)
at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer.analyzeDeclarations(LazyTopDownAnalyzer.kt:201)
at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer.analyzeDeclarations$default(LazyTopDownAnalyzer.kt:60)
at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:112)
at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:82)
at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:554)
at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:81)
at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:107)
at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:545)
at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:176)
at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:163)
at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:51)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:85)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:43)
at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:104)
at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:349)
at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:105)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileIncrementally(IncrementalCompilerRunner.kt:237)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.access$compileIncrementally(IncrementalCompilerRunner.kt:37)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner$compile$2.invoke(IncrementalCompilerRunner.kt:79)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:91)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:606)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:99)
at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1645)
at sun.reflect.GeneratedMethodAccessor182.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:357)
at sun.rmi.transport.Transport$1.run(Transport.java:200)
at sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException: Descriptor wasn't found for declaration SCRIPT
at org.jetbrains.kotlin.resolve.lazy.BasicAbsentDescriptorHandler.diagnoseDescriptorNotFound(AbsentDescriptorHandler.kt:18)
at org.jetbrains.kotlin.resolve.lazy.BasicAbsentDescriptorHandler.diagnoseDescriptorNotFound(AbsentDescriptorHandler.kt:17)
at org.jetbrains.kotlin.resolve.lazy.LazyDeclarationResolver.findClassDescriptor(LazyDeclarationResolver.kt:88)
at org.jetbrains.kotlin.resolve.lazy.LazyDeclarationResolver.getScriptDescriptor(LazyDeclarationResolver.kt:65)
at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer$analyzeDeclarations$1.visitScript(LazyTopDownAnalyzer.kt:89)
at org.jetbrains.kotlin.psi.KtVisitorVoid.visitScript(KtVisitorVoid.java:519)
at org.jetbrains.kotlin.psi.KtVisitorVoid.visitScript(KtVisitorVoid.java:21)
at org.jetbrains.kotlin.psi.KtScript.accept(KtScript.java:69)
at org.jetbrains.kotlin.psi.KtElementImplStub.accept(KtElementImplStub.java:59)
at org.jetbrains.kotlin.resolve.ExceptionWrappingKtVisitorVoid.visitDeclaration(ExceptionWrappingKtVisitorVoid.kt:32)
... 61 more
依赖项是
implementation "org.jetbrains.kotlin:kotlin-script-runtime:1.3.70"
编辑(2021-04-11):这是一个丑陋的临时解决方案,没有存在的权利。请阅读 我更闪亮、更新、更好的 答案。
不确定这是否算是一个很好的答案,因为它不仅完全修复了它,而且它的要点是...更改文件扩展名。只需在末尾添加下划线或其他内容即可。
OMFSM 我花了 这么长时间 试图找到一种正确的方法来做到这一点。然后尝试了一百万种不同的临时解决方案。而且我之前甚至没有遇到过这个问题(老实说我甚至不知道工作表的存在),这看起来像是一个好主意。
有几种方法可以使它更容易,但无论何时你想要构建它仍然需要人工干预(或者你可以将它们关闭直到你再次需要它们)。
我个人刚刚创建了几个批处理文件(虽然它们每个都只有一个命令),重命名所有.kts 文件(然后将它们重命名回来)并创建了一些方便的快捷方式。我运行的是 Windows,而 Bash 脚本绝对不在我的技能范围内,因此我相信这也可以在 *nix 上完成。
要重命名它们,使它们不会尝试进行编译:
forfiles /S /M *.ws.kts /C "cmd /c ren @file @fname.kts_"
并将它们重新转换为有效的工作表:
forfiles /S /M *.ws.kts_ /C "cmd /c ren @file @fname.kts"
要从其中一个创建批处理文件:
- 打开记事本
- 将其中一行复制到其中。
-
转到
文件 >保存
,导航到保存项目的文件夹并为其指定一个文件名, 用双引号 (") 括起来, 以 .bat 结尾- 例如 “disable_worksheets.bat” 和 “enable_worksheets.bat” ,但 请确保包含双引号 。
现在,您只需在 Windows 资源管理器中找到该文件,然后双击它即可一次禁用或启用它们。
如果您愿意,您还可以在 Android Studio 中制作一个宏来以每种方式执行此操作,但据我所知,它一次只能更改一个文件(尽管您可以设置键盘快捷键,因此如果您没有太多工作表,它可以工作)。要制作宏以禁用工作表:
- 在树视图中选择您的工作表文件左侧
-
在菜单栏中,转到
编辑 > 宏
并单击“ 开始宏录制 ” -
在树视图中右键单击工作表,然后在
重构
菜单下单击“ 重命名文件... ” - 按键盘上的 End 键
- 输入下划线 _
- 按 Enter
-
在菜单栏中,转到
编辑 >宏
并单击“ 停止宏录制 ” - 为宏命名并单击 确定
要重新启用它:
- 在左侧的树视图中选择您的工作表文件
-
在菜单栏中,转到
编辑 > 宏
并单击“ 开始宏录制 ” -
在树视图中右键单击您的工作表,然后在
重构
菜单下单击“ 重命名... ” - 按键盘上的 End
- 按 Backspace
- 按 Enter
-
在菜单栏中,转到
编辑 >宏
并点击“ 停止宏录制 ” - 为宏命名并点击 确定
现在您只需在树视图中选择一个文件,然后在菜单中转到
编辑 > 宏
并单击所需的宏。但为了更方便,您可以设置键盘快捷键。操作方法:
-
在菜单栏中,转到
文件
并单击“ 设置... ” - 在左侧菜单中,单击“ 键盘映射 ”
- 在编辑器的主窗格中,单击“ 宏 ”旁边的 ► 以展开该部分
- 右键单击要为其设置快捷方式的宏,然后单击“ 添加键盘快捷键 ”
-
按下要使用的快捷键的键(例如
Ctrl + 逗号
)。如果快捷键已经使用了这些键,它会发出警告,因此您可能需要使用几个修饰键(例如
Ctrl + Shift + G
)
- 我发现一些默认情况下为空(至少在我的安装中)并且仅使用 Ctrl 作为修饰键的键是 Ctrl + 逗号 (,)、 Ctrl + 分号 (;) 和 Ctrl + 反斜杠 (\)。
- 大多数数字键盘键都未使用,但显然它们不太方便。
- 单击 确定 返回主设置窗口。
- 如果您想为其他宏设置快捷方式,只需重复步骤 4-6
- 单击设置窗口底部的 确定 。
设置完这些后,您要做的就是单击左侧树视图中的文件名并按下键盘快捷键。
希望这些对大家有帮助!如果这篇文章有点长,请见谅,简洁也不符合我的技能。
TL;DR:IntelliJ 对此提供了很好的支持。Android Studio 将其隐藏。
1:通过在项目树中单击鼠标右键并选择 New ► Scratch File 或按 Ctrl+Alt+Shift+Insert 并从出现的列表中选择 Kotlin 来创建新文件。
它将这些存储在 IDE 的配置文件夹中,因此 Gradle 不会接近它们,但编辑器中为每个文件提供了一个简单的设置,以使用打开项目的类路径。这也意味着它们在项目之间共享。
2:在左侧的项目视图中,在顶部,单击 Android 并选择 Project 。它们将位于底部名为 Scratches and Consoles ► Scratches 的文件夹中,然后打开您的工作表。现在您可以切换回 Android 视图。
3:责怪 Google。
长话短说:
好吧,我尝试了一下,并做了更多研究 - 我可能一开始就应该这样做 - IntelliJ 支持此功能(从外观上看,支持得相当好),但 Android Studio 将其隐藏了。
IntelliJ 将它们称为临时文件(听起来很正确)。它们存储在 IDE 的设置文件夹中(在我的情况下为 %APPDATA%\Google\AndroidStudio4.1\scratches ),因此 Gradle 甚至看不到它们。由于存储在 IDE 的设置中,因此它们也是全局的,而不是特定项目的一部分,因此您可以从任何项目访问它们。
要创建一个,请在左侧的项目工具窗格中的任意位置单击鼠标右键,然后选择 新建 ► 临时文件 或按 Ctrl+Alt+Shift+Insert 。这将打开一个语言菜单,对我来说似乎默认为 Kotlin(可能是因为我打开的项目是 Kotlin 的),选择该菜单后,只需按 Enter 键即可。这将在编辑器中将文件作为选项卡打开,左侧显示代码,右侧显示结果。在顶部有一个名为 使用模块的类路径 的选项,右侧有一个下拉菜单,您可以在当前打开的项目中选择一个模块(您知道,用于使用项目测试内容)。
默认情况下,文件名为 scratch.kts (或者如果您有多个,则为 scratch_1.kts 、 scratch_2.kts 等。如果需要,您可以通过右键单击编辑器窗口中的选项卡并选择 重命名文件... 来重命名它。
这是重要的一点:
在 Android Studio 中,项目树的默认范围(默认情况下,窗口左侧的工具窗格)设置为 Android 。如果您点击它并选择 Project 。在底部会有一个名为 Scratches and Consoles 的文件夹,其中包含一个子文件夹名为 Scratches 。瞧!您的暂存文件就在那里。显然,在通用项目视图中,您会丢失所有 Android 细节,因此您现在可以切换回来,只需记住如何返回即可。如果有办法让它们显示出来,我找不到它(但如果您现在还不知道,我不是专业的 Android 程序员,只是一个有太多空闲时间的聪明人)。