我升级到 Android Studio 2.3.3,一个旧的、无错误的程序现在给出错误:“片段应该是静态的......”

Posted

技术标签:

【中文标题】我升级到 Android Studio 2.3.3,一个旧的、无错误的程序现在给出错误:“片段应该是静态的......”【英文标题】:I upgraded to Android Studio 2.3.3 and an old, bug-free program now gives error: "Fragments should be static..." 【发布时间】:2018-01-25 04:17:50 【问题描述】:

错误全文为:

C:\Users\Dov\Google Drive\androidStudioProjects\FlagQuiz - Copy (2)\app\src\main\java\com\dslomer64\flagquiz\QuizFragment.java

Error: Fragments should be static such that they can be re-instantiated by the system, and anonymous classes are not static [ValidFragment]

更糟糕的是,它并没有告诉我错误在哪一行。我已经假设,因为上面提到过,QuizFragment 有错,但是怎么办?所以我得出结论,提到QuizFragment 只是为了表明错误所在的类。

另外,请注意,没有任何行被标记为黄色方块所示的错误。

在下面不完整的代码段中,我在 cmets 的 3 个地方发现了“匿名”一词。

DialogFragment quizResults = new DialogFragment() // anonymously **********    
                       // extend DialogFragment class

  @Override public Dialog onCreateDialog(Bundle bundle)
   
    ...
     AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
     builder.setPositiveButton
     (
        R.string.reset_quiz,
        new DialogInterface.OnClickListener()
        
            public void onClick(DialogInterface dialog, int id)
             
                resetQuiz(); 
             
          // end anonymous inner class *******************
     ); 
     return builder.create(); // return the AlertDialog

   // end method onCreateDialog

; // end DialogFragment anonymous inner class ****************

DialogFragment quizResults = new DialogFragment() 或包含匿名内部类的 builder 的定义是否有问题(从 AS 2.3.3 开始;升级前没有任何问题)?

如果是这样,为什么没有编译错误?在这种情况下,我该如何解决这个问题?

