Android Fragments 创建时出现java.lang.NoSuchMethodException异常

3pmvbmvn  于 2022-12-19  发布在  Android
关注(0)|答案(7)|浏览(386)

我在Google Play崩溃日志中看到崩溃,这真的让我很难理解。

java.lang.RuntimeException: 
  at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3086)
  at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:3229)
  at android.app.servertransaction.LaunchActivityItem.execute (LaunchActivityItem.java:78)
  at android.app.servertransaction.TransactionExecutor.executeCallbacks (TransactionExecutor.java:108)
  at android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:68)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1926)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loop (Looper.java:214)
  at android.app.ActivityThread.main (ActivityThread.java:6981)
  at java.lang.reflect.Method.invoke (Native Method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:493)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1445)
Caused by: androidx.fragment.app.Fragment$InstantiationException: 
  at androidx.fragment.app.Fragment.instantiate (Fragment.java:462)
  at androidx.fragment.app.FragmentContainer.instantiate (FragmentContainer.java:50)
  at androidx.fragment.app.FragmentState.instantiate (FragmentState.java:80)
  at androidx.fragment.app.FragmentManagerImpl.restoreAllState (FragmentManager.java:3109)
  at androidx.fragment.app.FragmentController.restoreAllState (FragmentController.java:158)
  at androidx.fragment.app.FragmentActivity.onCreate (FragmentActivity.java:344)
  at androidx.appcompat.app.AppCompatActivity.onCreate (AppCompatActivity.java:85)
  at com.autotask.jbarra.kotlinmvvm.MainActivity.onCreate (MainActivity.kt:102)
  at android.app.Activity.performCreate (Activity.java:7326)
  at android.app.Activity.performCreate (Activity.java:7317)
  at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1271)
  at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3066)

Caused by: java.lang.NoSuchMethodException: 
  at java.lang.Class.getConstructor0 (Class.java:2328)
  at java.lang.Class.getConstructor (Class.java:1725)
  at androidx.fragment.app.Fragment.instantiate (Fragment.java:443)

问题是,主活动的第102行没有什么特别的

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState) //This is line 102

是什么原因造成的?为什么oncreate没有抛出这样的方法?它发生在一些用户的设备上,我还没有能够重现它。

xtupzzrd

xtupzzrd1#

正在从示例状态绑定还原该活动。还原操作的一部分是重新创建其片段。
您的Activity具有片段,而片段类没有框架所需的0-arg构造函数。

q0qdq0h2

q0qdq0h22#

我也有同样的问题。其他的答案没有帮助。
对我来说,它看起来像是Proguard。这解释了为什么它只发生在生产/发布构建中,以及为什么我在调试时一直无法重现它。
如果您遇到OP的问题,请尝试以下操作:
1.构建模糊的. apk。我使用了签名的,我发布到应用程序商店...
1.在设备的开发者选项中启用“不保留活动”。
1.在您的设备中安装.apk,然后打开崩溃并包含Fragment的Activity。
1.离开你的应用(最小化/主屏幕按钮/...),然后从最近使用的应用菜单中重新打开它。
它崩溃了吗?那就用没有混淆的调试版本试试。如果没有,那可能是Proguard。
为了修复它,我做了以下操作:
1.在proguard-rules.pro应用模块的根文件夹中创建www.example.com文件。

  1. Add -keep class * 将androidx.fragment.app.Fragment{}扩展到该文件。
    1.然后,在应用的build.gradle中,
    增加:
buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

见雅罗斯拉夫Mytkalyk的答案在这里:Fragment Instantiation crash,它帮助我解决了这个问题,尽管它现在有点旧和过时(例如,“runProfuard true”已经过时)。
至少现在当我执行上面的步骤时,它不会崩溃。

  • PS:我是在向我的片段添加0-arg构造函数的同时完成的,正如在其他答案中提到的,因为那是我第一次尝试修复。我相信只有Proguard才是问题所在,没有必要添加所述构造函数,但我现在无法验证这个假设。*
ljo96ir5

