Si accede alla variabile all'interno della classe interna. Deve essere dichiarato definitivo


116

Quindi il titolo dice tutto. Ricevo un errore di compilazione all'interno del mio file onClick.

Ecco il codice.

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
Se stai usando Eclipse, puoi premere Ctrl-1 (Cmd-1 su OS X) con l'errore selezionato per vedere una correzione rapida che ti mostrerebbe cosa doveva essere cambiato. Vedi di più qui: depth-first.com/articles/2008/01/11/…
Intrications

Risposte:


130

Se non vuoi renderlo definitivo, puoi sempre renderlo una variabile globale.


1
@KevinZhao Le variabili globali sono definitive una volta che sono state inizializzate?
the_prole

@the_prole Penso che tu possa usare final in Java, ma non sono sicuro che tu possa usarlo durante la creazione di app Android, quindi cercare su Google potrebbe essere una buona idea :-)
Kevin Zhao

15
In retrospettiva, l'utilizzo di variabili globali è una cattiva idea se possono essere evitate, a meno che tu non sia un principiante, nel qual caso complicare eccessivamente il tuo programma con le variabili globali è una buona esperienza di apprendimento. Ecco un buon articolo che spiega perché le variabili globali sono una cattiva idea.
the_prole

65

Puoi dichiarare la variabile finale o renderla una variabile di istanza (o globale). Se lo dichiari definitivo, non potrai modificarlo in seguito.

Qualsiasi variabile definita in un metodo e accessibile da una classe interna anonima deve essere finale. Altrimenti, è possibile utilizzare quella variabile nella classe interna, ignorando che se la variabile cambia nella classe interna e quindi viene utilizzata successivamente nell'ambito di inclusione, le modifiche apportate nella classe interna non persistono nell'ambito di inclusione. Fondamentalmente, ciò che accade nella classe interna rimane nella classe interna.

Ho scritto una spiegazione più approfondita qui . Spiega anche perché le variabili di istanza e globali non devono essere dichiarate finali.


44

L'errore dice tutto, cambia:

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

per

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

87
Motivo: se due metodi vedono la stessa variabile locale, Java vuole che tu giuri che non la cambierai - final, in Java si parla. Insieme all'assenza di parametri di riferimento, questa regola garantisce che i locali siano assegnati solo nel metodo a cui appartengono. Il codice è quindi più leggibile.
ignis

@ignis Ricevo un errore NullPointerException su addSiteButton.setOnClickListener(new View.OnClickListener() {hai idea del perché sarebbe in arrivo?
PhDeOliveira

1
@PhDeOliveira NPE viene in genere generato quando chiami un metodo su una variabile che contiene null. Probabilmente, findViewById sta tornando null. Non posso dire di più, non essendo un programmatore Android; Ti consiglio di aprire una domanda a parte. Certo, non ha nulla a che fare con classi interne, finale, et similia .
ignis

25

Ecco una risposta divertente.

Puoi dichiarare un array finale di un elemento e cambiare gli elementi dell'array quanto vuoi apparentemente. Sono sicuro che infrange il vero motivo per cui questa regola del compilatore è stata implementata in primo luogo, ma è utile quando sei in un vincolo temporale come lo ero io oggi.

In realtà non posso rivendicare il merito per questo. Era la raccomandazione di IntelliJ! Sembra un po 'hacky. Ma non sembra così grave come una variabile globale, quindi ho pensato che valesse la pena menzionarla qui. È solo una soluzione al problema. Non necessariamente il migliore.

final int[] tapCount = {0};

addSiteButton.setOnClickListener(new View.OnClickListener() {

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

});

Nel caso precedente non stai cambiando l'oggetto di riferimento, ma cambiando il contenuto all'interno dell'array. link ha una bella spiegazione.
Abilash

Si, lo so. Sembra solo un trucco per risolvere il problema. Grazie per il tuo commento chiarendolo per gli altri.
the_new_mr

4

Come ha detto @Veger, puoi fare in finalmodo che la variabile possa essere utilizzata nella classe interna.

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

L'ho chiamato pagerpiuttosto che mPagerperché lo stai usando come variabile locale nel onCreatemetodo. Il mprefisso è solitamente riservato alle variabili membro della classe (cioè variabili che sono dichiarate all'inizio della classe e sono disponibili per tutti i metodi di classe).

Se hai effettivamente bisogno di una variabile membro di classe, non funziona per renderla finale perché non puoi usarla findViewByIdper impostare il suo valore fino a onCreate. La soluzione è non utilizzare una classe interna anonima. In questo modo la mPagervariabile non deve essere dichiarata finale e può essere utilizzata in tutta la classe.

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();
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.