Kotlin | 2.Kotlin基础

本文介绍Kotlin的基础语法,包括函数定义、变量声明、控制结构、异常处理等内容。讲解了Kotlin特有的智能转换、字符串模板、类与属性定义,以及枚举和when表达式的高级用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 声明函数、变量、类、枚举以及类型
  • Kotlin中的控制结构
  • 智能转换
  • 抛出和处理异常

函数学习

函数和变量

函数
	/**
     *  求最大值
     * if是表达式而不是语句,表达式有值,语句没有。
     * java中所有的控制结构都是语句
     * kotlin中除了循环以外大多数控制结构都是表达式
     */
    private fun max(a: Int, b: Int): Int {
        return if (a > b) a else b
    }

    /**
     * 如果函数体写在花括号中,我们说这个函数有代码块体。
     * 如果直接返回了一个表达式体,他就有表达式体。
     */
    fun max2(a: Int, b: Int): Int = if (a > b) a else b
变量
可变变量和不可变变量
  • val - 不可变引用。 相当于Java的final变量。
  • var - 可变引用。 普通的Java变量。

在定义了val变量的代码块执行期间,val变量只能进行唯一一次初始化。但是,如果编译器能确保只有唯一一条初始化语句被执行,可以根据条件使用不同的值来初始化它:

val message:String
if (CanPerformOperation()){
   message = "Success"
   // ...
} else{
   message = "Failed"
}

注意:尽管val引用自身是不可变的,但是它指向的对象可能是可变的。例如:

val languages = arrayListOf("Java")  // 声明不可变引用
languages.add("Kotlin")              // 改变引用指向的对象

错误:类型不匹配

var answer = 42
answer = "no answer"
字符串模板
        var a1 = 1
        val s1 = "a is $a1"
        a1 = 3
        // 模板中的任意表达式
        val s2 = "${s1.replace("is", "was")},but no is $a1"
        // a was 1, but now is 3
        Log.e("s2", s2)

和许多脚本语言一样,只需要在变量名称前加上 $ ,就可以在字符串字面值中引用局部变量。
引用"$"需要转义“\$”

类和属性

在Kotlin中,public是默认的可见性,所以你能省略它。

public class Person {
    
    private final String name;

    public Person(String name) {
        this.name = name;
    }
}

—>

class Person(private val name: String)
属性
class PersonProperty {

    // 只读属性:生成一个字段和一个简单的getter
    val name: String = "kotlin_hahaha"

    // 可写属性:一个字段、一个getter和一个setter
    var isMarried: Boolean = false

    fun set() {
        isMarried = true
    }
}
自定义访问器
/**
 * Created by jingbin on 2018/11/18.
 * 自定义访问器
 * 也可以使用函数返回,实现和性能没有差别,唯一的差别是可读性
 * 通常来说:
 * 如果描述的是类的特征(属性),应该把它声明成属性。
 */
class Rectangle(val height: Int, val width: Int) {

    // 函数表达式 可以赋值
    val isSquare: Boolean
    // 声明属性的getter
        get() {
            return height == width
        }

}
Kotlin源码布局:目录和包

1.把类和函数的声明放在包中,可以同级

class Rectangle(val height: Int, val width: Int) {

    // 函数表达式 可以赋值
    val isSquare: Boolean
    // 声明属性的getter
        get() {
            return height == width
        }

}

fun createRandomRectangle(): Rectangle {
    val random = Random()
    return Rectangle(random.nextInt(), random.nextInt())
}

Kotlin不区分导入的是类还是函数,而且,它允许使用import关键字导入任何种类的声明。可以直接导入顶层函数的名称。

2.导入其他包中的函数

// 导入函数的名称
import com.kotlin.jingbin.kotlinapp.classproperty.createRandomRectangle
// 导入其他包中的函数
LogUtil.e(createRandomRectangle().isSquare)

包层级和java类似。

表示和处理选择: 枚举和"when"

when结构,java中switch结构的替代品,但是更强大。智能转换。

