无法分配局部变量,因为它是在外部定义的

时间:2014-11-18 18:41:59

标签: android variables boolean local final

我正在编写一个静态方法,并且我遇到了从内部方法访问变量的问题。我在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;
}

3 个答案:

答案 0 :(得分:1)

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

所以,这是第一个例子:

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

这不会编译,因为您无法在匿名类的方法中引用非final变量。将final修饰符添加到a的声明时,a的值将被复制到已定义的匿名类的已创建实例中。但是,您将不被允许更改a的值,因为声明的方法不会显示更改。

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

int a = 3;

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

此示例进行编译,每次调用匿名类'实例的run()方法时,它将增加3。 (在这个例子中,它永远不会被调用,但它只是一个例子。)

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

更新:在Java 8中,引入了有效最终变量的概念(请参阅Java语言规范)。但是,在这篇文章的第一个例子中,变量a被多次分配,这使它无法成为最终的。这意味着此示例仍然无法使用Java 8进行编译。(编译错误是“在封闭范围中定义的局部变量必须是最终的或有效的最终”)

答案 1 :(得分:0)

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

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个问题。

答案 2 :(得分:0)

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();

if(!ret)        返回true;    其他        返回false; }

因为您只将其设置为false,所以您无需更改它。