【问题标题】:Can't assign local variable because it is defined in outside无法分配局部变量,因为它是在外部定义的
【发布时间】:2014-11-18 18:41:58
【问题描述】:

我正在编写一个静态方法,但在从内部方法访问变量时遇到了问题。我在 Eclipse 中收到以下错误:

最终的局部变量 ret 不能赋值,因为它是在封闭类型中定义的

这是我的代码:

public static boolean noInternetAlertDialog(Context ctx) {
    final boolean ret;

    AlertDialog.Builder builder;
    builder = new AlertDialog.Builder(ctx);
    builder.setCancelable(false);
    builder.setTitle("Error");
    builder.setMessage("Connection error");

    builder.setPositiveButton("Retry", new DialogInterface.OnClickListener(){
        @Override
        public void onClick(DialogInterface dialog, int which)
        {
            dialog.dismiss();
            ret = false;
        }
    });

    builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.dismiss();
            ret = false;
        }
    });         
    AlertDialog dialog = builder.create();
    dialog.show();

   if (ret)
       return true;
   else
       return false;
}

【问题讨论】:

  • 仅使用声明尝试一下:(即 final boolean ret=false;)并且不要在你的内部方法中设置它
  • 我在ret = false; 收到此错误,而不是在final boolean ret;
  • 没有。请看下面我的回答

标签: android variables boolean local final


【解决方案1】:

关键是封闭类型的方法局部变量实际上被复制到匿名类的实例中(这是因为激活框架问题,但我不会进一步详细说明,因为这与问题无关),这就是为什么它们需要是 final 的,因为嵌套类型实例中的变量已经不一样了。

所以,这是第一个例子:

void foo() {
    int a = 3;
    new Runnable() {
        @Override
        public void run() {
            a += 3;
        }
    };
}

这不会编译,因为您不能在匿名类的方法中引用非最终变量。当您在 a 的声明中添加 final 修饰符时,a 的值将被复制到您定义的匿名类的创建实例中。但是,您将不能更改 a 的值,因为更改对声明 a 的方法是不可见的。

但是,匿名类不是静态的,也就是说,它们具有对封闭实例的引用(除非声明它们的方法是静态的),您可以使用它来修改封闭实例的变量:

int a = 3;

    void foo() {
        new Runnable() {
            @Override
            public void run() {
                a += 3;
            }
        };
    }

这个例子确实可以编译,每次调用匿名类实例的 run() 方法时,它都会增加 3。 (在这个例子中它从来没有被调用过,但这只是一个例子。)

因此,总而言之,您需要将变量 seatno 从方法局部变量转换为封闭类型的实例变量。或者,如果还没有,则需要删除 final 修饰符,因为 final 变量只能分配一次。

更新:在 Java 8 中,引入了有效最终变量的概念(请参阅 Java 语言规范)。然而,在这篇文章的第一个例子中,变量 a 被多次赋值,这阻止了它实际上是最终的。这意味着该示例仍然无法使用 Java 8 编译。(编译错误是“在封闭范围内定义的局部变量 a 必须是最终的或有效的最终”)

【讨论】:

  • 我确实在课程的开头(方法之前)添加了boolean ret = false;,但我收到以下错误:Cannot make a static reference to the non-static field ret
【解决方案2】:

您正在混合同步和异步代码。您的布尔方法将执行所有代码并在显示对话框之前返回。相反,您需要提供回调或调用单击侦听器内部的方法。像这样的...

public static void showNoInternetDialog(Context context) {
//setup here.
    builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {

            userTappedCancel();
        }
    });  

}

private static void userTappedCancel()
{
   //Do whatever you want here
}

您也需要对setPositiveButton() 执行相同的操作。请参阅 this questions 以获取不同的示例。

【讨论】:

  • 我不能使用这个解决方案,我只需要验证“ret”变量。
  • 您正在以一种无法使用的方式构建代码。在用户能够点击对话框中的按钮之前,该方法将执行所有代码并返回 false。显示 异步 对话框时获取值的唯一方法是在点击侦听器中使用回调或调用方法。 Android docs 在解释如何显示对话框和响应用户输入方面做得非常好。
【解决方案3】:
public static boolean noInternetAlertDialog(Context ctx) {
final boolean ret = false;   //<+======== this

AlertDialog.Builder builder;
builder = new AlertDialog.Builder(ctx);
builder.setCancelable(false);
builder.setTitle("Error");
builder.setMessage("Connection error");

builder.setPositiveButton("Retry", new DialogInterface.OnClickListener(){
    @Override
    public void onClick(DialogInterface dialog, int which)
    {
        dialog.dismiss();
        // =====>    you don't need this - ret = false;
    }
});

builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        dialog.dismiss();
        // =====>    you don't need this - ret = false;
    }
});         
AlertDialog dialog = builder.create();
dialog.show();

如果 (!ret) 返回真; 别的 返回假; }

由于你只是设置为false,所以不需要修改。

【讨论】:

    猜你喜欢
    • 2016-03-15
    • 2015-02-26
    • 2013-11-30
    • 2020-02-11
    • 1970-01-01
    • 1970-01-01
    • 2016-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多