Beranda › Forums › Belajar Flutter Mobile Apps Tingkat Mahir › error setelah migrasi ke null safety
Tagged: Migrasi ke Null Safety
- This topic has 28 replies, 2 voices, and was last updated 4 years, 3 months ago by Anonymous.
-
AuthorPosts
-
July 16, 2022 at 7:58 AM #51724
Dear coach..
saat migrasi ke null safety terjadi error pada emulator = Exeption = Error terjadi kesalahan..
selain itu saya coba tambahkan note baru juga muncul error berikut: RangeError(index):invalid value: Not in inclusive range 0..3:-1
mohon petunjuknya coach..
July 16, 2022 at 7:59 AM #51725ini kode add_or_detail_screen coach:
import ‘dart:ffi’;
import ‘package:flutter/material.dart’;
import ‘package:intl/intl.dart’;
import ‘package:notes/models/note.dart’;
import ‘package:notes/providers/notes.dart’;
import ‘package:provider/provider.dart’;class AddOrDetailScreen extends StatefulWidget {
static const routeName = ‘/addOrDetailScreen’;
@override
State<AddOrDetailScreen> createState() => _AddOrDetailScreenState();
}class _AddOrDetailScreenState extends State<AddOrDetailScreen> {
Note _note = Note(
id: ”,
title: ”,
note: ”,
// updatedAt: null,
// createdAt: null,
);bool _init = true;
// tambah parameter untuk penanda sedang loading atau tidak saat simpan note
bool _isLoading = false;final _formKey = GlobalKey<FormState>();
void submitNote() async {
// tambahkan validasi (if) karena migrasi ke null
if (_formKey.currentState != null) {
_formKey.currentState!.save();
}
// set isLoading jadi true
setState(() {
_isLoading = true;
});
try {
final now = DateTime.now();
_note = _note.copyWith(updatedAt: now, createdAt: now);
final notesProvider = Provider.of<Notes>(context, listen: false);
if (_note.id == null) {
await notesProvider.addNote(_note);
} else {
await notesProvider.updateNote(_note);
}
} catch (e) {
await showDialog(
context: context,
builder: (builder) {
return AlertDialog(
title: Text(‘Error’),
content: Text(e.toString()),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(‘Tutup’),
)
],
);
},
);
}
// notesProvider.addNote(_note);
Navigator.of(context).pop();
}@override
void didChangeDependencies() {
if (_init) {
String? id = ModalRoute.of(context)!.settings.arguments as String?;
// tambahkan fungsi if untuk validasi penambahan note baru
//jika id tidak sama dengan null baru cari note dari provider,
//jika null berarti note baru dan tidak perlu cari data atau id dalam provider
if (id != null) {
_note = Provider.of<Notes>(context).getNote(id);
}
_init = false;
}
super.didChangeDependencies();
}// fungsi untuk merubah format waktu di detail note
String _convertDate(DateTime dateTime) {
int diff = DateTime.now().difference(dateTime).inDays;
if (diff > 0) return DateFormat(‘dd-MM-yyyy’).format(dateTime);return DateFormat(‘hh-mm’).format(dateTime);
}@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
TextButton(
onPressed: submitNote,
// tambahkan fungsi isLoading
child: _isLoading
? CircularProgressIndicator()
: Text(
‘Simpan’,
style: TextStyle(color: Colors.white),
),
)
],
),
body: Stack(
children: [
Container(
height: double.infinity,
padding: EdgeInsets.all(12),
// wrap dengan SingleChildScrollView agar bisa di scroll
child: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
// tambahkan initialValue agar saat note ditekan memunculkan judul
initialValue: _note.title,
decoration: InputDecoration(
hintText: ‘Judul’, border: InputBorder.none),
onSaved: (value) {
_note = _note.copyWith(title: value);
},
),
TextFormField(
// tambahkan initialValue agar saat note ditekan memunculkan isi note
initialValue: _note.note,
decoration: InputDecoration(
hintText: ‘Tulis Catatan Disini…’,
border: InputBorder.none),
onSaved: (value) {
_note = _note.copyWith(note: value);
},
// tambahkan maxLines untuk menampilkan note tulisan ke bawah
maxLines: null,
),
],
)),
),
),
// 1. Untuk menampilkan kapan note terakhir diubah
// 2. wrap dengan Positioned agar update waktu pindah ke bawah
// 3. tambahkan fungsi if karena ada penambahan note baru sedangkan note.updatedAt masih null
// 4. jika note.updated tidak null maka baru tampilkan kapan terakhir diubah note nya
if (_note.updatedAt != null)
Positioned(
bottom: 10,
right: 10,
child: Text(‘Terakhir diubah ${_convertDate(_note.updatedAt!)}’),
),
],
),
);
}
}July 17, 2022 at 1:11 PM #51752Saya coba matikan internet dan hot reload, note yang tersimpan sebelumnya bisa muncul, namun jika internet di hidupkan dan di hot reload lagi kembali terjadi error pada emulator = Exeption = Error terjadi kesalahan..
Mohon petunjuknya coach..
July 18, 2022 at 10:53 AM #51766AnonymousHi, bisa kirimin code lainnya kamu?
sepertinya notes.dart dan notes_grid.dartJuly 18, 2022 at 11:45 AM #51768notes.dart coach..
import ‘dart:io’;
import ‘package:flutter/cupertino.dart’;
import ‘package:notes/api/note_api.dart’;
import ‘package:notes/database/database_helper.dart’;
import ‘package:notes/models/note.dart’;class Notes with ChangeNotifier {
List<Note> _notes = [
Note(
id: ‘N1’,
title: ‘Catatan Materi Flutter’,
note:
‘Flutter merupakan Software Development Kit (SDK) yang bisa membantu developer dalam membuat aplikasi mobile cross platform. Kelas ini akan mempelajari pengembangan aplikasi mobile yang dapat dijalankan baik di IOS maupun di Android’,
updatedAt: DateTime.parse(‘2021-05-19 20:33:33’),
createdAt: DateTime.parse(‘2021-05-19 20:33:33’),
),
Note(
id: ‘N2’,
title: ‘Target Pembelajaran Flutter’,
note:
‘Peserta dapat mengembangkan aplikasi mobile (IOS dan Android) menggunakan flutter,\nPeserta memahami konsep pengembangan aplikasi menggunakan flutter,\nPeserta dapat menjalankan aplikasi mobile di IOS dan Android ataupun Emulator,\nPeserta memahami bahasa pemrograman Dart,\nPeserta dapat mendevelop aplikasi mobile menggunakan flutter dan dart dari dasar secara berurutan.’,
updatedAt: DateTime.parse(‘2021-05-20 20:53:33’),
createdAt: DateTime.parse(‘2021-05-20 20:53:33’),
),
Note(
id: ‘N3’,
title: ‘Belajar Flutter di ITBOX’,
note: ‘Jangan lupa belajar flutter dengan video interactive di ITBOX.’,
updatedAt: DateTime.parse(‘2021-05-20 21:22:33’),
createdAt: DateTime.parse(‘2021-05-20 21:22:33’),
),
Note(
id: ‘N4’,
title: ‘Resep nasi goreng’,
note:
‘Nasi putih 1 piring\nBawang putih 2 siung, cincang halus\nKecap manis atau kecap asin sesuai selera\nSaus sambal sesuai selera\nSaus tiram sesuai selera\nGaram secukupnya\nKaldu bubuk rasa ayam atau sapi sesuai selera\nDaun bawang 1 batang, cincang halus\nTelur ayam 1 butir\nSosis ayam 1 buah, iris tipis\nMargarin atau minyak goreng 3 sdm.’,
updatedAt: DateTime.parse(‘2021-05-20 21:51:33’),
createdAt: DateTime.parse(‘2021-05-20 21:51:33’),
),
];Future<void> getAndSetNotes() async {
// tambahkan fungsi try & catch untuk mengatasi error
try {
_notes = await NoteApi().getAllNote();
// fungsi untuk gunakan getAllNote ke provider
await DatabaseHelper().insertAllNote(_notes);
notifyListeners();
} on SocketException {
// tambahkan fungsi agar saat internet tidak tersambung yang ditampilkan adalah data dari database
_notes = await DatabaseHelper().getAllNote();
notifyListeners();
} catch (e) {
return Future.error(e);
}
}List<Note> get notes {
// mengurutkan note ( yang di pin ditampilkan lebih dahulu)
List<Note> tempListNote = _notes.where((note) => note.isPinned).toList();
tempListNote.addAll(_notes.where((note) => !note.isPinned).toList());
return tempListNote;
}// menambahkan toggleIsPinned untuk merubah isPinned yang true ke false dan sebaliknya
Future<void> toggleIsPinned(String? id) async {
// menampung atau mencari note dengan id yang sama
int index = notes.indexWhere((note) => note.id == id);
try {
// melakukan validasi
if (index >= 0) {
_notes[index].isPinned = !_notes[index].isPinned;
// ganti tanggal update pada server
_notes[index] = _notes[index].copyWith(updatedAt: DateTime.now());
// tambahkan notifier untuk memberi tau widget yang listen ke provider bahwa data sudah berubah
notifyListeners();
// panggil fungsi toggleIsPinned pada API sebelum notifyListeners
await NoteApi().toggleIsPinned(
id, _notes[index].isPinned, _notes[index].updatedAt!);
// setelah update toggleIspinned ke API maka akan update toggleIspinned di databaseHelper
await DatabaseHelper().toogleIspinned(
id,
_notes[index].isPinned,
_notes[index].updatedAt!,
);
}
} catch (e) {
_notes[index].isPinned = !_notes[index].isPinned;
notifyListeners();
return Future.error(e);
}
}// 1. fungsi addNote untuk menambahkan note ke provider
Future<void> addNote(Note note) async {
try {
// 2. panggil fungsi postNote dan tambahkan await, future dan async
// 3. tampung return id dari API dengan membuat String id:
String? id = await NoteApi().postNote(note);
// 4. sebelum tambahkan notes ke dalam _notes buat note.copyWith(id: id saat kita post)
note = note.copyWith(id: id);
// setelah add note ke API maka akan add note di databaseHelper
await DatabaseHelper().insertNote(note);
_notes.add(note);
notifyListeners();
} catch (e) {
return Future.error(e);
}
}Note getNote(String? id) {
return _notes.firstWhere((note) => note.id == id);
}// Fungsi untuk update
Future<void> updateNote(Note newNote) async {
try {
// sebelum updateNote ke dalam listnote panggil dulu fungsi NoteApi
await NoteApi().updateNote(newNote);
// setelah update note ke API maka akan update note di databaseHelper
await DatabaseHelper().updateNote(newNote);
int index = _notes.indexWhere((note) => note.id == newNote.id);
_notes[index] = newNote;
notifyListeners();
} catch (e) {
return Future.error(e);
}
}// fungsi untuk delete note ketika di swap kiri atau kanan
Future<void> deleteNote(String? id) async {
// tambahkan fungsi agar pada saat error apa yang sudah di remove dibalikkan lagi
int index = _notes.indexWhere((note) => note.id == id);
Note tempNote = _notes[index];
try {
_notes.removeAt(index);
// _notes.removeWhere((note) => note.id == id);
notifyListeners();
// panggil fungsi delete pada note.api
await NoteApi().deleteNote(id);
// setelah delete note ke API maka akan delete note di databaseHelper
await DatabaseHelper().deleteNote(id);
} catch (e) {
_notes.insert(index, tempNote);
notifyListeners();
return Future.error(e);
}
}
}July 18, 2022 at 11:46 AM #51769ini yang notes_grid.dart coach
import ‘package:flutter/material.dart’;
import ‘package:notes/models/note.dart’;
import ‘package:notes/providers/notes.dart’;
import ‘package:notes/widgets/note_item.dart’;
import ‘package:provider/provider.dart’;class NotesGrid extends StatefulWidget {
@override
State<NotesGrid> createState() => _NotesGridState();
}class _NotesGridState extends State<NotesGrid> {
@override
Widget build(BuildContext context) {
// gunakan data provider
final notesProvider = Provider.of<Notes>(context);
List<Note> listNote = notesProvider.notes;
return Padding(
padding: EdgeInsets.all(12),
child: GridView.builder(
itemCount: listNote.length,
itemBuilder: (ctx, index) => NoteItem(
id: listNote[index].id,
ctx: context,
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
),
),
);
}
}July 18, 2022 at 12:10 PM #51770AnonymousHi, untuk error messagenya cuma itu aja kah?
bisa kasi lebih detail lagi?
mngkin seluruh dari error messagenyadan sekalian minta isi code dari note_api.dart ya
July 18, 2022 at 1:09 PM #51774g bisa di paste disini coach..saya coba buat post pertanyaan baru coach..
July 18, 2022 at 1:18 PM #51778namun saya ada dapat email dari fire base isinya:
notes
[Firebase] Akses klien ke ‘notes-9f78d-default-rtdb’ Realtime Database Anda akan berakhir dalam 4 hariAnda memilih untuk mulai mengembangkan aplikasi dalam Mode Uji, yang membuat instance Realtime Database Anda sepenuhnya terbuka ke internet. Karena pilihan ini membuat aplikasi Anda rentan terhadap penyerang, aturan keamanan database Anda dikonfigurasi untuk berhenti mengizinkan permintaan setelah 30 hari pertama.
Dalam 4 hari, semua permintaan klien ke instance Realtime Database Anda akan ditolak. Sebelum waktu tersebut, harap perbarui aturan keamanan agar aplikasi Anda dapat berfungsi sekaligus melindungi data Anda dengan tepat. Analisis dijalankan setiap hari; jika Anda telah mengubah aturan dalam 24 jam terakhir, perubahan tersebut mungkin tidak diperhitungkan.
ATURAN YANG SEGERA BERAKHIR
notes
Database
notes-9f78d-default-rtdbapa pengaruh ya coach ke API code nya?
July 18, 2022 at 1:19 PM #51779note.api
import ‘dart:convert’;
import ‘dart:io’;import ‘package:notes/models/note.dart’;
import ‘package:http/http.dart’ as http;// buat class yang berisi semua fungsi untuk koneksi ke server firebase
class NoteApi {
// buat fungsi untuk mendapatkan seluruh note (list)
// tambahkan Future dan async agar fungsi await bisa digunakan
Future<List<Note>> getAllNote() async {
// print(‘pertama dijalankan’);
final uri = Uri.parse(
‘https://notes-9f78d-default-rtdb.asia-southeast1.firebasedatabase.app/notes.json’);
// tambahakan try & catch untuk mengatasi error no internet/SocketException dan merubah tulisannya
List<Note> notes = [];
try {
// tambahkan await agar kode dibawah menunggu proses get data selesai
final response = await http.get(uri);print(response.statusCode);
if (response.statusCode == 200) {
// ubah data json menjadi map
final results = json.decode(response.body) as Map<String, dynamic>;
// looping map result ke List<Note>
results.forEach((key, value) {
notes.add(Note(
id: key,
title: value[‘title’],
note: value[‘note’],
isPinned: value[‘isPinned’],
updatedAt: DateTime.parse(value[‘updated_at’]),
createdAt: DateTime.parse(value[‘created_at’])));
});
} else {
throw Exception();
}
} on SocketException {
throw SocketException(‘Tidak dapat tersambung ke internet’);
} catch (e) {
throw Exception(‘Error terjadi kesalahan’);
}return notes;
}July 18, 2022 at 1:20 PM #51780// Buat fungsi note API untuk post note baru
// tambahkan Future pada string dan async agar fungsi await bisa digunakan
Future<String?> postNote(Note note) async {
final uri = Uri.parse(
‘https://notes-9f78d-default-rtdb.asia-southeast1.firebasedatabase.app/notes.json’);
// buat map untuk isi/body yang akan dikirim ke server
Map<String, dynamic> map = {
‘title’: note.title,
‘note’: note.note,
‘isPinned’: note.isPinned,
//1. karena encode akan mengubah data menjadi string json maka note.updatedAt dan note.createdAt di ubah menjadi string dengan toIso8601String
//2. tambahkan validasi karena migrasi ke null agar tidak error
‘updated_at’:
note.updatedAt == null ? null : note.updatedAt!.toIso8601String(),
‘created_at’:
note.createdAt == null ? null : note.createdAt!.toIso8601String()
};try {
// ubah map jadi string json
final body = json.encode(map);
// 1. melakukan post
// 2. tambahkan await agar kode dibawah menunggu proses get data selesai
final response = await http.post(uri, body: body);
if (response.statusCode == 200) {
return json.decode(response.body)[‘name’];
} else {
throw Exception();
}
} on SocketException {
throw SocketException(‘Tidak dapat tersambung ke internet’);
} catch (e) {
throw Exception(‘Error, terjadi kesalahan’);
}
}July 18, 2022 at 1:23 PM #51783// tambahkan fungsi agar saat note diubah maka akan terupdate juga pada server
Future<void> updateNote(Note note) async {
final uri = Uri.parse(
‘https://notes-9f78d-default-rtdb.asia-southeast1.firebasedatabase.app/notes/${note.id}.json’);
Map<String, dynamic> map = {
‘title’: note.title,
‘note’: note.note,
‘updated_at’: note.updatedAt!.toIso8601String(),
};try {
final body = json.encode(map);
final response = await http.patch(uri, body: body);
if (response.statusCode != 200) throw Exception();
} on SocketException {
throw SocketException(‘Tidak dapat tersambung ke internet’);
} catch (e) {
throw Exception(‘Error, terjadi kesalahan’);
}
}July 18, 2022 at 1:25 PM #51785// tambahkan fungsi toggleIspined agar saat note di PIN maka terupdate pada server
Future<void> toggleIsPinned(
String? id, bool? isPinned, DateTime updatedAt) async {
final uri = Uri.parse(
‘https://notes-9f78d-default-rtdb.asia-southeast1.firebasedatabase.app/notes/$id.json’);
Map<String, dynamic> map = {
‘isPinned’: isPinned,
‘updated_at’: updatedAt.toIso8601String(),
};
try {
final body = json.encode(map);
final response = await http.patch(uri, body: body);
if (response.statusCode != 200) throw Exception();
} on SocketException {
throw SocketException(‘Tidak dapat tersambung ke internet’);
} catch (e) {
throw Exception(‘Error, terjadi kesalahan’);
}
}July 18, 2022 at 1:26 PM #51786// fungsi untuk delete dan ubah atau kirim data tersebut ke server
Future<void> deleteNote(String? id) async {
final uri = Uri.parse(
‘https://notes-9f78d-default-rtdb.asia-southeast1.firebasedatabase.app/notes/$id.json’);
try {
final response = await http.delete(uri);
if (response.statusCode != 200) {
throw Exception();
}
} on SocketException {
throw SocketException(‘Tidak dapat tersambung ke internet’);
} catch (e) {
throw Exception(‘Error, terjadi kesalahan’);
}
}
}July 18, 2022 at 3:16 PM #51788AnonymousHi, untuk email tentang Realtime Database Anda akan berakhir dalam 4 hari. Itu maksutnya rules dari realtime database kamu di set agar hanya menerima request sampai dengan tanggal tertentu saja, karena pas pertama kali buat realtime database, kita memilih untuk mulai membuat database dalam test mode.
makanya kalau kamu lihat rules dari realtime database kamu.
kamu akan melihat code kurang lebih seperti ini{ "rules": { ".read": "now < 1660669200000", // 2022-8-17 ".write": "now < 1660669200000", // 2022-8-17 } }nah untuk mengatasi hal tersebut
kamu bisa ubah “now < 1660669200000” menjadi true saja agar kamu akan selalu ngebolehin untuk akses read dan write ke realtime database tanpa batasan waktu.jadi nanti rules kamu akan seperti ini.
{ "rules": { ".read": true, ".write": true, } } -
AuthorPosts
- You must be logged in to reply to this topic.