Saya menulis jawaban ini di '09 ketika Android relatif baru, dan ada banyak bidang yang tidak mapan dalam pengembangan Android. Saya telah menambahkan addendum panjang di bagian bawah posting ini, menangani beberapa kritik, dan merinci ketidaksepakatan filosofis yang saya miliki dengan penggunaan Singletons daripada subclassing Application. Baca dengan risiko Anda sendiri.
JAWABAN ASLI:
Masalah yang lebih umum yang Anda temui adalah bagaimana cara menyimpan status di beberapa Kegiatan dan semua bagian dari aplikasi Anda. Variabel statis (misalnya, singleton) adalah cara umum Java untuk mencapai ini. Namun saya telah menemukan, bahwa cara yang lebih elegan di Android adalah mengaitkan keadaan Anda dengan konteks Aplikasi.
Seperti yang Anda ketahui, setiap Kegiatan juga merupakan Konteks, yang merupakan informasi tentang lingkungan pelaksanaannya dalam arti luas. Aplikasi Anda juga memiliki konteks, dan Android menjamin bahwa itu akan ada sebagai contoh tunggal di seluruh aplikasi Anda.
Cara untuk melakukan ini adalah untuk membuat subclass Anda sendiri android.app.Application , dan kemudian tentukan kelas yang di tag aplikasi di nyata Anda. Sekarang Android akan secara otomatis membuat instance kelas itu dan membuatnya tersedia untuk seluruh aplikasi Anda. Anda dapat mengaksesnya dari context
menggunakan Context.getApplicationContext()
metode apa pun ( Activity
juga menyediakan metode getApplication()
yang memiliki efek sama persis). Berikut ini adalah contoh yang sangat sederhana, dengan peringatan yang harus diikuti:
class MyApp extends Application {
private String myState;
public String getState(){
return myState;
}
public void setState(String s){
myState = s;
}
}
class Blah extends Activity {
@Override
public void onCreate(Bundle b){
...
MyApp appState = ((MyApp)getApplicationContext());
String state = appState.getState();
...
}
}
Ini pada dasarnya memiliki efek yang sama dengan menggunakan variabel statis atau tunggal, tetapi terintegrasi cukup baik ke dalam kerangka Android yang ada. Perhatikan bahwa ini tidak akan berfungsi lintas proses (jika aplikasi Anda menjadi salah satu yang langka yang memiliki banyak proses).
Sesuatu yang perlu diperhatikan dari contoh di atas; misalkan kita telah melakukan sesuatu seperti:
class MyApp extends Application {
private String myState = /* complicated and slow initialization */;
public String getState(){
return myState;
}
}
Sekarang inisialisasi lambat ini (seperti memukul disk, memukul jaringan, apa pun pemblokiran, dll) akan dilakukan setiap kali Aplikasi di-instantiated! Anda mungkin berpikir, yah, ini hanya sekali untuk proses dan saya harus membayar biayanya, kan? Sebagai contoh, seperti yang disebutkan Dianne Hackborn di bawah ini, sangat mungkin bagi proses Anda untuk dipakai-cukup- untuk menangani acara siaran latar belakang. Jika pemrosesan siaran Anda tidak memerlukan kondisi ini, Anda berpotensi melakukan serangkaian operasi yang rumit dan lambat secara gratis. Instantiasi malas adalah nama permainan di sini. Berikut ini adalah cara yang sedikit lebih rumit dalam menggunakan Aplikasi yang lebih masuk akal untuk apa pun kecuali penggunaan yang paling sederhana:
class MyApp extends Application {
private MyStateManager myStateManager = new MyStateManager();
public MyStateManager getStateManager(){
return myStateManager ;
}
}
class MyStateManager {
MyStateManager() {
/* this should be fast */
}
String getState() {
/* if necessary, perform blocking calls here */
/* make sure to deal with any multithreading/synchronicity issues */
...
return state;
}
}
class Blah extends Activity {
@Override
public void onCreate(Bundle b){
...
MyStateManager stateManager = ((MyApp)getApplicationContext()).getStateManager();
String state = stateManager.getState();
...
}
}
Sementara saya lebih suka subkelas Aplikasi daripada menggunakan lajang di sini sebagai solusi yang lebih elegan, saya lebih suka pengembang menggunakan lajang jika benar-benar perlu daripada tidak memikirkan sama sekali melalui kinerja dan implikasi multithreading dari negara asosiasi dengan subkelas Aplikasi.
CATATAN 1: Juga sebagai anticafe berkomentar, untuk mengikat dengan benar Aplikasi Anda menimpa ke aplikasi Anda tag diperlukan dalam file manifes. Sekali lagi, lihat dokumen Android untuk info lebih lanjut. Sebuah contoh:
<application
android:name="my.application.MyApp"
android:icon="..."
android:label="...">
</application>
CATATAN 2: user608578 bertanya di bawah bagaimana ini bekerja dengan mengelola siklus objek asli. Saya tidak secepat menggunakan kode asli dengan Android sedikit pun, dan saya tidak memenuhi syarat untuk menjawab bagaimana itu akan berinteraksi dengan solusi saya. Jika seseorang memiliki jawaban untuk hal ini, saya bersedia memberi mereka kredit dan memasukkan informasi dalam pos ini untuk visibilitas maksimum.
TAMBAHAN:
Seperti yang dicatat oleh beberapa orang, ini bukan solusi untuk keadaan gigih , sesuatu yang saya mungkin harus lebih menekankan pada jawaban asli. Yaitu ini tidak dimaksudkan sebagai solusi untuk menyimpan pengguna atau informasi lain yang dimaksudkan untuk bertahan selama masa hidup aplikasi. Jadi, saya menganggap sebagian besar kritik di bawah ini terkait dengan Aplikasi yang dimatikan kapan saja, dll ..., diperdebatkan, karena apa pun yang perlu dipertahankan ke disk tidak boleh disimpan melalui subkelas Aplikasi. Ini dimaksudkan sebagai solusi untuk menyimpan keadaan aplikasi sementara yang mudah dibuat kembali (apakah pengguna login misalnya) dan komponen yang bersifat tunggal (misalnya manajer jaringan aplikasi) ( BUKAN tunggal!) Di alam.
Dayerman telah berbaik hati untuk menunjukkan percakapan yang menarik dengan Reto Meier dan Dianne Hackborn di mana penggunaan subkelas Aplikasi tidak disarankan untuk mendukung pola Singleton. Somatik juga menunjukkan sesuatu dari sifat ini sebelumnya, meskipun saya tidak melihatnya pada saat itu. Karena peran Reto dan Dianne dalam menjaga platform Android, saya tidak dapat dengan itikad baik merekomendasikan untuk mengabaikan saran mereka. Apa yang mereka katakan, pergi. Saya ingin tidak setuju dengan pendapat, yang diungkapkan sehubungan dengan memilih Singleton daripada subkelas Aplikasi. Dalam ketidaksepakatan saya, saya akan menggunakan konsep yang paling baik dijelaskan dalam penjelasan StackExchange tentang pola desain Singleton ini, sehingga saya tidak perlu mendefinisikan istilah dalam jawaban ini. Saya sangat menyarankan membaca sekilas tautan sebelum melanjutkan. Poin demi poin:
Dianne menyatakan, "Tidak ada alasan untuk subkelas dari Aplikasi. Tidak ada bedanya dengan membuat singleton ..." Klaim pertama ini tidak benar. Ada dua alasan utama untuk ini. 1) Kelas Aplikasi memberikan jaminan seumur hidup yang lebih baik untuk pengembang aplikasi; dijamin memiliki masa pakai aplikasi. Singleton tidak secara eksplisit terkait dengan masa berlaku aplikasi (meskipun itu efektif). Ini mungkin bukan masalah bagi pengembang aplikasi rata-rata Anda, tetapi saya berpendapat ini adalah jenis kontrak yang seharusnya ditawarkan oleh API Android, dan menyediakan lebih banyak fleksibilitas untuk sistem Android juga, dengan meminimalkan masa pakai yang terkait data. 2) Kelas Aplikasi menyediakan pengembang aplikasi dengan pemegang instance tunggal untuk status, yang sangat berbeda dari pemegang negara Singleton. Untuk daftar perbedaan, lihat tautan penjelasan Singleton di atas.
Dianne melanjutkan, "... kemungkinan besar akan menjadi sesuatu yang Anda sesali di masa depan ketika Anda mendapati objek Aplikasi Anda menjadi kekacauan besar seperti apa yang seharusnya menjadi logika aplikasi independen." Ini tentu saja tidak salah, tetapi ini bukan alasan untuk memilih Singleton daripada subkelas Aplikasi. Tidak ada argumen Diane yang memberikan alasan bahwa menggunakan Singleton lebih baik daripada subkelas Aplikasi, yang ia coba tegaskan adalah bahwa menggunakan Singleton tidak lebih buruk daripada subkelas Aplikasi, yang saya yakin salah.
Dia melanjutkan, "Dan ini mengarah secara alami pada bagaimana Anda seharusnya mengelola hal-hal ini - menginisialisasi mereka sesuai permintaan." Ini mengabaikan fakta bahwa tidak ada alasan Anda tidak dapat menginisialisasi berdasarkan permintaan menggunakan subkelas Aplikasi juga. Sekali lagi tidak ada perbedaan.
Dianne diakhiri dengan "Kerangka itu sendiri memiliki berton-ton lajang untuk semua sedikit data bersama yang dipelihara untuk aplikasi, seperti cache sumber daya yang dimuat, kumpulan objek, dll. Ini bekerja dengan baik." Saya tidak berpendapat bahwa menggunakan Lajang tidak dapat berfungsi dengan baik atau bukan alternatif yang sah. Saya berpendapat bahwa Singletons tidak memberikan kontrak yang kuat dengan sistem Android sebagai menggunakan subkelas Aplikasi, dan lebih lanjut bahwa menggunakan Singletons umumnya menunjuk pada desain yang tidak fleksibel, yang tidak mudah dimodifikasi, dan menyebabkan banyak masalah di jalan. IMHO, kontrak kuat yang ditawarkan API Android untuk aplikasi pengembang adalah salah satu aspek pemrograman yang paling menarik dan menyenangkan dengan Android, dan membantu mengarah pada adopsi pengembang awal yang mendorong platform Android menuju kesuksesan yang dimilikinya saat ini.
Dianne juga berkomentar di bawah ini, menyebutkan kelemahan tambahan untuk menggunakan subkelas Aplikasi, mereka dapat mendorong atau membuatnya lebih mudah untuk menulis kode kinerja yang lebih sedikit. Ini sangat benar, dan saya telah mengedit jawaban ini untuk menekankan pentingnya mempertimbangkan perf di sini, dan mengambil pendekatan yang benar jika Anda menggunakan subklasifikasi Aplikasi. Seperti yang dikatakan Dianne, penting untuk diingat bahwa kelas Aplikasi Anda akan dipakai setiap kali proses Anda dimuat (bisa beberapa kali sekaligus jika aplikasi Anda berjalan dalam beberapa proses!) Bahkan jika proses hanya dimuat untuk siaran latar belakang peristiwa. Oleh karena itu penting untuk menggunakan kelas Aplikasi lebih sebagai repositori untuk pointer ke komponen bersama aplikasi Anda daripada sebagai tempat untuk melakukan pemrosesan!
Saya meninggalkan Anda dengan daftar kelemahan untuk Singletons, seperti yang dicuri dari tautan StackExchange sebelumnya:
- Ketidakmampuan untuk menggunakan kelas abstrak atau antarmuka;
- Ketidakmampuan untuk subkelas;
- Kopling tinggi di seluruh aplikasi (sulit untuk dimodifikasi);
- Sulit untuk diuji (tidak dapat memalsukan / mengejek dalam unit test);
- Sulit untuk diparalelkan dalam kasus keadaan yang bisa berubah (membutuhkan penguncian yang luas);
dan tambahkan milik saya:
- Kontrak seumur hidup yang tidak jelas dan tidak dapat dikelola tidak cocok untuk pengembangan Android (atau sebagian besar lainnya);