4

i have "Cannot refer to a non-final variable i inside an inner class defined in a different method" error... Where am i going wrong?... I just started to learn android and java programming..

public class Tictac extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

        Button button[] = new Button[9];
        button[0]= (Button) findViewById(R.id.button1);
        button[1] = (Button) findViewById(R.id.button2);
        button[2] = (Button) findViewById(R.id.button3);
        button[3] = (Button) findViewById(R.id.button4);
        button[4] = (Button) findViewById(R.id.button5);
        button[5] = (Button) findViewById(R.id.button6);
        button[6] = (Button) findViewById(R.id.button7);
        button[7] = (Button) findViewById(R.id.button8);
        button[8] = (Button) findViewById(R.id.button9);


        final TextView text = (TextView) findViewById(R.id.textView1);

        final ImageView img[] = new ImageView[9];
        img[0] = (ImageView) findViewById(R.id.img1);
        img[1] = (ImageView) findViewById(R.id.img2);
        img[2] = (ImageView) findViewById(R.id.img3);
        img[3] = (ImageView) findViewById(R.id.img4);
        img[4] = (ImageView) findViewById(R.id.img5);
        img[5] = (ImageView) findViewById(R.id.img6);
        img[6] = (ImageView) findViewById(R.id.img7);
        img[7] = (ImageView) findViewById(R.id.img8);
        img[8] = (ImageView) findViewById(R.id.img9);
        final ImageView imSq[] = new ImageView[9];
        imSq[0] = (ImageView) findViewById(R.id.imSq1);
        imSq[1] = (ImageView) findViewById(R.id.imSq2);
        imSq[2] = (ImageView) findViewById(R.id.imSq3);
        imSq[3] = (ImageView) findViewById(R.id.imSq4);
        imSq[4] = (ImageView) findViewById(R.id.imSq5);
        imSq[5] = (ImageView) findViewById(R.id.imSq6);
        imSq[6] = (ImageView) findViewById(R.id.imSq7);
        imSq[7] = (ImageView) findViewById(R.id.imSq8);
        imSq[8] = (ImageView) findViewById(R.id.imSq9);


        for(int i =0;i <=8;i++){
        if(i%2==0){
             button[i].setOnClickListener(new View.OnClickListener() {
                     public void onClick(View v) {
        **HERE-->**       img[i].setVisibility(2);
                         text.setText("COOL");

                    }
                    });
        }
        else{   
             button[i].setOnClickListener(new View.OnClickListener() {
                     public void onClick(View v) {
         **HERE-->**        imSq[i].setVisibility(2);
                         text.setText("COOL");

                    }
                    });
    }



        }

}      

}

Sergio
  • 41
  • 1
  • 1
  • 2

2 Answers2

11

The error message says exactly what's wrong: the i variable isn't final, but you're trying to refer to it within an anonymous inner class.

You can do this:

for (int i = 0; i <= 8;i++) {
  if (i % 2 == 0) {
     final int j = i;
     button[i].setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
           img[j].setVisibility(2);
           text.setText("COOL");
         }
     });
  }
}

Here we take a copy of the variable i, and assign it to a final variable j, which we can then use within the anonymous inner class. Alternatively, if you don't care about the possibility of the array changing, you could do:

for (int i = 0; i <= 8;i++) {
  if (i % 2 == 0) {
     final ImageView imageView = img[i];
     button[i].setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
           imageView.setVisibility(2);
           text.setText("COOL");
         }
     });
  }
}

From section 8.1.3 of the Java Language Specification:

Any local variable, formal method parameter or exception handler parameter used but not declared in an inner class must be declared final. Any local variable, used but not declared in an inner class must be definitely assigned (§16) before the body of the inner class.

Adam Parkin
  • 17,891
  • 17
  • 66
  • 87
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Okay.. Thank you :).. it's not that what i wanted to do.. but your suggesting worked.. so thanks again – Sergio May 13 '11 at 21:37
  • Why does any local variable, formal method parameter or exception handler parameter used but not declared in an inner class must be declared final? – Roberto Feb 17 '13 at 00:18
  • 2
    @Roberto: It's because the value is effectively passed to the compiler-generated constructor of the anonymous inner class. By making the variables final, you avoid situations where you read a "changed" variable in the inner class, and expect to see the new value, where you'd actually only see the old value. – Jon Skeet Feb 17 '13 at 07:49
0

you can create a method, like that:

private void method(final Button btn, final ImageView img) {
    btn.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            img.setVisibility(2);
            text.setText("COOL");
        }
    });
}

and use that in your for i loop. This should work (not tested)