Mengekalkan Keadaan dengan HydratedBloc
Siri dan pulihkan keadaan BLoC secara automatik merentas permulaan semula aplikasi dengan hydrated_bloc.
Mengekalkan Keadaan dengan HydratedBloc ialah pelajaran Pembangunan Aplikasi Mudah Alih Flutter percuma di CoddyKit. Ini ialah pelajaran 3 daripada 4. Sebanyak 3 pelajaran dalam laluan pembelajaran ini boleh dibaca sepenuhnya secara percuma — selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan praktikal dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Pembangunan Aplikasi Mudah Alih Flutter, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Pembangunan Aplikasi Mudah Alih Flutter merangkumi sejumlah 4 pelajaran.
Mengapa Keadaan BLoC Perlu Disimpan?
Secara lalai, Bloc atau Cubit kehilangan segala-galanya apabila proses aplikasi dihentikan. Apabila aplikasi dibuka semula, keadaan awal dijalankan semula, jadi pilihan terakhir pengguna, kandungan bakul, atau tema akan hilang.
hydrated_bloc menyelesaikan masalah ini tanpa memerlukan anda menulis kod simpan/muat secara manual. Ia secara telus:
- Menukar setiap keadaan baharu kepada bentuk bersiri dan menyimpannya dalam storan setempat apabila keadaan itu dikeluarkan
- Memulihkan keadaan terakhir secara automatik apabila BLoC dicipta semula
Ini amat sesuai untuk keutamaan antara muka, penanda orientasi awal, dan data sesi kecil yang perlu kekal selepas aplikasi dimulakan semula.
Persediaan dan Pemulaan Storan
Tambahkan pakej pada pubspec.yaml:
hydrated_blocmenyediakanHydratedBlocdanHydratedCubitpath_providermenyediakan direktori yang boleh ditulis pada peranti
Sebelum aplikasi anda berjalan, anda mesti membina bahagian belakang storan dan menetapkannya kepada HydratedBloc.storage. Oleh sebab langkah ini melibatkan saluran platform, bungkusnya dengan WidgetsFlutterBinding.ensureInitialized().
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
HydratedBloc.storage = await HydratedStorage.build(
storageDirectory: kIsWeb
? HydratedStorageDirectory.web
: HydratedStorageDirectory(
(await getApplicationDocumentsDirectory()).path,
),
);
runApp(const MyApp());
}Daripada Cubit kepada HydratedCubit
Cara paling mudah untuk menyimpan keadaan ialah melanjutkan HydratedCubit dan bukannya Cubit. Anda mesti mengatasi dua kaedah:
toJson(state)menukar keadaan kepadaMapyang boleh dikodkan sebagai JSON (atau mengembalikannulluntuk melangkau penyimpanan)fromJson(json)membina semula keadaan daripada peta tersebut (atau mengembalikannulluntuk kembali kepada keadaan awal pembina)
Di sini, pembilang kekal selepas aplikasi dimulakan semula dengan hanya beberapa baris.
class CounterCubit extends HydratedCubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
@override
int? fromJson(Map<String, dynamic> json) => json['value'] as int?;
@override
Map<String, dynamic>? toJson(int state) => {'value': state};
}Cara fromJson dan toJson Mengawal Penyimpanan
Alirannya berlaku secara automatik sepenuhnya setelah kaedah ditakrifkan:
- Pada setiap
emit, hydrated_bloc memanggiltoJsondan menulis hasilnya ke storan menggunakanstorageTokenBLoC sebagai kunci. - Apabila BLoC dibina, kelas asas membaca JSON yang disimpan dan memanggil
fromJson; nilai yang dikembalikan menjadi keadaan permulaan, menggantikan nilai yang dihantar kepadasuper(...).
Jika fromJson mengembalikan null (belum ada data atau penyahkodan gagal), keadaan awal pembina digunakan. Kembali kepada nilai ini apabila null ialah jaring keselamatan anda.
Menyimpan Kelas Keadaan Tersuai
Aplikasi sebenar jarang menyimpan int biasa. Untuk keadaan tersuai, petakan setiap medan yang anda perlukan dalam toJson dan baca semula dalam fromJson. Di bawah, keadaan tetapan dengan penanda tema dan skala fon disiri sepenuhnya.
Kekalkan bentuk JSON yang stabil dan jelas supaya versi akan datang masih boleh membaca data lama.
class SettingsState {
final bool darkMode;
final double fontScale;
const SettingsState({required this.darkMode, required this.fontScale});
Map<String, dynamic> toMap() =>
{'darkMode': darkMode, 'fontScale': fontScale};
factory SettingsState.fromMap(Map<String, dynamic> m) => SettingsState(
darkMode: m['darkMode'] as bool? ?? false,
fontScale: (m['fontScale'] as num?)?.toDouble() ?? 1.0,
);
}
class SettingsCubit extends HydratedCubit<SettingsState> {
SettingsCubit()
: super(const SettingsState(darkMode: false, fontScale: 1.0));
void toggleDark() =>
emit(SettingsState(darkMode: !state.darkMode, fontScale: state.fontScale));
@override
SettingsState? fromJson(Map<String, dynamic> json) =>
SettingsState.fromMap(json);
@override
Map<String, dynamic>? toJson(SettingsState state) => state.toMap();
}Menggunakan HydratedBloc dengan Peristiwa
Untuk logik dipacu peristiwa, lanjutkan HydratedBloc dan bukannya HydratedCubit. Kontrak toJson/fromJson adalah sama; hanya penghasilan keadaan yang berubah (anda mendaftarkan pengendali peristiwa dengan on<Event>).
Ini pilihan yang tepat apabila peralihan memerlukan semantik peristiwa, pengelogan, atau transformer.
sealed class CartEvent {}
class ItemAdded extends CartEvent {
final String sku;
ItemAdded(this.sku);
}
class CartBloc extends HydratedBloc<CartEvent, List<String>> {
CartBloc() : super(const []) {
on<ItemAdded>((event, emit) => emit([...state, event.sku]));
}
@override
List<String>? fromJson(Map<String, dynamic> json) =>
(json['items'] as List?)?.cast<String>();
@override
Map<String, dynamic>? toJson(List<String> state) => {'items': state};
}Logik Penyirian Tulen (Boleh Diuji)
Teras penyimpanan ialah Dart biasa: menukar objek kepada Map dan menukarnya kembali. Anda boleh menguji kitaran pergi balik ini secara unit tanpa Flutter, storan, atau peranti. Di bawah ialah atur cara kendiri yang membuktikan pengekodan/penyahkodan tidak kehilangan data.
Anggap toJson/fromJson anda sebagai fungsi biasa dan ujinya secara berasingan sebelum menyambungkannya kepada BLoC.
import 'dart:convert';
Map<String, dynamic> toJson(int value) => {'value': value};
int? fromJson(Map<String, dynamic> json) => json['value'] as int?;
void main() {
final state = 42;
final encoded = jsonEncode(toJson(state));
print('stored: $encoded');
final decoded = fromJson(jsonDecode(encoded) as Map<String, dynamic>);
print('restored: $decoded');
print('lossless: ${decoded == state}');
}Migrasi Skema dengan Medan Versi
Selepas aplikasi anda diterbitkan, data bersiri lama masih berada pada peranti pengguna. Jika anda menambah atau menamakan semula medan, fromJson yang naif boleh gagal atau membaca data yang rosak. Pertahanan standard ialah medan versi yang ditulis ke dalam JSON.
Semasa membaca, pilih cabang berdasarkan versi dan naik taraf bentuk lama. Demo ini memindahkan muatan v1 (satu name) kepada v2 (firstName/lastName).
import 'dart:convert';
Map<String, dynamic> migrate(Map<String, dynamic> json) {
final version = json['v'] as int? ?? 1;
if (version >= 2) return json;
final parts = (json['name'] as String).split(' ');
return {
'v': 2,
'firstName': parts.first,
'lastName': parts.length > 1 ? parts.last : '',
};
}
void main() {
final oldData = jsonDecode('{"v":1,"name":"Ada Lovelace"}');
final upgraded = migrate(oldData as Map<String, dynamic>);
print(upgraded);
}fromJson Berdaya Tahan: Mengendalikan Data Rosak
Jika fromJson menghasilkan ralat, hydrated_bloc menangkapnya dan kembali kepada keadaan awal, tetapi peta yang sah sebahagiannya masih boleh menghasilkan keadaan yang salah. Jadikan penyahkodan menyeluruh: sahkan jenis, sediakan nilai lalai, dan kembalikan null apabila data tidak boleh digunakan.
Mengembalikan null ialah tindakan yang disengajakan dan selamat — tindakan ini memberitahu hydrated_bloc supaya menggunakan keadaan awal pembina.
@override
SettingsState? fromJson(Map<String, dynamic> json) {
try {
final scale = (json['fontScale'] as num?)?.toDouble();
if (scale == null || scale <= 0) return null; // reject bad data
return SettingsState(
darkMode: json['darkMode'] as bool? ?? false,
fontScale: scale,
);
} catch (_) {
return null; // fall back to initial state
}
}Penyimpanan Terpilih dan Pengosongan Keadaan
Anda tidak perlu menyimpan setiap keadaan. Mengembalikan null daripada toJson melangkau penulisan untuk keluaran keadaan itu — berguna untuk keadaan sementara memuatkan atau ralat yang tidak mahu dipulihkan.
Untuk memadam data yang disimpan, panggil clear() pada tika tersebut (hanya membuang entri BLoC ini) atau HydratedBloc.storage.clear() (memadamkan semuanya, contohnya semasa log keluar).
class AuthCubit extends HydratedCubit<AuthState> {
AuthCubit() : super(const Unauthenticated());
void logout() {
clear(); // remove this cubit's persisted entry
emit(const Unauthenticated());
}
@override
Map<String, dynamic>? toJson(AuthState state) =>
state is Authenticated ? {'token': state.token} : null; // skip others
@override
AuthState? fromJson(Map<String, dynamic> json) =>
json['token'] is String ? Authenticated(json['token'] as String) : null;
}Berbilang Tika dan storageToken
hydrated_bloc mengenal pasti data yang disimpan berdasarkan storageToken, yang secara lalai ialah runtimeType. Oleh itu, dua tika daripada kelas BLoC yang sama berkongsi satu ruang storan dan akan saling menimpa data.
Jika anda memerlukan penyimpanan mengikut entiti (contohnya, satu cubit bagi setiap bilik sembang), atasi id supaya setiap tika mendapat token unik seperti ChatCubit-room42.
class ChatCubit extends HydratedCubit<List<String>> {
final String roomId;
ChatCubit(this.roomId) : super(const []);
@override
String get id => roomId; // token becomes 'ChatCubit-$roomId'
@override
List<String>? fromJson(Map<String, dynamic> json) =>
(json['messages'] as List?)?.cast<String>();
@override
Map<String, dynamic>? toJson(List<String> state) => {'messages': state};
}Semakan Pantas
Seorang rakan sepasukan melaporkan bahawa HydratedCubit mengeluarkan keadaan sementara Loading, dan selepas aplikasi dimulakan semula, antara muka kadangkala tersekat memaparkan pemutar yang tidak pernah selesai. Apakah pembaikan yang paling bersih?
Rumusan
Kini anda boleh menyimpan keadaan BLoC merentas permulaan semula dengan hydrated_bloc:
- Mulakan
HydratedBloc.storagedalammain()selepasensureInitialized(). - Lanjutkan
HydratedCubitatauHydratedBlocdan atasitoJson/fromJson. - Pemulihan berlaku secara automatik semasa pembinaan;
nulldaripadafromJsonkembali kepada keadaan awal dengan selamat. - Kembalikan
nulldaripadatoJsonuntuk melangkau penyimpanan keadaan sementara, dan gunakanclear()semasa log keluar. - Lindungi daripada data rosak dengan penyahkodan berdaya tahan dan migrasi berasaskan versi.
- Atasi
idapabila anda memerlukan token storan bagi setiap tika.
Pastikan muatan yang disimpan kecil serta penyirian anda tulen dan diuji — itulah yang menjadikan keadaan selamat selepas permulaan semula boleh dipercayai pada skala besar.
Pelajari Dart dengan tutor kecerdasan buatan — percuma
Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.
- Kursus
- 22
- Pelajaran
- 88
Soalan Lazim
Adakah pelajaran “Mengekalkan Keadaan dengan HydratedBloc” percuma?
Ya — sebanyak 3 pelajaran dalam laluan pembelajaran Pembangunan Aplikasi Mudah Alih Flutter, termasuk “Mengekalkan Keadaan dengan HydratedBloc”, boleh dibaca sepenuhnya secara percuma di web ini. Selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan interaktif dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Kursus Pembangunan Aplikasi Mudah Alih Flutter merangkumi sejumlah 4 pelajaran.
Apakah yang akan saya pelajari dalam “Mengekalkan Keadaan dengan HydratedBloc”?
Siri dan pulihkan keadaan BLoC secara automatik merentas permulaan semula aplikasi dengan hydrated_bloc. Anda berlatih Pembangunan Aplikasi Mudah Alih Flutter menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.
Adakah saya memerlukan pengalaman untuk memulakan Pembangunan Aplikasi Mudah Alih Flutter?
Tiada pengalaman terdahulu diperlukan. Pembelajaran Pembangunan Aplikasi Mudah Alih Flutter di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 3 daripada 4.
Berapa lamakah pelajaran “Mengekalkan Keadaan dengan HydratedBloc” diambil?
Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.
Bolehkah saya menulis dan menjalankan kod dalam pelajaran Pembangunan Aplikasi Mudah Alih Flutter ini?
Ya. Setiap pelajaran Pembangunan Aplikasi Mudah Alih Flutter menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.
Semua pelajaran dalam kursus ini
- Peristiwa, Keadaan dan Keputusan Cubit-berbanding-Bloc
- Pengubah Stream dan Penyahlantunan Peristiwa dalam BLoC
- Mengekalkan Keadaan dengan HydratedBloc
- Menguji BLoC dengan bloc_test dan Mocktail