Saya membuat aplikasi yang memerlukan login. Saya membuat aktivitas utama dan login.
Dalam onCreate
metode aktivitas utama saya menambahkan kondisi berikut:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
...
loadSettings();
if(strSessionString == null)
{
login();
}
...
}
The onActivityResult
metode yang dijalankan ketika form login berakhir terlihat seperti ini:
@Override
public void onActivityResult(int requestCode,
int resultCode,
Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode)
{
case(SHOW_SUBACTICITY_LOGIN):
{
if(resultCode == Activity.RESULT_OK)
{
strSessionString = data.getStringExtra(Login.SESSIONSTRING);
connectionAvailable = true;
strUsername = data.getStringExtra(Login.USERNAME);
}
}
}
Masalahnya adalah form login kadang muncul dua kali ( login()
metode ini disebut dua kali) dan juga ketika keyboard ponsel slide form login muncul lagi dan saya kira masalahnya adalah variabel strSessionString
.
Adakah yang tahu cara mengatur variabel global untuk menghindari munculnya formulir masuk setelah pengguna berhasil mengautentikasi?
android
singleton
global-variables
state
Niko Gamulin
sumber
sumber
Jawaban:
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
menggunakanContext.getApplicationContext()
metode apa pun (Activity
juga menyediakan metodegetApplication()
yang memiliki efek sama persis). Berikut ini adalah contoh yang sangat sederhana, dengan peringatan yang harus diikuti: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:
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:
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:
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:
dan tambahkan milik saya:
sumber
Buat subkelas ini
Di AndroidManifest.xml tambahkan android: name
Contoh
sumber
java.lang.IllegalAccessException: access to class is not allowed
Cara yang disarankan oleh Soonil untuk menjaga keadaan aplikasi tetap bagus, namun ada satu kelemahannya - ada beberapa kasus ketika OS membunuh seluruh proses aplikasi. Ini dokumentasi tentang ini - Proses dan siklus hidup .
Pertimbangkan sebuah kasus - aplikasi Anda masuk ke latar belakang karena seseorang memanggil Anda (Aplikasi telepon ada di latar depan sekarang). Dalam hal ini && dalam beberapa kondisi lain (periksa tautan di atas untuk mengetahui kemungkinannya), OS dapat mematikan proses aplikasi Anda, termasuk
Application
instance subclass. Akibatnya negara hilang. Ketika nanti Anda kembali ke aplikasi, maka OS akan mengembalikan aktivitas tumpukan danApplication
subkelasnya, namun demikianmyState
bidangnyanull
.AFAIK, satu-satunya cara untuk menjamin keamanan negara adalah dengan menggunakan segala jenis keadaan yang tetap ada, misalnya menggunakan pribadi untuk file aplikasi atau
SharedPrefernces
(akhirnya menggunakan pribadi untuk file aplikasi dalam sistem file internal).sumber
SharedPreferences
; ini adalah bagaimana saya melihatnya selesai. Saya merasa aneh untuk menyalahgunakan sistem preferensi untuk negara yang diselamatkan, tetapi ia bekerja dengan sangat baik sehingga masalah ini hanya menjadi masalah terminologi.Hanya sebuah catatan ..
Menambahkan:
atau apa pun yang Anda beri nama subclass Anda ke tag yang ada
<application>
. Saya terus mencoba menambahkan<application>
tag lain ke manifes dan akan mendapatkan pengecualian.sumber
Saya juga tidak bisa menemukan cara untuk menentukan tag aplikasi, tetapi setelah banyak Googling, menjadi jelas dari dokumen manifes file: gunakan android: name, selain ikon dan label default di bait aplikasi.
android: name Nama subkelas Aplikasi yang sepenuhnya memenuhi syarat yang diterapkan untuk aplikasi. Ketika proses aplikasi dimulai, kelas ini dipakai sebelum salah satu komponen aplikasi.
Subkelas adalah opsional; kebanyakan aplikasi tidak membutuhkannya. Dengan tidak adanya subkelas, Android menggunakan turunan dari kelas Aplikasi dasar.
sumber
Bagaimana dengan memastikan koleksi memori asli dengan struktur global seperti itu?
Aktivitas memiliki
onPause/onDestroy()
metode yang disebut penghancuran, tetapi kelas Aplikasi tidak memiliki padanan. Mekanisme apa yang direkomendasikan untuk memastikan bahwa struktur global (terutama yang mengandung referensi ke memori asli) dikumpulkan secara tepat ketika aplikasi dimatikan atau tumpukan tugas diletakkan di latar belakang?sumber
Anda hanya perlu mendefinisikan nama aplikasi seperti di bawah ini yang akan berfungsi:
sumber
Seperti telah dibahas di atas, OS dapat mematikan APLIKASI tanpa pemberitahuan apa pun (tidak ada acara onDestroy) sehingga tidak ada cara untuk menyimpan variabel global ini.
SharedPreferences bisa menjadi solusi KECUALI Anda memiliki variabel TERSTRUKTUR COMPLEX (dalam kasus saya, saya memiliki array integer untuk menyimpan ID yang sudah ditangani pengguna). Masalah dengan SharedPreferences adalah sulit untuk menyimpan dan mengambil struktur ini setiap kali nilai yang dibutuhkan.
Dalam kasus saya, saya memiliki latar belakang SERVICE sehingga saya dapat memindahkan variabel-variabel ini ke sana dan karena layanan tersebut memiliki onDestroy event, saya dapat menyimpan nilai-nilai itu dengan mudah.
sumber
Jika beberapa variabel disimpan dalam sqlite dan Anda harus menggunakannya dalam sebagian besar aktivitas di aplikasi Anda. maka Aplikasi mungkin cara terbaik untuk mencapainya. Permintaan variabel dari basis data saat aplikasi dimulai dan menyimpannya di bidang. Kemudian Anda dapat menggunakan variabel-variabel ini dalam aktivitas Anda.
Jadi temukan jalan yang benar, dan tidak ada jalan terbaik.
sumber
Anda dapat memiliki bidang statis untuk menyimpan keadaan seperti ini. Atau taruh di Bundle sumber daya dan kembalikan dari sana di onCreate (Bundle SavedInstanceState). Pastikan Anda sepenuhnya memahami siklus hidup yang dikelola aplikasi Android (mis. Mengapa login () dipanggil saat perubahan orientasi keyboard).
sumber
JANGAN Gunakan
<application>
tag lain dalam file manifes. Cukup lakukan satu perubahan pada<application>
tag yang ada , tambahkan baris ini diandroid:name=".ApplicationName"
mana,ApplicationName
akan menjadi nama subkelas Anda (gunakan untuk menyimpan global) yang akan Anda buat.jadi, akhirnya tag SATU DAN HANYA
<application>
dalam file manifes Anda akan terlihat seperti ini: -sumber
Anda dapat menggunakan Intents, Sqlite, atau Preferensi Bersama. Ketika datang ke penyimpanan media, seperti dokumen, foto, dan video, Anda dapat membuat file baru sebagai gantinya.
sumber
Anda dapat melakukan ini menggunakan dua pendekatan:
Menggunakan Preferensi Bersama
Menggunakan kelas Aplikasi
Contoh:
Anda dapat menggunakan kelas di atas untuk menerapkan login di MainActivity Anda seperti di bawah ini. Kode akan terlihat seperti ini:
Metode ini akan berfungsi untuk penyimpanan sementara. Anda benar-benar tidak tahu kapan sistem operasi akan mematikan aplikasi, karena memori rendah. Ketika aplikasi Anda berada di latar belakang dan pengguna menavigasi melalui aplikasi lain yang menuntut lebih banyak memori untuk dijalankan, maka aplikasi Anda akan mati karena sistem operasi lebih diprioritaskan untuk proses foreground daripada latar belakang. Karenanya objek aplikasi Anda akan menjadi nol sebelum pengguna keluar. Karenanya untuk ini saya merekomendasikan untuk menggunakan metode kedua yang ditentukan di atas.
Menggunakan preferensi bersama.
sumber
Hasil aktivitas dipanggil sebelum pada resume. Jadi, gerakkan Anda untuk masuk ke resume dan login kedua Anda dapat diblokir begitu aktivitas kedua telah mengembalikan hasil yang positif. Pada resume dipanggil setiap kali sehingga tidak ada kekhawatiran itu tidak dipanggil pertama kali.
sumber
Pendekatan subclassing juga telah digunakan oleh kerangka kerja BARACUS. Dari sudut pandang saya, aplikasi subclassing dimaksudkan untuk bekerja dengan siklus hidup Android; ini adalah apa yang setiap Aplikasi Kontainer tidak. Alih-alih memiliki global saat itu, saya mendaftarkan kacang ke konteks ini dan membiarkan mereka diinjeksi ke dalam kelas yang dapat dikelola oleh konteks. Setiap contoh kacang yang disuntikkan sebenarnya adalah singleton.
Lihat contoh ini untuk detailnya
Mengapa pekerjaan manual jika Anda dapat memiliki lebih banyak?
sumber
sumber
Anda bisa membuat kelas yang memperluas
Application
kelas dan kemudian mendeklarasikan variabel Anda sebagai bidang kelas itu dan menyediakan metode pengambil untuk itu.Dan kemudian untuk mengakses variabel itu di Aktivitas Anda, gunakan ini:
sumber