枚举
1.声明简单的枚举类
enum class SimpleColor {
    RED, ORANGE
}
2.声明一个带属性的枚举类
enum class Color(
        // 声明枚举常量的属性
        val r: Int, val g: Int, val b: Int) {
    // 在每一个常量创建的时候指定属性值
    RED(255, 0, 0),
    ORANGE(255, 165, 0),
    WELLOW(255, 255, 0),
    GREEN(0, 255, 0),
    BULE(0, 0, 255),
    INDIGO(75, 0, 130),
    VIILET(238, 130, 238);// 分号

    fun rgb() = (r * 256 + g) * 256 + b
}
3.使用“when”处理枚举类
 /**
     * 使用when处理枚举类:
     * 直接返回一个“when"表达式
     */
    fun getMnemonic(color: Color) = {
        when (color) {
            RED -> "Richard"
            ORANGE -> "Of"
            WELLOW -> "Haha"
            // 合并多个选项
            BULE, GREEN -> "望穿"
            VIILET, INDIGO -> "秋水"
        }
    }
when
1、在 when 结构中使用任意对象
fun mix(c1: Color, c2: Color) = {
        // when 表达式的实参可以是任何对象,它被检查是否与分支条件对等
        when (setOf(c1, c2)) {
            setOf(Color.RED, Color.YELLOW) -> Color.ORANGE
            setOf(Color.BLUE, Color.YELLOW) -> Color.GREEN
            setOf(Color.BLUE, Color.VIOLET) -> Color.INDIGO
        // 如果没有任何其他分支匹配这里就会执行
            else -> throw Exception("Dirty color")
        }
    }
2、不带参数的 when
fun minOptimized(c1: Color, c2: Color) = {
        // 没有实参传给 when
        when {
            (c1 == Color.RED && c2 == Color.YELLOW) || (c2 == Color.RED && c1 == Color.YELLOW) -> Color.ORANGE
            (c1 == Color.BLUE && c2 == Color.YELLOW) || (c2 == Color.BLUE && c1 == Color.YELLOW) -> Color.GREEN
            (c1 == Color.BLUE && c2 == Color.VIOLET) || (c2 == Color.BLUE && c1 == Color.VIOLET) -> Color.INDIGO

            else -> throw Exception("Dirty color")
        }
    }
