La variable se accede dentro de la clase interna. Necesita ser declarado final

Entonces el título lo dice todo. Obtengo un error de comstackción dentro de mi onClick .

Aquí está el código.

 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); //Comstacktion error happens here. } }); cancelButton = (Button) findViewById(R.id.cancel_button); signInButton = (Button) findViewById(R.id.sign_in_button); } 

Si no quiere que sea definitivo, siempre puede convertirlo en una variable global.

Puede declarar la variable final o convertirla en una variable de instancia (o global). Si declara que es definitiva, no podrá cambiarla más tarde.

Cualquier variable definida en un método y accedida por una clase interna anónima debe ser definitiva. De lo contrario, podría usar esa variable en la clase interna, sin saber que si la variable cambia en la clase interna, y luego se usa más adelante en el ámbito adjunto, los cambios realizados en la clase interna no persistieron en el ámbito adjunto. Básicamente, lo que sucede en la clase interna permanece en la clase interna.

Escribí una explicación más detallada aquí . También explica por qué las variables de instancia y globales no necesitan ser declaradas finales.

El error lo dice todo, cambia:

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

a

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

Como dijo @Veger, puedes hacerlo final para que la variable se pueda usar en la clase interna.

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

Lo llamé pager lugar de mPager porque lo está usando como una variable local en el método onCreate . El prefijo m se reserva habitualmente para variables de miembros de clase (es decir, variables que se declaran al comienzo de la clase y están disponibles para todos los métodos de clase).

Si realmente necesita una variable de miembro de clase, no funciona para que sea definitiva porque no puede usar findViewById para establecer su valor hasta onCreate . La solución es no usar una clase interna anónima. De esta forma, la variable mPager no necesita ser declarada final y puede usarse en toda la clase.

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

Aquí hay una respuesta graciosa.

Puede declarar una matriz final de un elemento y cambiar los elementos de la matriz, todo lo que desee aparentemente. Estoy seguro de que rompe la verdadera razón por la que se implementó esta regla del comstackdor en primer lugar, pero es útil cuando estás en un límite de tiempo como lo estaba hoy.

De hecho, no puedo reclamar crédito por este. ¡Fue la recomendación de IntelliJ! Se siente un poco hacky. Pero no parece tan malo como una variable global, así que pensé que valía la pena mencionarlo aquí. Es solo una solución al problema. No necesariamente el mejor.

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