Hari ini saya ingin berbagi dengan Anda pendekatan lain untuk mempertahankan status ketika mengembangkan aplikasi android. Bukan rahasia bahwa aplikasi kita di latar belakang dapat dibunuh kapan saja dan masalah ini menjadi lebih mendesak dengan diperkenalkannya penghematan energi yang agresif - halo
Oreo . Juga, tidak ada yang membatalkan perubahan konfigurasi pada ponsel: orientasi, perubahan bahasa, dll. Dan untuk membuka aplikasi dari latar belakang dan menampilkan antarmuka dalam keadaan terakhir, kita harus berhati-hati menyimpannya. Oh,
onSaveInstanceState ini.

Betapa sakitnya dia membawa kita.
Saya akan memberikan contoh nanti menggunakan
Clean Achitecture dan
Dagger2 , jadi bersiaplah untuk ini :)
Masalah mempertahankan status tergantung pada tugas dapat diselesaikan dengan beberapa cara:
- Simpan data primer di onSaveInstanceState host (Aktivitas, Fragmen) - seperti pengidentifikasi halaman, pengguna, dan apa pun. Apa yang kita butuhkan untuk akuisisi data awal dan tampilan halaman.
- Simpan data yang diterima dalam program interaktif di repositori (SharedPreference, Database.
- Gunakan fragmen rethein untuk menyimpan dan mengembalikan data saat membuat ulang aktivitas.
Tetapi bagaimana jika kita perlu mengembalikan keadaan ui, serta reaksi antarmuka saat ini terhadap tindakan pengguna? Untuk kesederhanaan, mari kita pertimbangkan solusi untuk masalah ini menggunakan contoh nyata. Kami memiliki halaman login - pengguna memasukkan datanya, mengklik tombol dan kemudian dia menerima panggilan masuk. Aplikasi kita masuk ke latar belakang. Sistem membunuhnya. Kedengarannya menakutkan, bukan?)
Pengguna kembali ke aplikasi dan apa yang harus dilihatnya? Minimal, melanjutkan operasi login dan menunjukkan kemajuan. Jika aplikasi berhasil masuk sebelum memanggil metode onDestroy host, maka pengguna akan melihat navigasi ke layar mulai aplikasi. Perilaku ini dapat dengan mudah diselesaikan menggunakan mesin negara.
Laporan yang sangat bagus
dari Yandex . Dalam artikel yang sama saya akan mencoba membagikan pemikiran saya tentang laporan ini.
Sekarang sedikit kode:
Basestatepublic interface BaseState<VIEW extends BaseView, OWNER extends BaseOwner> extends Parcelable{ @NonNull String getName(); void onEnter(@NonNull VIEW aView); void onExit(); void forward(); void back(); void invalidateView(@NonNull VIEW aView); @NonNull OWNER getOwner(); void setOwner(@NonNull OWNER aOwner); }
Baseoverner public interface BaseOwner<VIEW extends BaseView, STATE extends BaseState> extends BasePresenter<VIEW>{ void setState(@NonNull STATE aState); }
BasestateImpl public abstract class BaseStateImpl<VIEW extends BaseView, OWNER extends BaseOwner> implements BaseState<VIEW, OWNER>{ private OWNER mOwner; @NonNull @Override public String getName(){ return getClass().getName(); } @Override public void onEnter(@NonNull final VIEW aView){ Timber.d( getName()+" onEnter");
Dalam kasus kami, pemilik negara akan menjadi presenter.
Melihat halaman login, tiga status unik dapat dibedakan:
LoginInitState ,
LoginProgressingState ,
LoginCompleteState .
Jadi, sekarang pertimbangkan apa yang terjadi di negara-negara ini.
LoginInitState kami memiliki validasi bidang dan jika validasi berhasil, tombol login menjadi aktif.
Permintaan
Login dibuat di
LoginProgressingState , token disimpan, permintaan tambahan dibuat untuk memulai aktivitas utama aplikasi.
LoginCompleteState menavigasi ke layar utama aplikasi.
Secara kondisional, transisi antar negara dapat ditampilkan dalam diagram berikut:
Status LoginProgressingState keluar jika operasi login
berhasil dalam keadaan
LoginCompleteState , dan jika
LoginInitState gagal . Dengan demikian, ketika pandangan kita dilepaskan, kita memiliki keadaan presenter yang sepenuhnya deterministik. Kita harus menyimpan keadaan ini menggunakan mekanisme android standar
onSaveInstanceState . Agar kami dapat melakukan ini, semua status login harus mengimplementasikan antarmuka
Parcelable . Oleh karena itu, kami memperluas
BaseState antarmuka antarmuka
kami .
Selanjutnya, kami memiliki pertanyaan, bagaimana cara meneruskan keadaan ini dari presenter ke host kami? Cara termudah adalah dengan meminta data kepada presenter, tetapi dari sudut pandang arsitektur, ini tidak terlihat bagus. Jadi simpanlah fragmen untuk membantu kami. Kami dapat membuat antarmuka untuk cache dan mengimplementasikannya dalam fragmen ini:
public interface Cache{ void saveCacheData(@Nullable Parcelable aData); @Nullable Parcelable getCacheData(); boolean isCacheExist(); }
Selanjutnya, kami menyuntikkan fragmen cache ke konstruktor interaktor, seperti Cache. Kami menambahkan metode dalam integrator untuk mendapatkan dan menyimpan status dalam cache. Sekarang, dengan setiap perubahan dalam kondisi presenter, kita dapat menyimpan status di dalam interaktor, dan pada gilirannya interaktor menyimpan dalam cache. Semuanya menjadi sangat logis. Ketika host pertama kali dimuat, presenter menerima keadaan dari interaktor, yang pada gilirannya menerima data dari cache. Beginilah tampilan metode perubahan keadaan dalam presenter:
@Override public void setState(@NonNull final LoginBaseState aState){ mState.onExit(); mState = aState; clearDisposables(); mState.setOwner(this); mState.onEnter(getView()); mInteractor.setState(mState); }
Saya ingin mencatat hal ini - menyimpan data melalui cache dapat dilakukan untuk data apa pun, tidak hanya untuk negara bagian. Anda mungkin perlu membuat cache snippet unik Anda sendiri untuk menyimpan data saat ini. Artikel ini menjelaskan pendekatan umum. Saya juga ingin mencatat bahwa situasi yang dipermasalahkan sangat berlebihan. Dalam hidup Anda harus menyelesaikan masalah yang jauh lebih rumit. Misalnya, dalam aplikasi kami tiga halaman digabungkan: login, registrasi, pemulihan kata sandi. Dalam hal ini, diagram keadaan adalah sebagai berikut:

Hasilnya, dengan menggunakan pola dan pendekatan keadaan yang dijelaskan dalam artikel, kami dapat membuat kode lebih mudah dibaca dan dipelihara. Dan yang penting adalah mengembalikan keadaan aplikasi saat ini.
Kode lengkap dapat dilihat
di repositori .