I upgraded to Android Studio 2.3.3 and an old, bug-free program now gives error: "Fragments should be static..."
I upgraded to Android Studio 2.3.3 and an old, bug-free program now gives error: "Fragments should be static..."
错误全文为:
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
只是为了指出错误在哪个 class 中。
另外请注意,没有任何行被标记为黄色方块所示的错误。
我在下面不完整的代码段的注释中的 3 个地方找到了 "anonymous" 这个词。
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()
或包含匿名内部 class 的 builder
的定义是否有问题(从 AS 2.3.3 开始;升级前没有任何问题)?
如果是这样,为什么没有编译错误?在这种情况下,我该如何解决这个问题?
(我不想开始破解我没有写的代码 [我从作者那里收到了项目并做了很多修改] 因为至少有 3 个可以想象的起点,也许 none 解决错误。
错误的部分如下:
DialogFragment quizResults = new DialogFragment() {
@Override
public Dialog onCreateDialog(Bundle bundle) {
您在其中定义 DialogFragment
的匿名子类。这是 错误的 使用 Fragments 的方式,正如 Android 2.3.3.
中新的 lint 检查所建议的那样
为什么?如果您使用 Activity 的 FragmentManager
,像这样实例化 Fragments 会导致问题。
问题情况如下:当调用 Activity#saveInstanceState(Bundle outState)
时,FragmentManager
将尝试保存片段的状态。当随后恢复 Activity 的状态时,FragmentManager
将尝试重新创建您的片段(使用无参数构造函数)并将它们的状态设置为之前的状态。如果您使用 Fragment 的匿名子类,这是不可能的。
Henec,片段必须有一个无参数的构造函数,并且实例化它们的首选方法是使用静态工厂方法。使用 Fragment#setArguments(Bundle bundle)
:
而不是匿名子类
里面QuizFragment.java:
public static QuizFragment instantiate(Bundle args) {
QuizFragment frag = new QuizFragment();
frag.setArguments(args);
return frag;
}
nothing was wrong before upgrade
很可能有。 Android Studio 之前并没有抱怨您的代码,但它可能无法正常工作。不同的是,现在 Android Studio 会指出问题,而不是您在测试中发现困难。
Is there something wrong... with DialogFragment quizResults = new DialogFragment()
是的。无法重新创建片段。
因此,当用户旋转屏幕、更改区域设置、启动夜间模式或任何其他可能的配置更改时,当 Android 销毁片段并尝试重新创建它时,它可以't。只有您问题中的代码行才能重新创建片段,而这些代码行是您的,而不是框架的,并且它不知道它们。
您可能已经通过 android:configChanges
阻止 activity 的普通销毁和重建循环来解决此问题。这本身通常是一种反模式,但如果您合法地需要 android:configChanges
并正确使用它,您应该能够抑制此 Lint 错误。
And in this case, how do I fix the problem?
为 quizResults
创建一个常规 Java class,扩展 DialogFragment
并包含您的代码。然后,使用 Java class.
感谢@Commonsware 和@David Rawson,我通过将编译器抱怨的任何内容更改为 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
中分配一次。
所以教科书并不总是正确的,因为这样做会使文本的水平远远超出目标受众。
我运行遇到了同样的问题。我将匿名 DialogFragment class 转换为常规 class :
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);
错误全文为:
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
只是为了指出错误在哪个 class 中。
另外请注意,没有任何行被标记为黄色方块所示的错误。
我在下面不完整的代码段的注释中的 3 个地方找到了 "anonymous" 这个词。
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()
或包含匿名内部 class 的 builder
的定义是否有问题(从 AS 2.3.3 开始;升级前没有任何问题)?
如果是这样,为什么没有编译错误?在这种情况下,我该如何解决这个问题?
(我不想开始破解我没有写的代码 [我从作者那里收到了项目并做了很多修改] 因为至少有 3 个可以想象的起点,也许 none 解决错误。
错误的部分如下:
DialogFragment quizResults = new DialogFragment() {
@Override
public Dialog onCreateDialog(Bundle bundle) {
您在其中定义 DialogFragment
的匿名子类。这是 错误的 使用 Fragments 的方式,正如 Android 2.3.3.
为什么?如果您使用 Activity 的 FragmentManager
,像这样实例化 Fragments 会导致问题。
问题情况如下:当调用 Activity#saveInstanceState(Bundle outState)
时,FragmentManager
将尝试保存片段的状态。当随后恢复 Activity 的状态时,FragmentManager
将尝试重新创建您的片段(使用无参数构造函数)并将它们的状态设置为之前的状态。如果您使用 Fragment 的匿名子类,这是不可能的。
Henec,片段必须有一个无参数的构造函数,并且实例化它们的首选方法是使用静态工厂方法。使用 Fragment#setArguments(Bundle bundle)
:
里面QuizFragment.java:
public static QuizFragment instantiate(Bundle args) {
QuizFragment frag = new QuizFragment();
frag.setArguments(args);
return frag;
}
nothing was wrong before upgrade
很可能有。 Android Studio 之前并没有抱怨您的代码,但它可能无法正常工作。不同的是,现在 Android Studio 会指出问题,而不是您在测试中发现困难。
Is there something wrong... with DialogFragment quizResults = new DialogFragment()
是的。无法重新创建片段。
因此,当用户旋转屏幕、更改区域设置、启动夜间模式或任何其他可能的配置更改时,当 Android 销毁片段并尝试重新创建它时,它可以't。只有您问题中的代码行才能重新创建片段,而这些代码行是您的,而不是框架的,并且它不知道它们。
您可能已经通过 android:configChanges
阻止 activity 的普通销毁和重建循环来解决此问题。这本身通常是一种反模式,但如果您合法地需要 android:configChanges
并正确使用它,您应该能够抑制此 Lint 错误。
And in this case, how do I fix the problem?
为 quizResults
创建一个常规 Java class,扩展 DialogFragment
并包含您的代码。然后,使用 Java class.
感谢@Commonsware 和@David Rawson,我通过将编译器抱怨的任何内容更改为 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
中分配一次。
所以教科书并不总是正确的,因为这样做会使文本的水平远远超出目标受众。
我运行遇到了同样的问题。我将匿名 DialogFragment class 转换为常规 class :
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);