开发者问题收集

如何在 Android 项目中使用 Kotlin 工作表

2020-03-11
2067

我想在我的 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"

2个回答

编辑(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"

要从其中一个创建批处理文件:

  1. 打开记事本
  2. 将其中一行复制到其中。
  3. 转到 文件 >保存 ,导航到保存项目的文件夹并为其指定一个文件名, 用双引号 (") 括起来, 以 .bat 结尾
    • 例如 “disable_worksheets.bat” “enable_worksheets.bat” ,但 请确保包含双引号

现在,您只需在 Windows 资源管理器中找到该文件,然后双击它即可一次禁用或启用它们。

如果您愿意,您还可以在 Android Studio 中制作一个宏来以每种方式执行此操作,但据我所知,它一次只能更改一个文件(尽管您可以设置键盘快捷键,因此如果您没有太多工作表,它可以工作)。要制作宏以禁用工作表:

  1. 在树视图中选择您的工作表文件左侧
  2. 在菜单栏中,转到 编辑 > 宏 并单击“ 开始宏录制
  3. 在树视图中右键单击工作表,然后在 重构 菜单下单击“ 重命名文件...
  4. 按键盘上的 End
  5. 输入下划线 _
  6. Enter
  7. 在菜单栏中,转到 编辑 >宏 并单击“ 停止宏录制
  8. 为宏命名并单击 确定

要重新启用它:

  1. 在左侧的树视图中选择您的工作表文件
  2. 在菜单栏中,转到 编辑 > 宏 并单击“ 开始宏录制
  3. 在树视图中右键单击您的工作表,然后在 重构 菜单下单击“ 重命名...
  4. 按键盘上的 End
  5. Backspace
  6. Enter
  7. 在菜单栏中,转到 编辑 >宏 并点击“ 停止宏录制
  8. 为宏命名并点击 确定

现在您只需在树视图中选择一个文件,然后在菜单中转到 编辑 > 宏 并单击所需的宏。但为了更方便,您可以设置键盘快捷键。操作方法:

  1. 在菜单栏中,转到 文件 并单击“ 设置...
  2. 在左侧菜单中,单击“ 键盘映射
  3. 在编辑器的主窗格中,单击“ ”旁边的 以展开该部分
  4. 右键单击要为其设置快捷方式的宏,然后单击“ 添加键盘快捷键
  5. 按下要使用的快捷键的键(例如 Ctrl + 逗号 )。如果快捷键已经使用了这些键,它会发出警告,因此您可能需要使用几个修饰键(例如 Ctrl + Shift + G
    • 我发现一些默认情况下为空(至少在我的安装中)并且仅使用 Ctrl 作为修饰键的键是 Ctrl + 逗号 (,)、 Ctrl + 分号 (;) 和 Ctrl + 反斜杠 (\)。
    • 大多数数字键盘键都未使用,但显然它们不太方便。
  6. 单击 确定 返回主设置窗口。
  7. 如果您想为其他宏设置快捷方式,只需重复步骤 4-6
  8. 单击设置窗口底部的 确定

设置完这些后,您要做的就是单击左侧树视图中的文件名并按下键盘快捷键。

希望这些对大家有帮助!如果这篇文章有点长,请见谅,简洁也不符合我的技能。

Slashee the Cow
2021-03-14

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 程序员,只是一个有太多空闲时间的聪明人)。

Slashee the Cow
2021-04-11