非法访问错误:该方法对类不可访问。

8

我遇到了一个非常奇怪的错误,因为它只会在安装了从生成的.apk文件中安装的应用程序后发生。当我尝试通过IDE运行该应用程序时,它可以正常工作。

java.lang.IllegalAccessError: Method 'int <package>.BaseActivity$Companion.getANIMATION_SLIDE_FROM_RIGHT()' is inaccessible to class '<package>.MyActivity' (declaration of '<package>.MyActivity' appears in /data/app/<package>-mg7eYmJ8hX5WvkNWNZWMVg==/base.apk!classes3.dex)

如您所看到的,这里有一个名为 BaseActivity 的类,它的代码如下:

open class BaseActivity : AppCompatActivity() {

    companion object {
        @JvmStatic
        protected val ANIMATION_DEFAULT = 0
        @JvmStatic
        protected val ANIMATION_SLIDE_FROM_RIGHT = 1
        @JvmStatic
        protected val ANIMATION_SLIDE_FROM_BOTTOM = 2
    }

    protected open var animationKind = ANIMATION_DEFAULT

    // Some other stuff
}

现在每个活动都扩展了这个类,并经常像这样覆盖animationKind

class MyActivity: BaseActivity() {

    override var animationKind = ANIMATION_SLIDE_FROM_RIGHT

    // Some other stuff
}

问题在于ANIMATION_SLIDE_FROM_RIGHT对于MyActivity不可访问。需要强调的是,这仅在手动生成的.apk上出现。有趣的是,我没有使用multidex,但错误似乎表明BaseActivityclasses3.dex中。以下是我的gradle文件:

应用插件:'com.android.application' 应用插件:'kotlin-android' 应用插件:'kotlin-android-extensions' 应用插件:'kotlin-kapt'

android {

    compileSdkVersion 28

    defaultConfig {
        applicationId <package>
        versionCode <versionCode>
        versionName <versionName>
        minSdkVersion 21
        targetSdkVersion 28
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    androidExtensions {
        experimental = true
    }
}

dependencies {

    // Dependencies
}

我尝试使用“multidexEnabled false/true”来进行操作,但唯一的变化是在“false”状态下,“classes3.dex”后缀消失了。
更新:
当我将“MyActivity”的“animationKind”属性更改为“1”时,一切都正常工作。
第二次更新:
删除“@JvmStatic”和受保护可见性后,它可以正常工作。

请查看https://dev59.com/s1YM5IYBdhLWcg3wfQIa#48781460 - Vinay Rathod
@VinayRathod 感谢提供链接。不幸的是,IDE 建议我使用 @JvmStatic,因为“在超类伴侣中保护非 JVM 静态成员的使用尚不受支持。” 当然,我可以改为 public,但它并没有告诉我问题出在哪里。 - Nominalista
@JvmStatic 更改为 @JvmField 会有所帮助吗? - yole
很不幸,只有@JvmStatic可以被编译。 - Nominalista
@Nominalista,请为我清理并重新构建它的工作。 - Vinay Rathod
@VinayRathod,你有没有尝试通过生成的.apk文件运行应用程序?在清理和重新构建之后,它无法正常工作。 - Nominalista
4个回答

11
官方 Kotlin 文档可知:

Java 允许从同一包中的其他类访问 protected 成员,而 Kotlin 不允许,则 Java 类对代码有更广泛的访问权。

因此,请确保您的 BaseActivityMyActivity 在同一个包中。
如果这两个 Activity 不在同一包中,则可以通过直接在 Studio 中运行来正常运行,但是如果您生成 APK 并尝试在设备上安装该 APK 运行时,就会崩溃(IllegalAccessError)。

它并没有说明实际问题是什么。此外,“伴生对象”和“protected”定义没有任何关系。如果我不想在扩展类之外共享这些字段怎么办? - Nominalista
你能证明一下protected只有在同一个包中的类之间才有效吗? - Nominalista
我的意思是,在 Kotlin 中,你只能在同一个包中访问受保护的字段,但我找不到相关信息。 - Nominalista
我是通过分析得出的结论,而并非官方声明。 - Vinay Rathod
在我的情况下,这是在Java->Kotlin转换期间发生的。文件在同一个包中。最后我尝试删除build、app/build和.idea,并执行“无效缓存并重启”,然后事情开始正常工作了。AndroidStudio 4.0.1,Kotlin版本1.4.10。当问题根本没有意义时,这通常似乎起作用。 - steven smith

1
虽然我不确定为什么会导致IllegalAccessError,但您应该像这样定义这些常量:
companion object {
    const val ANIMATION_DEFAULT = 0
    const val ANIMATION_SLIDE_FROM_RIGHT = 1
    const val ANIMATION_SLIDE_FROM_BOTTOM = 2
}

那应该解决了你的问题,否则使用@JvmField而不是@JvmStatic可能会是更好的选择。


如评论中所述,对于受保护的字段,只有@JvmStatic起作用。你说得对,在这种情况下,const val更好,但是如果它必须是受保护的呢? - Nominalista
当然 :) protected => @JvmStatic - Nominalista

