在内部类中访问变量。需要宣布为最终


116

因此标题说明了一切。我的内出现编译错误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);

}

1
如果使用的是Eclipse,则可以按Ctrl-1(在OS X上为Cmd-1),并选择错误,以查看快速修复程序,该修复程序将向您显示需要更改的内容。在此处查看更多信息:depth-first.com/articles/2008/01/11/…–
复杂性

Answers:


130

如果您不想使其最终确定,则始终可以将其设置为全局变量。


1
@KevinZhao全局变量初始化后是否为最终变量?
the_prole

@the_prole我认为您可以在Java中使用final,但是我不确定在构建Android应用时是否可以使用它,因此使用Google谷歌搜索可能是一个好主意:-)
Kevin Zhao

15
回顾一下,如果可以避免使用全局变量,则不是一个好主意,除非您是初学者,在这种情况下,使程序与全局变量过度复杂是一种很好的学习经验。是一篇很好的文章,解释了为什么全局变量不是一个好主意。
the_prole

65

您可以将变量声明为final,或使其成为实例(或全局)变量。如果将其声明为final,则以后将无法对其进行更改。

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

在这里写了更深入的解释。它还说明了为什么实例和全局变量不需要声明为final。


44

错误说明了一切,更改:

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

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

87
原因:如果两个方法看到相同的局部变量,Java希望您发誓不会更改它- final用Java来说。加上不存在按引用参数,此规则可确保仅在本地方法所属的方法中分配本地方法。因此,代码更具可读性。
ignis 2013年

@ignis我遇到NullPointerException错误,addSiteButton.setOnClickListener(new View.OnClickListener() {您知道为什么会出现这种情况吗?
PhDeOliveira

1
当您对包含的变量调用方法时,通常会引发@PhDeOliveira NPE null。可能是findViewById正在返回null。我不能说更多,不是Android程序员。我建议您打开一个单独的问题。当然,它与内部类final 和similia无关。
ignis

25

这是一个有趣的答案。

您可以声明一个最终的单元素数组,然后显然可以更改所有元素。我敢肯定,这完全打破了最初执行此编译器规则的原因,但是当您像今天一样处于时间限制时,这非常方便。

我实际上不能为此索赔。这是IntelliJ的推荐!感觉有点。但是它看起来不像全局变量那么糟糕,因此我认为在这里值得一提。这只是解决问题的一种方法。不一定是最好的。

final int[] tapCount = {0};

addSiteButton.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {
       tapCount[0]++;
    }

});

在上述情况下,您不是在更改引用的对象,而是在数组内部更改内容。链接有很好的解释。
阿比拉什

是的我知道。似乎可以解决该问题。感谢您为其他人澄清的评论。
the_new_mr

4

就像@Veger所说的那样,您可以使它final在内部类中使用。

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

我之所以调用它,pager并不是mPager因为您在onCreate方法中将其用作局部变量。该m前缀是按惯例为类成员变量保留的(即,在类的开头声明的变量可用于所有类方法)。

如果您确实确实需要一个类成员变量,那么将其定为最终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);
        }
    };
}

0
    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();
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.