(我不想只是开始修改我没有编写的代码 [我收到了作者的项目并进行了许多修改],因为至少有 3 个可以想象的起点,也许没有一个可以解决错误(s ?)。

【问题讨论】:

我回复了这个问题,因为修订版 1 是一个很好的规范问题,可能对未来的读者有用。如果您还有其他疑问,那么最好将它们添加为新问题,而不是在旧问题上编辑添加内容。祝你好运! 【参考方案1】:

升级前没有任何问题

很可能,有。 Android Studio 之前没有抱怨您的代码,但它可能无法正常工作。不同的是,现在 Android Studio 会指出问题所在,而不是您在测试中找出困难的方法。

有什么问题吗... DialogFragment quizResults = new DialogFragment()

是的。无法重新创建片段。

因此,当用户旋转屏幕、更改区域设置、启动夜间模式或任何其他可能的配置更改时,当 Android 销毁片段并尝试重新创建它时,它就无法做到。只有您问题中的代码行可以重新创建片段,并且这些代码行是您的,而不是框架的,并且它不知道它们。

您可能通过android:configChanges 阻止活动的普通销毁和重新创建循环来解决此问题。这本身通常是一种反模式,但如果您合法地需要 android:configChanges 并正确使用它,您应该能够抑制此 Lint 错误。

在这种情况下,我该如何解决这个问题?

quizResults 创建一个常规Java 类,扩展DialogFragment 并包含您的代码。然后,使用那个 Java 类。

【讨论】:

哦,对不起,你忍了我! @CommonsWare,我从第一句话就知道是你。或者也许是黄色突出显示。无论如何,谢谢你再来一次棉花采摘时间。 @DavidRawson:抱歉,我们提交的时间差不多。如果我晚点过来,我就会对你的答案投赞成票并继续前进。 @CommonsWare 没问题 - 我认为这两个答案都有帮助 是的,两者都有很大帮助。【参考方案2】:

错误的部分如下:

DialogFragment quizResults = new DialogFragment() 

    @Override
    public Dialog onCreateDialog(Bundle bundle) 

您在其中定义DialogFragment 的匿名子类。这是 Android 2.3.3 中新的 lint 检查所建议的使用 Fragments 的错误方式。

为什么?如果您使用的是 Activity 的FragmentManager,那么像这样实例化 Fragment 会导致问题。

有问题的情况如下:当Activity#saveInstanceState(Bundle outState) 被调用时,FragmentManager 会尝试保存你的 Fragment 的状态。当随后恢复 Activity 的状态时,FragmentManager 将尝试重新创建您的片段(使用无参数构造函数)并将它们的状态设置为之前的状态。如果您使用 Fragment 的匿名子类,这是不可能的。

Henec,Fragment 必须有一个无参数构造函数,并且实例化它们的首选方法是使用静态工厂方法。代替匿名子类,使用Fragment#setArguments(Bundle bundle):

QuizFragment.java中:

public static QuizFragment instantiate(Bundle args) 
    QuizFragment frag = new QuizFragment();
    frag.setArguments(args);
    return frag;

【讨论】:

【参考方案3】:

我遇到了同样的问题。我将匿名 DialogFragment 类转换为常规类:

public  DialogFragment instantiate(Bundle args)  
 DialogFragment quizResults = new DialogFragment();

 quizResults.setArguments(args);
 Dialog aDialog = createDialog(args);
 aDialog.show();

 return quizResults;


// create an AlertDialog and return it 
public Dialog createDialog(Bundle bundle)
  AlertDialog.Builder builder =
   new AlertDialog.Builder(getActivity());
     builder.setCancelable(false);

     builder.setMessage(
     getResources().getString(
       R.string.results, totalGuesses, (1000 / (double) totalGuesses)));

    // "Reset Quiz" Button            
builder.setPositiveButton(R.string.reset_quiz,
 new DialogInterface.OnClickListener()
public void onClick(DialogInterface dialog,int id)

  resetQuiz();

 // end anonymous inner class
  ); // end call to setPositiveButton

return builder.create(); // return the AlertDialog
 // end method createDialog

onClick(View v)下的原始代码块:

///////////////////////////////////////////////////////////////////
 DialogFragment quizResults = new DialogFragment()
  
    // create an AlertDialog and return it
    @Override
    public Dialog onCreateDialog(Bundle bundle)
    
       AlertDialog.Builder builder =
          new AlertDialog.Builder(getActivity());
          builder.setCancelable(false);

          builder.setMessage(
          getResources().getString(R.string.results, totalGuesses, (1000 / (double) totalGuesses)));

          // "Reset Quiz" Button
          builder.setPositiveButton(R.string.reset_quiz,
             new DialogInterface.OnClickListener()
             
                public void onClick(DialogInterface dialog, int id)
                
                   resetQuiz();
                
              // end anonymous inner class
           ); // end call to setPositiveButton

          return builder.create(); // return the AlertDialog
        // end method onCreateDialog

已替换为调用以实例化 DialogFragment,如下所示:

    DialogFragment quizResults = instantiate(mSavedInstanceState);   

【讨论】:

【参考方案4】:

感谢@Commonsware 和@David Rawson,我设法通过将编译器抱怨的任何内容更改为static,使其与static 内部类一起工作static,其中包括多种方法以及许多(每个?) 变量。

这带来了一个问题:

public static void loadNextFlag() 
    
...
    // display current question number--2nd and 3rd parameters are INPUT into the xml statement

    questionNumberTextView.setText
         (correctAnswers + 1) + //was ,
         "/" + FLAGS_IN_QUIZ);

     //        AssetManager assets = getActivity().getAssets();

...
 // end method loadNextFlag

格式化questionNumberTextView的行必须改为

questionNumberTextView.setText(
                              (""  + (correctAnswers + 1) 
                               "/" + FLAGS_IN_QUIZ);

因为原来

questionNumberTextView.setText(getResources().getString
             (R.string.question,
             (correctAnswers + 1),
              FLAGS_IN_QUIZ);

给出了getResources 的静态与非静态错误。我只是选择了一种不太好的格式,但很合适。

我还让assets 一个全局的static 变量在onCreateView 中只分配一次。

因此,教科书并不总是正确地做到这一点,因为这样做会使文本的水平远远超出预期的受众。

【讨论】:

以上是关于我升级到 Android Studio 2.3.3,一个旧的、无错误的程序现在给出错误:“片段应该是静态的......”的主要内容,如果未能解决你的问题,请参考以下文章

android studio Gradle升级到3.5.0遇到的坑

更新至Android Studio 2.3.3中的gradle 3.2.1无效

解决升级到Android Studio4.2问题汇总

在 IONIC 项目中升级到电容器 3 后,Android Studio 构建失败

Android Studio 升级中的“未找到默认活动”

无法识别启动活动:升级到 Android Studio 4.0 后未找到默认活动