ljo96ir53#

我的Activity有一个使用废弃构造函数的FragmentPagerAdapter

class MyPagerAdapter(
        fragmentManager: FragmentManager,
        private val myActivity: MyActivity
    ) : FragmentPagerAdapter(fragmentManager) // DEPRECATED

class MyPagerAdapter(
        fragmentManager: FragmentManager,
        private val myActivity: MyActivity
    ) : FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)

似乎已经解决了问题

tkqqtvp1

tkqqtvp14#

经过一番搜索,我终于解决了这个问题。你必须检查三件事。
1.片段中应该有一个0-arg构造函数,最佳实践是执行类似下面这样的操作
1.如果在调用者中使用回调,则必须检查getContext是否为null(否则将获得NullPointerException)
1.不要忘记在屏幕方向改变时测试用例,这将允许您重现由于恢复片段状态而导致的一些潜在问题
示例代码示例:

public class MyDialogFragment extends DialogFragment{
     private String id;

     public static MyDialogFragment newInstance(String id) {
        MyDialogFragment f = new MyDialogFragment ();

        Bundle args = new Bundle();
        if(id!= null){
            args.putString("id", id);
        }
        f.setArguments(args);

        return f;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(savedInstanceState != null){
            id= savedInstanceState.getString("id");
        }
    }
    }
mrwjdhj3

mrwjdhj35#

如前所述,问题在于Fragment中缺少0-arg构造函数。
在我的例子中,通过版本变体的代码收缩从DialogFragment中删除了构造函数。
要重现崩溃,请使用minifyEnabled true构建应用程序,弹出DialogFragment并旋转设备屏幕。
保留0-arg构造函数的一个简单解决方案是添加一个@Keep注解:

public class MyDialogFragment extends DialogFragment {
    @Keep
    public MyDialogFragment() {}
}
3pvhb19x

3pvhb19x6#

对于Kotlin,下面是一个有问题的构造函数语法以及如何重写它的示例。第一行是构造函数,它有一个参数。这导致了getConstructor0在应用关闭时崩溃,Android试图恢复它:

open class MyFragment(parent: MyClass) : Fragment() {
    var parent = parent
}

下面的重写避免了崩溃。第一行是0参数构造函数,第二行是自定义构造函数:

open class MyFragment : Fragment() {
    constructor(parent: MyClass): this() {
        this.parent = parent
    }

    lateinit var parent: MyClass
}

当你示例化类MyFragment(parent)时,它的工作原理和以前一样。但是,当Android恢复应用时,它将调用MyFragment(),因此你需要考虑使用未初始化变量运行的类。如果需要,你可以检查this::parent.isInitialized
与其将问题描述为“您需要一个0参数的构造函数”,我更容易理解为“在创建片段时不能传递参数(除非您准备不设置该参数)”。
我花了一段时间才理解这一点,因为我的大多数片段类都没有参数,我也看不出我做错了什么。但我有一个子片段的子片段,我已经设置了一个参数。这个类名没有显示在Google Play控制台的崩溃日志中,但当我按照this answer的说明重现这个问题时,它确实显示在Android Studio控制台中,然后这一点终于变得清晰起来。
Google Play崩溃日志只显示了这一点:

Caused by java.lang.NoSuchMethodException:

但Android Studio控制台显示了这一点,其中崩溃发生在FormList类中:

Caused by: java.lang.NoSuchMethodException: com.arlomedia.bandhelper.superclasses.FormList.<init> []

另一种设计方法可能更适合你的情况。在我的例子中,变量是一个对象,所以我不能保存它,也不能从捆绑包中恢复它。我不想让它成为可选的,因为当应用正常运行时,它总是会被设置。而且我的应用无论如何都会在重新启动后重新加载界面,所以我只需要在不崩溃的情况下完成Android的恢复尝试。

kmbjn2e3

kmbjn2e37#

由于缺少片段的零参数构造函数,系统无法还原片段。
在所有片段中添加一个零参数构造函数可以解决这个问题。

public YourFragment() {}

相关问题