【问题标题】:Variable is accessed within inner class. Needs to be declared final在内部类中访问变量。需要宣布最终
【发布时间】:2013-01-03 18:02:00
【问题描述】:

我的onClick 内部出现编译错误。

这是代码。

public class fieldsActivity extends Activity {

Button addSiteButton;
Button cancelButton;
Button signInButton;


/**
 * Called when the activity is first created.
 */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // to create a custom title bar for activity window
    requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);

    setContentView(R.layout.fields);
    // use custom layout title bar
    getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.topbar);

    Pager adapter = new Pager();
    ViewPager mPager = (ViewPager) findViewById(R.id.fieldspager);
    mPager.setAdapter(adapter);
    mPager.setCurrentItem(1);



    addSiteButton = (Button) findViewById(R.id.addSiteButton);
    addSiteButton.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
           mPager.setCurrentItem(2, true); //Compilation error happens here.
        }


    });


    cancelButton = (Button) findViewById(R.id.cancel_button);
    signInButton = (Button) findViewById(R.id.sign_in_button);

}

【问题讨论】:

  • 如果您使用的是 Eclipse,那么您可以按下 Ctrl-1(在 OS X 上为 Cmd-1)并选择错误以查看快速修复,它会告诉您需要更改的内容。在此处查看更多信息:depth-first.com/articles/2008/01/11/…

标签: java android


【解决方案1】:

如果你不想让它成为最终的,你总是可以让它成为一个全局变量。

【讨论】:

  • @KevinZhao 全局变量在初始化后是否为最终变量?
  • @the_prole 我认为你可以在 Java 中使用 final,但我不确定你是否可以在构建 Android 应用程序时使用它,所以谷歌搜索可能是个好主意 :-)
  • 回想起来,如果可以避免使用全局变量,则不是一个好主意,除非您是初学者,在这种情况下,使用全局变量过度复杂化您的程序是很好的学习经验。 Here 是一篇很好的文章,解释了为什么全局变量是一个坏主意。
【解决方案2】:

您可以将变量声明为 final,或将其设为实例(或全局)变量。如果您将其声明为 final,您以后将无法更改它。

在方法中定义并由匿名内部类访问的任何变量都必须是 final 的。否则,您可以在内部类中使用该变量,而不知道如果内部类中的变量发生更改,然后稍后在封闭范围中使用,则内部类中所做的更改不会在封闭范围中持续存在。基本上,内部类中发生的事情都留在内部类中。

我写了更多in-depth explanation here。它还解释了为什么不需要将实例变量和全局变量声明为 final。

【讨论】:

    【解决方案3】:

    错误说明了一切,更改:

    ViewPager mPager = (ViewPager) findViewById(R.id.fieldspager);
    

    final ViewPager mPager = (ViewPager) findViewById(R.id.fieldspager);
    

    【讨论】:

    • 原因:如果两个方法看到相同的局部变量,Java 希望你发誓你不会改变它 - final,用 Java 说话。再加上没有引用参数,此规则确保仅在它们所属的方法中分配局部变量。代码因此更具可读性。
    • @ignis 我在addSiteButton.setOnClickListener(new View.OnClickListener() { 收到 NullPointerException 错误,您知道为什么会出现这种情况吗?
    • @PhDeOliveira NPE 通常在您对包含 null 的变量调用方法时抛出。 findViewById 可能正在返回 null。我不能说更多,不是Android程序员;我建议你打开一个单独的问题。当然,它与内部类、final、et similia 无关。
    • @ignis “如果两个方法看到相同的局部变量”,这在这个上下文中是不相关的。 OP 正在使用一个接口,Java 希望确保在其上执行“任务”时不会同时修改提供的对象。 “因此代码更具可读性。”这是一个明显的误导性句子。 Java 试图降低并发修改错误,而这个警告(或编译错误)与可读性无关。
    【解决方案4】:

    这是一个有趣的答案。

    您可以声明一个最终的单元素数组,然后显然可以随意更改数组的元素。我确信它打破了最初实现此编译器规则的原因,但是当您像我今天一样处于时间限制时它很方便。

    我实际上不能为这个申请功劳。这是 IntelliJ 的推荐!感觉有点hacky。但似乎没有全局变量那么糟糕,所以我认为这里值得一提。这只是解决问题的一种方法。不一定是最好的。

    final int[] tapCount = {0};
    
    addSiteButton.setOnClickListener(new View.OnClickListener() {
    
        @Override
        public void onClick(View v) {
           tapCount[0]++;
        }
    
    });
    

    【讨论】:

    • 在上述情况下,您不会更改引用的对象,而是更改数组内的内容。 link 有很好的解释。
    • 是的,我知道。似乎是解决该问题的一种技巧。感谢您的评论为其他人澄清。
    • 在这种情况下,在我看来全局变量更好......
    【解决方案5】:

    正如@Veger 所说,您可以将其设为final,以便该变量可以在内部类中使用。

    final ViewPager pager = (ViewPager) findViewById(R.id.fieldspager);
    

    我将其称为pager 而不是mPager,因为您在onCreate 方法中将其用作局部变量。 m 前缀通常保留给类成员变量(即,在类开头声明的变量,对所有类方法都可用)。

    如果您确实需要一个类成员变量,那么将其设为 final 是行不通的,因为您不能使用 findViewById 来设置它的值,直到 onCreate。解决方案是不使用匿名内部类。这样mPager 变量就不需要声明为final,并且可以在整个类中使用。

    public class MainActivity extends AppCompatActivity {
    
        private ViewPager mPager;
        private Button mButton;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            // ...
    
            mPager = (ViewPager) findViewById(R.id.fieldspager);
    
            // ...
    
            mButton.setOnClickListener(myButtonClickHandler);
        }
    
    
        View.OnClickListener myButtonClickHandler = new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mPager.setCurrentItem(2, true);
            }
        };
    }
    

    【讨论】:

      【解决方案6】:
          public class ConfigureActivity extends Activity {
      
              EditText etOne;
              EditText etTwo;
              @Override
              protected void onCreate(Bundle savedInstanceState) {
                  super.onCreate(savedInstanceState);
                  setContentView(R.layout.activity_configure);
      
                  Button btnConfigure = findViewById(R.id.btnConfigure1);   
                  btnConfigure.setOnClickListener(new View.OnClickListener() {
                              @Override
                              public void onClick(View v) {
                                  configure();
                              }
                          });
          }
      
          public  void configure(){
                  String one = etOne.getText().toString();
                  String two = etTwo.getText().toString();
          }
      }
      

      【讨论】:

      • 当然,如果您需要从内部类更新外部类状态,这就是解决方案。赞成陈述显而易见的事情!
      猜你喜欢
      • 2017-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-08
      • 1970-01-01
      • 1970-01-01
      • 2015-02-17
      • 1970-01-01
      相关资源
      最近更新 更多