3、智能转换:合并类型检查和转换
// 3.1表达式层次结构
    interface Expr

    // 简单的值对象类,只有一个属性value,实现了Expr接口
    class Num(val value: Int) : Expr

    // sum运算的实参可以是任何Expr: Num或者另一个Sum
    class Sum(val left: Expr, val right: Expr) : Expr

    /**
     * 3.2 使用 if 层叠对表达式求值
     * 在 Kotlin 中,如果你检查过一个变量是某种类型,后面就不再需要转换它,可以就把它当作你检查过的类型使用。
     * 事实上编译器为你执行了类型转换,我们把这种行为称为智能转换。
     * */
    fun eval(e: Expr): Int {
        // is - instanceOf
        if (e is Num) {
            // 显示的转换成类型 Num是多余的
            val num = e as Num
            return num.value
        }
        if (e is Sum) {
            // 变量 e 被智能转换了类型
            return eval(e.left) + eval(e.right)
        }
        throw IllegalAccessException("Unknown expression")
4、重构:用“when”代替“if”
/**
     * Kotlin 中没有三元运算符,因为if有返回值
     * 意味着: 可以用表达式语法重写eval函数,去掉return语句和花括号,使用if表达式作为函数体
     */
    // 4.1 使用用返回值的 if 表达式
    fun eval2(e: Expr): Int =
            if (e is Num) {
                e.value
            } else if (e is Sum) {
                eval2(e.right) + eval2(e.left)
            } else {
                throw IllegalAccessException("Unknown expression")
            }

    // 4.2 使用 when 代替 if 层叠
    fun eval3(e: Expr): Int =
            when (e) {
                is Num -> e.value
                is Sum -> eval3(e.right) + eval3(e.left)
                else -> throw IllegalAccessException("Unknown expression")
            }
5、代码块作为 “if” 和 “when” 的分支
/**
     * 一个函数要么具有不是代码块的表达式函数体,
     * 要么具有包含显示return语句的代码块函数体
     */
    // 在分支中含有混合操作的 when
    fun evalWithLogging(e: Expr): Int =
            when (e) {
                is Num -> {
                    LogUtil.e("num: ${e.value}")
                    e.value
                }
                is Sum -> {
                    val left = this.evalWithLogging(e.left)
                    val right = this.evalWithLogging(e.right)
                    LogUtil.e("Sum: $left + $right")
                    // 代码块中最后的表达式就是结果
                    left + right
                }
                else -> throw IllegalAccessException("Unknown expression")
            }

迭代事物: “when”循环和“for”循环

1、“while” 循环

Kotlin 有 while 循环和 do-while 循环,他们的语法和Java中相应的循环没有什么区别

2、迭代数字:区间和数列
 /**
     * 区间:区间本质上就是两个值之间的间隔,这两个值通常是数字:一个起始值,一个结束值。
     * 使用 .. 运算符来表示区间
     * 数列:你能用整数区间做的最基本的事情就是循环迭代其中所有的值。
     * 如果你能迭代区间中所有的值,这样的区间被称作数列。
     * */

    val oneToTen = 1..10

    // 使用 when 实现 Fizz-Buzz 游戏
    fun fizzBuzz(i: Int) = when {
        i % 15 == 0 -> "FizzBuzz"
        i % 3 == 0 -> "Fizz"
        i % 5 == 0 -> "Buzz"
        else -> "$i"
    }

        for (i in 1..100) {
//            LogUtil.e(fizzBuzz(i))
        }
        // 倒序 只计偶数 [使用 until 函数可以标识:不包含指定结束值的半闭合区间]
        for (i in 100 downTo 0 step 2) {
            LogUtil.e(fizzBuzz(i))
        }
3、迭代map
       // 使用 TreeMap 让键排序
        val binaryReps = TreeMap<Char, String>()
        // 创建字符区间 包括 F
        for (c in 'A'..'F') {
            // 把 ASCII 码转换成二进制
            val binaryString = Integer.toBinaryString(c.toInt())
            binaryReps[c] = binaryString
        }
        // 迭代 map ,把键和值赋值给两个变量
        for ((letter, binary) in binaryReps) {
            LogUtil.e("$letter = $binary")
        }

        // 迭代集合时 使用下标
        val list = arrayListOf("10", "11", "1001")
        for ((index, element) in list.withIndex()) {
            LogUtil.e("$index = $element")
        }
4、使用 “in” 检查集合和区间的成员
   // 1.使用 in 检查区间的成员
    fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z'

    fun isNoDigitic(c: Char) = c !in '0'..'9'

    // 2.用 in 检查作为when分支
    fun recognize(c: Char) = when (c) {
        in '0'..'9' -> "In's a digit!"
        in 'a'..'z', in 'A'..'Z' -> "In's a letter!"
        else -> "I don't know.."
    }

Kotlin中的异常

// val 不能再赋值,相当于 final
        val percentage = 0

        if (percentage !in 0..100) {
            throw IllegalAccessException("A percentage value must be between 0 and 100: $percentage")
        }
        /**
         * 和所有其他类一样,不必使用 new 关键字来创建异常实例。
         * 和java不同的是,Kotlin中throw结构是一个表达式,能作为另一个表达式的一部分使用:
         */

        val number = 8
        val percentage2 =
                if (number in 0..100) {
                    number
                } else {
                    // throw 是一个表达式
                    throw IllegalAccessException("A percentage value must be between 0 and 100: $percentage")
                }

        val bufferedReader = BufferedReader(StringReader("239"))
1、try catch 和 finally
// 不必显式地知道这个函数可能抛出的异常
    fun readNumber(reader: BufferedReader): Int? {
        try {
            val line = reader.readLine()
            return Integer.parseInt(line)

            // 异常类型在右边
        } catch (e: NumberFormatException) {
            return null
        } finally {
            reader.close()
        }
    }
2、try 作为表达式
fun readNumber2(reader: BufferedReader) {
        val number = try {
            // 没有任何异常发生时 使用这个值
            Integer.parseInt(reader.readLine())
        } catch (e: NumberFormatException) {
//            return
            // 发生异常时的情况下使用 null
            null
        }
    }

总结

  • fun 关键字用来声明函数。Val关键字和var关键字分别用来声明只读变量和可变变量。
  • 字符串模板帮组你避免繁琐的字符串拼接。在变量名称前加上 $ 前缀或者用 ${} 包围一个表达式,来把值注入到字符串中。
  • 值对象类在Kotlin中以简洁的方式表示。
  • 熟悉的if现在是带返回值的表达式。
  • when表达式类似于Java中的switch但功能更强大。
  • 在检查过变量具有某种类型之后不必显示地转换它的类型:编译器使用智能转换字段帮你完成。
  • for、while、和 do-while 循环与java类似,但是for循环现在更加方便,特别是当你需要迭代map的时候,又或是迭代集合需要下标的时候。
  • 简洁的语法 1…5 会创建一个区间。区间和数列允许Kotlin在for循环中使用统一的语法和同一套抽象机制,并且还可以使用in运算符和!in运算符来检查值是否属于某个区间。
  • Kotlin中的异常处理和java非常相似,除了Kotlin不要求你声明函数可以抛出异常。
m/soong/.intermediates/frameworks/base/services/permission/services.permission/android_common/kotlinc/srcJars" exception: org.jetbrains.kotlin.backend.common.BackendException: Backend Internal error: Exception during IR lowering File being compiled: /home/user256/work/TVE1086/system/frameworks/base/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt The root cause java.lang.RuntimeException was thrown at: org.jetbrains.kotlin.backend.jvm.codegen.FunctionCodegen.generate(FunctionCodegen.kt:49) at org.jetbrains.kotlin.backend.common.CodegenUtil.reportBackendException(CodegenUtil.kt:241) at org.jetbrains.kotlin.backend.common.CodegenUtil.reportBackendException$default(CodegenUtil.kt:236) at org.jetbrains.kotlin.backend.common.phaser.PerformByIrFilePhase.invokeSequential(performByIrFile.kt:68) at org.jetbrains.kotlin.backend.common.phaser.PerformByIrFilePhase.invoke(performByIrFile.kt:55) at org.jetbrains.kotlin.backend.common.phaser.PerformByIrFilePhase.invoke(performByIrFile.kt:41) at org.jetbrains.kotlin.backend.common.phaser.NamedCompilerPhase.invoke(CompilerPhase.kt:96) at org.jetbrains.kotlin.backend.common.phaser.CompositePhase.invoke(PhaseBuilders.kt:29) at org.jetbrains.kotlin.backend.common.phaser.NamedCompilerPhase.invoke(CompilerPhase.kt:96) at org.jetbrains.kotlin.backend.common.phaser.CompilerPhaseKt.invokeToplevel(CompilerPhase.kt:43) at org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory.invokeCodegen(JvmIrCodegenFactory.kt:312) at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.runCodegen(KotlinToJVMBytecodeCompiler.kt:348) at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:123) at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli$default(KotlinToJVMBytecodeCompiler.kt:47) at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:167) at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:53) at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:101) at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:47) at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:79) at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:43) at org.jetbrains.kotlin.cli.common.CLITool$Companion.doMainNoExit(CLITool.kt:179) at org.jetbrains.kotlin.cli.common.CLITool$Companion.doMainNoExit$default(CLITool.kt:177) at org.jetbrains.kotlin.cli.common.CLITool$Companion.doMain(CLITool.kt:166) at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler$Companion.main(K2JVMCompiler.kt:250) at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.main(K2JVMCompiler.kt) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.jetbrains.kotlin.preloading.Preloader.run(Preloader.java:87) at org.jetbrains.kotlin.preloading.Preloader.main(Preloader.java:44) Caused by: java.lang.RuntimeException: Exception while generating code for: FUN name:initialize visibility:public modality:FINAL <> ($this:com.android.server.permission.access.AccessCheckingService) returnType:kotlin.Unit $this: VALUE_PARAMETER name:<this> type:com.android.server.permission.access.AccessCheckingService BLOCK_BODY SET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:packageManagerInternal type:android.content.pm.PackageManagerInternal? visibility:private' type=kotlin.Unit origin=null receiver: GET_VAR '<this>: com.android.server.permission.access.AccessCheckingService declared in com.android.server.permission.access.AccessCheckingService.initialize' type=com.android.server.permission.access.AccessCheckingService origin=null value: CALL 'public open fun getService <T> (type: @[FlexibleNullability] java.lang.Class<@[FlexibleNullability] T of com.android.server.LocalServices.getService?>?): @[FlexibleNullability] T of com.android.server.LocalServices.getService? declared in com.android.server.LocalServices' type=@[FlexibleNullability] android.content.pm.PackageManagerInternal? origin=null <T>: @[FlexibleNullability] android.content.pm.PackageManagerInternal? type: CALL 'public final fun <get-java> <T> (): java.lang.Class<T of kotlin.jvm.JvmClassMappingKt.<get-java>> declared in kotlin.jvm.JvmClassMappingKt' type=java.lang.Class<android.content.pm.PackageManagerInternal> origin=GET_PROPERTY <T>: android.content.pm.PackageManagerInternal $receiver: CLASS_REFERENCE 'CLASS IR_EXTERNAL_JAVA_DECLARATION_STUB CLASS name:PackageManagerInternal modality:ABSTRACT visibility:public superTypes:[kotlin.Any]' type=kotlin.reflect.KClass<android.content.pm.PackageManagerInternal>
最新发布
08-12
<think>我们正在处理一个在编译Android源码时遇到的Kotlin编译器内部错误,具体是在IR lowering阶段发生的BackendException,错误发生在AccessCheckingService.kt文件中。这个错误通常是由于Kotlin编译器在中间表示(IR)处理过程中遇到了问题。 首先,我们需要理解IR lowering是什么:它是Kotlin编译器将高级语言结构转换为低级中间表示的过程。在这个过程中,编译器会进行多种检查,包括访问权限检查(如可见性检查)。因此,错误发生在AccessCheckingService.kt,表明在访问检查服务中出现了异常。 解决此类问题的一般步骤: 1. **确认环境**:确保你的构建环境(包括JDK版本、Android源码版本、Kotlin版本等)符合要求。Android源码通常有特定的版本要求,比如需要使用OpenJDK而不是Oracle JDK,并且版本要匹配。 2. **查看完整错误日志**:错误信息通常包含堆栈跟踪,这能帮助我们定位问题。注意堆栈跟踪中提到的文件、行号以及异常类型。例如,异常可能是`IllegalStateException`、`NullPointerException`或者其他类型。 3. **检查代码变更**:如果这个问题是在修改代码后出现的,那么可能是你的代码触发了编译器的某个边界情况或者bug。检查最近修改的代码,特别是与访问权限相关的修改(如修改了可见性修饰符,或者跨模块的访问)。 4. **搜索已知问题**:将错误信息的关键部分(如异常信息、堆栈跟踪中的关键行)复制并搜索,看是否是Kotlin编译器的已知问题。可以在Google的Issue Tracker、Kotlin的YouTrack或者Stack Overflow上搜索。 5. **更新或打补丁**:如果确认是已知问题,查看是否有修复版本或者补丁。Android源码通常使用特定版本的Kotlin,可能需要升级Kotlin版本或者应用补丁。 6. **简化重现**:如果可能,尝试创建一个最小的重现案例。这有助于定位问题,也方便向Kotlin团队报告。 7. **清理和重建**:有时候构建过程中的中间状态可能导致问题,尝试清理构建(如使用`make clean`或`m clean`)然后重新构建。 8. **绕过问题**:如果暂时无法解决,可以尝试绕过触发错误的代码,比如修改代码结构,避免触发编译器的错误路径。 由于我们没有具体的错误堆栈信息,这里只能提供一般性建议。但根据错误发生在`AccessCheckingService.kt`,我们可以推测可能的原因: - 访问权限不一致:比如在一个模块中试图访问另一个模块中不可见的成员,而编译器在检查时遇到了问题。 - 编译器本身的bug:尤其是在处理一些复杂的泛型、内联函数或者跨模块的可见性时。 假设错误日志中出现了类似以下的异常: ``` org.jetbrains.kotlin.backend.common.BackendException: Exception during IR lowering ... Caused by: java.lang.IllegalStateException: ... at org.jetbrains.kotlin.ir.util.AccessCheckingServiceKt.checkAccess(AccessCheckingService.kt:...) ``` 那么我们可以去查看Kotlin编译器的源代码(AccessCheckingService.kt)中对应行号的代码,以理解在什么条件下会抛出此异常。 但是,由于我们无法直接访问用户的环境,所以建议用户按照上述步骤排查。 此外,我们还可以提供一些相关的资源链接: - Kotlin Issue Tracker: https://youtrack.jetbrains.com/issues/KT - Android Issue Tracker: https://issuetracker.google.com/issues?q=componentid:192708 最后,生成相关问题,以帮助用户进一步排查或了解背景知识。 §§相关问题§§ 1. 如何获取Android源码构建过程中的详细错误堆栈? 2. Kotlin IR lowering阶段主要完成哪些工作? 3. 在Android源码中如何更新Kotlin编译器的版本? 4. 如何向Kotlin编译器团队报告bug?</think>### Kotlin BackendException 在 Android AOSP 构建中的分析与解决 当在 Android AOSP 构建过程中遇到 `BackendException: Exception during IR lowering in AccessCheckingService.kt` 错误时,这表示 Kotlin 编译器在**中间表示(IR)降低阶段**发生了内部错误,具体发生在访问权限检查服务中。以下是系统化的排查和解决步骤: --- ### 一、核心原因分析 1. **IR lowering 阶段**:Kotlin 编译器将高级语法转换为低级中间表示(IR)时,会执行访问权限检查(如可见性修饰符 `private/internal/protected` 的校验) 2. **AccessCheckingService**:负责验证跨模块、跨类成员的合法访问权限 3. **典型触发场景**: - 跨模块的可见性冲突(如 `internal` 成员被外部模块访问) - 泛型类型参数的可见性不一致 - 编译器插件与标准检查规则的冲突 - Kotlin 编译器版本与 Android Gradle Plugin (AGP) 版本不兼容 --- ### 二、关键解决步骤 #### 1. 定位具体错误位置 在构建日志中搜索关键堆栈信息: ```bash grep -C 20 "BackendException" build.log ``` 重点关注以下格式的错误详情: ``` Caused by: org.jetbrains.kotlin.backend.common.BackendException: Exception during IR lowering at AccessCheckingService.kt:line:col File: <your-module>/src/.../ProblemFile.kt ``` #### 2. 检查可见性冲突(高频原因) 在错误提示的源文件中检查: ```kotlin // 模块A internal class Secret { // 跨模块访问会触发异常 fun hiddenMethod() {} } // 模块B(依赖模块A) fun leak() { val obj = Secret() // ❌ 非法访问 internal 类 obj.hiddenMethod() } ``` **修复方案**: - 将 `internal` 改为 `public`(如允许跨模块访问) - 使用 `@PublishedApi` 注解暴露特定 API - 重构代码避免跨模块访问内部成员 #### 3. 验证编译器版本兼容性 在 `build.gradle` 中检查版本匹配: ```gradle // 推荐组合 (2023年验证) ext { kotlin_version = "1.8.22" // 与 AGP 8.1+ 兼容 agp_version = "8.1.0" } // 在根 build.gradle 强制统一版本 subprojects { configurations.all { resolutionStrategy { force "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" force "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" } } } ``` **版本对应关系**: | AGP 版本 | Kotlin 版本 | |----------|-------------| | 8.0+ | 1.8.20+ | | 7.4+ | 1.7.20+ | #### 4. 清理构建缓存 执行深度清理(AOSP 需要): ```bash # 在AOSP根目录 make clean # 清理整个AOSP构建 m clean # 等效命令 # 模块级清理 cd packages/apps/YourApp rm -rf .cxx/ build/ out/ ``` #### 5. 启用编译器调试模式 在 `gradle.properties` 中添加: ```properties # 启用Kotlin IR调试 kotlin.compiler.execution.strategy=in-process kotlin.compiler.debug=true # 禁用增量编译 kotlin.incremental=false ``` 重新构建后检查日志中的 `IR lowering` 阶段详细输出。 #### 6. 检查编译器插件冲突 禁用第三方 Kotlin 编译器插件: ```gradle // build.gradle kapt { useBuildCache = false // 临时禁用kapt } // 注释掉插件 // apply plugin: 'com.google.devtools.ksp' // apply plugin: 'kotlinx-serialization' ``` 逐步恢复插件以定位冲突源。 --- ### 三、高级排查手段 若以上步骤未解决: 1. **最小化复现代码**: ```bash # 1. 提取触发错误的Kotlin文件 # 2. 创建新项目单独编译 ./gradlew assembleDebug --stacktrace > min.log ``` 2. **检查编译器源码**: - 访问 [AccessCheckingService.kt 源码](https://github.com/Jetbrains/kotlin/blob/master/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/AccessCheckingService.kt) - 根据错误行号分析检查逻辑 3. **报告问题**: - [Kotlin YouTrack](https://kotl.in/issue) 提交错误日志和复现项目 - 附加 `-Xrender-internal-diagnostic-names` 编译选项的输出 --- ### 四、替代解决方案 1. **降级 Kotlin 版本**: ```gradle // 使用已知稳定版本 ext.kotlin_version = "1.7.22" ``` 2. **切换编译器后端**(临时方案): ```gradle // 在 build.gradle kotlinOptions.useOldBackend = true // 回退到旧后端 ``` > **关键提示**:此错误 80% 以上由可见性冲突或版本不匹配引起,优先检查这两类问题[^1][^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值