1

确保你已经在相同的模块中声明了出现问题的方法,就像调用代码一样。

在我的情况下,我遇到了以下错误:

java.lang.IllegalAccessError: Method 'boolean[] my.package.common.kotlin.AndroidExtensionsKt.$jacocoInit()' is inaccessible to class 'my.package.ui.first.FirstActivity$viewModel$2' (declaration of 'my.package.ui.first.FirstActivity$viewModel$2' appears in /data/app/my.package.dev-fdHNodmdXHv-b_heK4MXeA==/base.apk!classes8.dex)
    at my.package.ui.first.FirstActivity$viewModel$2.invoke(FirstActivity.kt:18)
    at my.package.ui.first.FirstActivity$viewModel$2.invoke(FirstActivity.kt:14)
    at kotlin.UnsafeLazyImpl.getValue(Lazy.kt:81)
    at my.package.ui.first.FirstActivity.getViewModel(Unknown Source:11)
    at my.package.ui.first.FirstActivity.onCreate(FirstActivity.kt:23)

getViewModel()common模块中声明,而FirstActivityapp模块中声明:

inline fun <reified T : ViewModel> FragmentActivity.getViewModel(
    factory: ViewModelProvider.Factory = ViewModelProvider.NewInstanceFactory()
) = ViewModelProviders.of(this, factory).get(T::class.java)

getViewModel()common模块移动到app模块后,未发现任何问题。


2
删除关键字 inline 也可以解决这个错误。但是我想知道为什么我不能调用不同模块中的内联函数。 - BakaWaii
这在我们使用AGP 4.2.0-beta06时发生了,手动运行Gradle任务总是会给出“IllegalAccessError”错误,看起来需要进行报告。 - mochadwi
在jacoco中打开了一个问题:https://github.com/jacoco/jacoco/issues/1171,Google也在这里发表了评论:https://issuetracker.google.com/issues/171802602#comment5 - mochadwi
1
在 Google 问题跟踪器上评论旧问题可能不会得到任何结果。我已经为此提交了一个新问题。如果 @mochadwi 和其他人想要给它加个“星”,以帮助引起 Google 的注意,那就太好了。 https://issuetracker.google.com/issues/192636549 - Bradleycorn

0
open class BaseActivity : AppCompatActivity() {
    @JvmField
    protected val ANIMATION_DEFAULT = 0
    @JvmField
    protected val ANIMATION_SLIDE_FROM_RIGHT = 1
    @JvmField
    protected val ANIMATION_SLIDE_FROM_BOTTOM = 2

protected open var animationKind = ANIMATION_DEFAULT

// Some other stuff
}

这个怎么样?

我认为,Kotlin还没有完全支持伴生对象的jvm静态成员。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接