2014-11-18 3 views
1

Я пишу статический метод, и я испытываю проблемы с доступом к переменной из внутреннего метода. Я получаю следующее сообщение об ошибке в 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

попробуйте использовать только декларацию: (т.е. final boolean ret = false;) и не устанавливайте его во внутренних методах. – Martin

+0

Я получаю эту ошибку в 'ret = false;', а не в 'final boolean ret; ' – smartmouse

+0

№. см. мой ответ ниже – Martin

ответ

1

что метод-локальные переменные из охватывающего типа фактически копируются в экземпляры анонимных классов (это из-за проблем с кадрами активации, но я не буду углубляться подробно, поскольку это не имеет отношения к вопросу), что почему они должны быть окончательными, поскольку переменная в экземпляре вложенного типа не то же самое.

Итак, вот первый пример:

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

Это не компилируется, потому что вы не можете ссылаться на неконечное переменную в методе анонимного класса. Когда вы добавляете окончательный модификатор в объявление a, значение a будет скопировано в созданный экземпляр анонимного класса, который вы определили. Однако вам не будет позволено изменять значение a, потому что изменения не будут видны методу, в котором было объявлено.

Однако анонимные классы не являются статичными, то есть, у них есть ссылка на ограждающий экземпляр (если только метод, при котором они объявлены не статичен), которые вы можете использовать, чтобы изменить переменные вмещающие например:

int a = 3; 

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

В этом примере выполняется компиляция, и она будет увеличиваться на 3 каждый раз, когда вызывается метод run() экземпляра анонимного класса. (В этом примере это никогда не вызывается, но это просто пример.)

Итак, чтобы суммировать, вам нужно преобразовать переменную seatno из локальной локальности метода в переменную экземпляра охватывающего типа. Или, если это так, вам нужно удалить последний модификатор, поскольку конечные переменные могут быть назначены только один раз.

Обновление: на Java 8 введена концепция эффективных конечных переменных (см. Спецификацию языка Java). Однако в первом примере этого сообщения переменная a назначается несколько раз, что предотвращает ее окончательную окончательность. Это означает, что этот пример до сих пор не компилируется с Java 8. (Ошибка компиляции: «Локальная переменная a, определенная в охватывающей области, должна быть окончательной или эффективной окончательной»)

+0

Я добавляю 'boolean ret = false;' в начале класса (до метода), но я получаю следующую ошибку: 'Не могу сделать статическую ссылку на нестатическое поле ret' – smartmouse

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 вопросы для другого примера.

+0

Я могу 't использовать это решение, мне просто нужно проверить переменную «ret». – smartmouse

+0

Вы производите архитектуру своего кода. Метод выполнит весь код и вернет false до того, как пользователь сможет нажать кнопку в диалоговом окне. Единственный способ получить значение при отображении * асинхронного * диалогового окна с обратными вызовами или вызовами методов внутри прослушивателей кликов. В документах [Android docs] (http://developer.android.com/guide/topics/ui/dialogs.html) очень хорошо написано, как показывать диалоги и отвечать на ввод пользователя. – kevskree

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

если (! Ret) return true; else return false; }

Поскольку вы устанавливаете только значение false, вам не нужно его менять.

Смежные вопросы