我目前在 Flutter 中使用 GetX 和 Sqflite,遇到插入后資料更新的問題。
首先,有一個 LoadingScreen 檢查用戶資料庫中是否有任何條目。如果沒有,那么它會打開用戶填寫的注冊頁面。如果用戶資料庫中已有條目,則打開登錄頁面。
注冊頁面完成后,資料將寫入用戶資料庫,然后用戶將被帶到主頁,其中用戶名顯示在抽屜中。
用戶在 LoadingScreenController 中的 .obs 上,我在主頁中使用 Obx 作為用戶名。盡管如此,插入命令完成后的資料不會自動更新。
但是,如果我在 HomePage 的 init 中再次呼叫 fetch 函式,那么新的資料就會被帶進來。
我的問題是,每次更新資料庫時我都必須運行 fetch 函式嗎?它不符合 Getx 的目的嗎?顯然,我在某個地方錯了。
下面是 Home Page、LoadingScreen、LoadingScreenController、SignUp Page 以及 Database Helper 的代碼。
將不勝感激任何幫助。
主頁代碼:
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
LoadingController loadingController = Get.find();
var notifyHelper;
@override
void initState() {
super.initState();
notifyHelper = NotifyHelper();
notifyHelper.initializeNotification();
notifyHelper.requestIOSPermissions();
username = loadingController.users[0].name.toString();
usermail = loadingController.users[0].mail.toString();
}
String name = '', usernames = '', usermail = '';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: _appbar(context),
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Center(
child: Obx(() => Text(loadingController.users.length.toString())),
),
),
drawer: MyDrawer(usernames, usermail),
);
}
_appbar(BuildContext context) {
return AppBar(
//leading: Drawer(),
actions: [
const Icon(
Icons.person,
size: 20.0,
),
],
);
}
}
加載畫面
class LoadingScreen extends StatelessWidget {
final loadingController = Get.put(LoadingController());
final splashController = Get.put(SplashController());
final TextEditingController passwordController = TextEditingController();
int index = 0;
LoadingScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
//backgroundColor: Colors.black,
body: SafeArea(
child: SingleChildScrollView(
child: Column(
children: [
const SizedBox(
height: 20,
),
_splash(context),
GetBuilder<SplashController>(
builder: (_) => splashController.completes.value == false
? MyTextContainer(
20.0,
'Counting Your Money ... \n Please wait',
.4,
true,
subTitleStyle)
: const Text('')),
GetBuilder<LoadingController>(
builder: (_) => loadingController.users.length > 0
? _signin(
context, loadingController.users[0].name.toString())
: _signup(context),
),
],
),
),
),
);
}
onTap() {
if (passwordController.text !=
loadingController.users[0].password.toString()) {
Get.snackbar('Alert', 'Passwords do not match',
snackPosition: SnackPosition.BOTTOM);
} else {
Get.to(() => const Home());
}
}
Widget _splash(BuildContext context) {
return Center(
child: GetBuilder<SplashController>(
builder: (_) => ScaleTransition(
scale: splashController.anim,
child: Container(
margin: const EdgeInsets.only(left: 8.0, top: 8.0, right: 8.0),
padding: const EdgeInsets.only(bottom: 12.0),
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [primaryClr, yellowClr],
),
borderRadius: BorderRadius.circular(18),
border: Border.all(color: Colors.white, width: 2.0),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Lottie.asset('assets/loadingScreen.json',
height: MediaQuery.of(context).size.height * .40),
Text('Welcome ', style: titleStyle),
],
)),
),
));
}
Widget _signin(BuildContext context, String username) {
return GetBuilder<SplashController>(
builder: (_) => ScaleTransition(
scale: splashController.anim,
child: Container(
margin: const EdgeInsets.only(left: 10.0, right: 10.0),
child: Column(
children: [
Text(
"Welome back $username \nEnter Password to Sign-In",
textAlign: TextAlign.center,
),
MyTextInputField(
title: 'Password',
hint: 'Enter Your Password',
textStyle: subTitleStyle,
textInputType: TextInputType.number,
textCapital: TextCapitalization.none,
controller: passwordController,
isObscure: true,
),
const SizedBox(
height: 20.0,
),
passwordController.text.isEmpty
? Container()
: MyButton(
label: 'SignIn',
onTap: onTap,
textStyle: titleStyle,
colorScheme: primaryClr,
),
],
),
),
),
);
}
Widget _signup(BuildContext context) {
return GetBuilder<SplashController>(
builder: (_) => ScaleTransition(
scale: splashController.anim,
child: Column(
children: [
Text(
"This is your first Login \nClick here to Sign-Up",
style: subTitleStyle,
),
const SizedBox(
height: 20.0,
),
MyButton(
label: 'Sign-Up',
textStyle: titleStyle,
onTap: () => Get.to(() => const SignUp()),
colorScheme: primaryClr,
),
],
),
),
);
}
}
加載螢屏控制器
class LoadingController extends GetxController {
// ignore: deprecated_member_use
//var allacc = List<AllAccounts>().obs;
var users = <User>[].obs;
var allaccounts = <AllAccounts>[].obs;
List<AllAccounts> allacc = <AllAccounts>[].obs;
@override
void onInit() async {
await fetchUsers();
await fetchAllAccounts();
super.onInit();
}
fetchUsers() async {
var userList = await DatabaseHelper.db.getAllUsers();
users.assignAll(userList);
update();
}
fetchAllAccounts() async {
await DatabaseHelper.db.getAllAccounts().then((accountList) {
allaccounts.value = accountList.cast<AllAccounts>();
update();
});
}
Future<void> insertUser({User? user}) async {
await DatabaseHelper.db.insertUser(user!);
update();
}
}
DatabaseHelper(沒有資料庫創建代碼)
Future<int> insertUser(User user) async {
Database dbase = await database;
var res = dbase.insert(User.tblUser, user.toMap());
return res;
}
Future<List<User>> getAllUsers() async {
Database db = await database;
List<Map<String, dynamic>> username = await db.rawQuery('''
SELECT COALESCE(${User.colUserId},'') as 'id', COALESCE(${User.colUserName},'') as 'name',
COALESCE(${User.colUserPhone},'') as 'phone', COALESCE(${User.colUserMail},'9999') as 'mail',
COALESCE(${User.colUserPassword},'') as 'password', COALESCE(${User.colUserStartDate},'') as 'startdate'
FROM ${User.tblUser}
''');
//print('Printing from db $usernames');
return username.isEmpty
? []
: username.map((e) => User.fromMap(e)).toList();
}
報名
class SignUp extends StatefulWidget {
const SignUp({Key? key}) : super(key: key);
@override
State<SignUp> createState() => _SignUpState();
}
class _SignUpState extends State<SignUp> {
final TextEditingController nameController = TextEditingController();
final TextEditingController phoneController = TextEditingController();
final TextEditingController mailController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
final TextEditingController repasswordController = TextEditingController();
final TextEditingController startdateController = TextEditingController();
final LoadingController loadingController = Get.find();
String alertmsg = '';
Future<void> onTap() async {
if (_validateText() == null) {
_showSnackBar('Writing Data... Please wait');
_addDataToDB();
}
//Get.to(() => Home());
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: _appbar(context),
body: SafeArea(
child: Container(
padding: const EdgeInsets.only(left: 20, top: 10, right: 20),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Sign-Up', style: headingStyle),
MyTextInputField(
title: 'Name',
hint: 'Enter First Name and Last Name here',
textStyle: subTitleStyle,
textInputType: TextInputType.text,
textCapital: TextCapitalization.words,
controller: nameController,
),
MyTextInputField(
title: 'Phone Number',
hint: 'Phone Number is to send reminders - Required',
textStyle: subTitleStyle,
textInputType: TextInputType.number,
textCapital: TextCapitalization.none,
controller: phoneController,
),
MyTextInputField(
title: 'Mail ID',
hint: 'Mail ID is to back up the Data - Required',
textStyle: subTitleStyle,
textInputType: TextInputType.emailAddress,
textCapital: TextCapitalization.none,
controller: mailController,
),
MyTextInputField(
title: 'Password',
hint: 'Enter Pasword Here - Minimum of 4 digits',
textStyle: subTitleStyle,
textInputType: TextInputType.number,
textCapital: TextCapitalization.none,
controller: passwordController,
isObscure: true,
),
MyTextInputField(
title: 'Confirm Password',
hint: 'Re-enter Your Pasword Here',
textStyle: subTitleStyle,
textInputType: TextInputType.number,
textCapital: TextCapitalization.none,
controller: repasswordController,
isObscure: true,
),
MyTextInputField(
title: 'Start Date',
hint: 'Date from when the Transactions start',
textStyle: subTitleStyle,
textInputType: TextInputType.number,
textCapital: TextCapitalization.none,
controller: startdateController,
widget: IconButton(
icon: const Icon(Icons.calendar_today_outlined),
onPressed: () {
print('Printed');
},
)),
const SizedBox(
height: 20.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
MyButton(
label: 'Confirm',
onTap: onTap,
textStyle: titleStyle,
colorScheme: primaryClr,
)
],
)
],
),
),
),
));
}
_addDataToDB() async {
await loadingController
.insertUser(
user: User(
name: nameController.text,
phone: phoneController.text,
mail: mailController.text,
password: passwordController.text,
startdate: DateTime.now().toString(),
created: DateTime.now().toString()))
.then((value) {
_showSnackBar('Data Saved');
Get.to(() => Home());
});
}
_validateText() {
if (nameController.text.isEmpty) {
alertmsg = 'Name is Required';
_showSnackBar(alertmsg);
return alertmsg;
} else if (_validatePhone(phoneController.text) != null) {
_showSnackBar(alertmsg);
return alertmsg;
} else if (_validateMail(mailController.text) != null) {
_showSnackBar(alertmsg);
return alertmsg;
} else if (_validatePassword(
passwordController.text, repasswordController.text) !=
null) {
_showSnackBar(alertmsg);
return alertmsg;
}
return null;
}
String? _validatePhone(String value) {
if (value.isEmpty || value.length < 10) {
alertmsg = 'Please enter valid Phone Number';
// _showSnackBar(alertmsg);
return alertmsg;
}
return null;
}
String? _validateMail(String value) {
bool emailValid = RegExp(
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'* -/=?^_`{|}~] @[a-zA-Z0-9] \.[a-zA-Z] ")
.hasMatch(value);
if (!emailValid) {
alertmsg = 'Please enter valid mail ID';
return alertmsg;
}
return null;
}
String? _validatePassword(String value1, String value2) {
print('$value1 $value2');
if (!value1.isNum && value1.length < 4) {
alertmsg = 'Password should be atleast a 4 digit Number ';
_showSnackBar(alertmsg);
return alertmsg;
} else if (value2.isEmpty) {
alertmsg = 'Confirm Password';
_showSnackBar(alertmsg);
return alertmsg;
} else if (value1 != value2) {
alertmsg = 'Passwords do not match';
_showSnackBar(alertmsg);
return alertmsg;
}
}
_showSnackBar(String value) {
Get.snackbar('Alert', value, snackPosition: SnackPosition.BOTTOM);
}
_appbar(BuildContext context) {
return AppBar(
backgroundColor: Theme.of(context).colorScheme.primary,
leading: InkWell(
onTap: () {
Get.back();
},
child: const Icon(Icons.arrow_back),
),
);
}
}
uj5u.com熱心網友回復:
您必須在每次添加/更新/洗掉操作后呼叫 fetch data,除非您的資料庫以某種方式回傳流。它并沒有違背 GetX 的目的。這是預期的行為。用戶應該在他們的代碼中明確定義他們想要做什么。
另一件事:您GetBuilder在使用.obs. 這不會起作用,因為GetBuilder它不是反應性的,并且不會在可觀察的 ( .obs) 更改時做出反應/更新 UI。您應該使用GetXorObx代替。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/410666.html
標籤:
上一篇:從Dart隔離中捕獲例外
