我正在编写一个静态方法,并且我遇到了从内部方法访问变量的问题。我在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;
}
答案 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,所以您无需更改它。