Variabel diakses di dalam kelas dalam. Harus dinyatakan final

116

Jadi judulnya menjelaskan semuanya. Saya mendapatkan kesalahan kompilasi di dalam file onClick.

Ini kodenya.

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

}
PhDeOliveira
sumber
1
Jika Anda menggunakan Eclipse, Anda dapat menekan Ctrl-1 (Cmd-1 di OS X) dengan kesalahan dipilih untuk melihat Quick Fix yang akan menunjukkan kepada Anda apa yang perlu diubah. Lihat lebih lanjut di sini: depth-first.com/articles/2008/01/11/…
Intrications

Jawaban:

130

Jika Anda tidak ingin menjadikannya final, Anda selalu dapat menjadikannya variabel global.

Kevin Zhao
sumber
1
@KevinZhao Apakah variabel global final setelah diinisialisasi?
the_prole
@the_prole Saya rasa Anda dapat menggunakan final di Java, tetapi saya tidak yakin apakah Anda dapat menggunakannya saat membuat aplikasi Android, jadi Googling mungkin ide yang bagus :-)
Kevin Zhao
15
Dalam retrospeksi, menggunakan variabel global adalah ide yang buruk jika dapat dihindari, kecuali Anda seorang pemula, dalam hal ini memperumit program Anda dengan global adalah pengalaman belajar yang baik. Berikut adalah artikel bagus yang menjelaskan mengapa variabel global adalah ide yang buruk.
the_prole
65

Anda dapat mendeklarasikan variabel final, atau menjadikannya sebagai variabel instance (atau global). Jika Anda menyatakannya sebagai final, Anda tidak dapat mengubahnya nanti.

Variabel apa pun yang ditentukan dalam metode dan diakses oleh kelas dalam anonim harus final. Jika tidak, Anda bisa menggunakan variabel itu di kelas dalam, tidak menyadari bahwa jika variabel berubah di kelas dalam, dan kemudian digunakan nanti di lingkup yang melingkupi, perubahan yang dibuat di kelas dalam tidak bertahan di lingkup yang melingkupi. Pada dasarnya, yang terjadi di kelas dalam tetap berada di kelas dalam.

Saya menulis penjelasan yang lebih mendalam di sini . Ini juga menjelaskan mengapa instance dan variabel global tidak perlu dinyatakan final.

Brendan L.
sumber
44

Kesalahan mengatakan itu semua, ubah:

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

untuk

final ViewPager mPager = (ViewPager) findViewById(R.id.fieldspager);
Veger
sumber
87
Alasan: jika dua metode melihat variabel lokal yang sama, Java ingin Anda bersumpah tidak akan mengubahnya - final, dalam bahasa Java. Bersama dengan tidak adanya parameter rujukan, aturan ini memastikan bahwa penduduk lokal hanya ditetapkan dalam metode yang mereka miliki. Kode dengan demikian lebih mudah dibaca.
ignis
@ignis Saya mendapatkan kesalahan NullPointerException pada addSiteButton.setOnClickListener(new View.OnClickListener() {apakah Anda tahu mengapa hal itu akan muncul?
PhDeOliveira
1
@PhDeOliveira NPE biasanya dilempar saat Anda memanggil metode pada variabel yang berisi null. Mungkin, findViewById kembali null. Saya tidak bisa mengatakan lebih banyak, bukan menjadi programmer Android; Saya menyarankan Anda untuk membuka pertanyaan terpisah. Tentu, ini tidak ada hubungannya dengan kelas dalam, final, dan sejenisnya .
ignis
25

Inilah jawaban yang lucu.

Anda dapat mendeklarasikan larik satu elemen terakhir dan mengubah elemen larik sesuai keinginan Anda. Saya yakin itu melanggar alasan mengapa aturan kompilator ini diterapkan di tempat pertama tetapi berguna ketika Anda dalam waktu-terikat seperti saya hari ini.

Saya sebenarnya tidak dapat mengklaim kredit untuk yang satu ini. Itu adalah rekomendasi IntelliJ! Rasanya agak hacky. Tapi sepertinya tidak seburuk variabel global jadi saya pikir itu perlu disebutkan di sini. Itu hanya satu solusi untuk masalah ini. Belum tentu yang terbaik.

final int[] tapCount = {0};

addSiteButton.setOnClickListener(new View.OnClickListener() {

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

});
the_new_mr
sumber
Dalam kasus di atas Anda tidak mengubah objek yang direferensikan, tetapi mengubah konten di dalam array. Tautan memiliki penjelasan yang bagus.
Abilash
Ya saya tahu. Sepertinya peretasan untuk mengatasi masalah ini. Terima kasih atas komentar Anda yang menjelaskannya kepada orang lain.
the_new_mr
4

Seperti yang dikatakan @Veger, Anda dapat membuatnya finalagar variabel dapat digunakan di kelas dalam.

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

Saya menyebutnya pagerdaripada mPagerkarena Anda menggunakannya sebagai variabel lokal dalam onCreatemetode ini. Itum awalan cusomarily disediakan untuk variabel anggota kelas (yaitu variabel yang dideklarasikan pada awal kelas dan tersedia untuk semua metode kelas).

Jika Anda benar-benar membutuhkan variabel anggota kelas, itu tidak berfungsi untuk menjadikannya final karena Anda tidak dapat menggunakan findViewByIduntuk menetapkan nilainya hingga onCreate. Solusinya adalah dengan tidak menggunakan kelas dalam anonim. Dengan cara ini mPagervariabel tidak perlu dinyatakan final dan dapat digunakan di seluruh kelas.

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);
        }
    };
}
Suragch
sumber
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();
    }
}
Shiv Buyya
sumber