hello I am currently learning about streams in flutter and I came across a timer application. that involves me storing data using shared preferences. I have a thrown exception when I try to store the default preference to the phone I traced it back to this code block:
readSettings() async {
prefs = await SharedPreferences.getInstance();
int workTime = prefs.getInt(WORKTIME);
if (workTime == null) {
await prefs.setInt(WORKTIME, int.parse('30'));
}
int shortBreak = prefs.getInt(SHORTBREAK);
if (shortBreak == null) {
await prefs.setInt(SHORTBREAK, int.parse('5'));
}
int longBreak = prefs.getInt(LONGBREAK);
if (longBreak == null) {
await prefs.setInt(LONGBREAK, int.parse('20'));
}
setState(() {
txtWork.text = workTime.toString();
txtShort.text = shortBreak.toString();
txtLong.text = longBreak.toString();
});
}
this is the error I recieve:
Exception has occurred.
NoSuchMethodError (NoSuchMethodError: The setter 'text=' was called on null.
Receiver: null
Tried calling: text="30")
I think that most likely your error is not caused by SharedPreferences.
Also assuming that txtWork.text is a textEditingController.
Go up to where you defined TextEditingController textWork;
and change them to this:
TextEditingController textWork = TextEditingController ();
TextEditingController txtLong = TextEditingController ();
TextEditingController txtShort = TextEditingController ();
It should work, please update on what happens.
I think that txtWork the object that have .text is null
so you are trying to do this:
null.text = "30"
Check where you instantiate it.
I managed to do it by moving my textEditing controllers out of my intiState function
old code:
void initState() {
TextEditingController txtWork = TextEditingController();
TextEditingController txtShort = TextEditingController();
TextEditingController txtLong = TextEditingController();
readSettings();
super.initState();
}
new code:
TextEditingController txtWork = TextEditingController();
TextEditingController txtShort = TextEditingController();
TextEditingController txtLong = TextEditingController();
#override
void initState() {
readSettings();
super.initState();
}
Related
im new for both flutter and getx and i'm trying to make edit Form with getx , but i get Null .. how to fill TextEditingController after api response
class EditMarketerController extends GetxController {
final DashboardApiProvider dashboardApiProvider;
EditMarketerController({required this.dashboardApiProvider});
MarketerToEdit marketer = MarketerToEdit();
TextEditingController usernameController =
TextEditingController();
TextEditingController emailController =
TextEditingController();
#override
void onInit() {
_getMarketer(); //----- **api call**
// Wait until the completion of the data call and then fill ↓↓↓
final usernameController = TextEditingController(text:
marketer.username);
final emailController = TextEditingController(text:
marketer.email);
super.onInit();
}
Use callBack in your _getMarketer method like this.
_getMarketer({Function? callBack}){
/// implement your api and put callBack in your api call success like this
if(callBack != null){
callBack();
}
}
I'm trying to give default value to a TextFormField using text: parameter in it's controller
class _EditProfileState extends State<EditProfile> {
String firstName = "Sushant";
TextEditingController firstNameController = TextEditingController(text: firstName);
But am getting the following error
The instance member 'firstName' can't be accessed in an initializer.
Try replacing the reference to the instance member with a different expression
Try to use late with TextEditingController then initialize TextEditingController inside initState.
class _EditProfileState extends State<EditProfile> {
String firstName = "Sushant";
late TextEditingController firstNameController;
#override
void initState() {
firstNameController = TextEditingController(text: firstName);
}
}
#override
void dispose() {
firstNameController.dispose();
super.dispose();
}
Or use
class _EditProfileState extends State<EditProfile> {
String firstName = "Sushant";
TextEditingController firstNameController = TextEditingController();
#override
void initState() {
firstNameController.text = firstName;
}
}
#override
void dispose() {
firstNameController.dispose();
super.dispose();
}
Here you are trying to initiate firstNameController with a non-constant value. firstName here is not static and belongs to the instance.
When the class is created, it cannot access properties of itself because they are not created either (nothing guarantees that firstName is created before firstNameController).
However, you can use the late keyword:
class _EditProfileState extends State<EditProfile> {
String firstName = "Sushant";
late TextEditingController firstNameController = TextEditingController(text: firstName);
}
late will make firstNameController "lazy". It means it is only going to be evaluated when called (and not when your class instance is created). Therefore, when using the late keyword, when evaluated, your class is already created with its properties and you can access them.
Since you are using State, set default text in initState.
This will only trigger once when Widget is initialized. Also set all TextEditingController as final, you should not assign new one later.
Last, remember to dispose it.
String firstName = "Sushant";
final TextEditingController firstNameController = TextEditingController();
#override
void initState() {
firstNameController.text = firstName;
super.initState();
}
#override
void dispose() {
firstNameController.dispose();
super.dispose();
}
I am pulling data from Firestore and Editing, and when I click on the data to edit, I don't see it showing anything, however when I write the information and Save. Instead of changing the Edited Field, I get a new document with the edited field.
For example in the code, I edit the name => I will have a new document with the email reused and name changed.
And here is my code:
class EditHouse extends StatefulWidget {
final House house;
EditHouse(this.house);
class _EditHouseState extends State<EditHouse> {
final nameController = TextEditingController();
final emailController = TextEditingController();
#override
void dispose() {
nameController.dispose();
emailController.dispose();
super.dispose();
}
#override
void initState() {
if (widget.house == null) {
nameController.text == "";
emailController.text == "";
new Future.delayed(Duration.zero, () {
final houseProvider =
Provider.of<HouseProvider>(context, listen: false);
houseProvider.loadValues(House(
name: '',
email: ''));
});
} else {
nameController.text = widget.house.name;
emailController.text = widget.house.email;
new Future.delayed(Duration.zero, () {
final houseProvider =
Provider.of<HouseProvider>(context, listen: false);
houseProvider.loadValues(widget.house);
});
}
super.initState();
}}
I don't know if the problem lies here or not EditHouse(this.house);
when I can't use it EditHouse([required this.house]); I will get an error message Can't have modifier 'required' here
The following code is part of my login screen. I am using shared_preferences to save the remember me checkbox and the user name. The checkbox value is working, but the user name is not being set. I know it is being saved because I can see the value using print. But I guess it is being set too late, as my TextField is blank. Any ideas?
class RmoLogin extends StatefulWidget {
static const String id = 'login_screen';
#override
_RmoLoginState createState() => _RmoLoginState();
}
class _RmoLoginState extends State<RmoLogin> {
final TextStyle style = TextStyle(fontFamily: 'Montserrat', fontSize: 20.0);
final TextEditingController usernameController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
bool showSpinner = false;
bool rememberMe = false;
String userName = '';
_saveRememberUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('username', usernameController.text);
prefs.setBool('remember', rememberMe);
}
_getRememberUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
userName = prefs.getString('username') ?? '';
rememberMe = prefs.getBool('remember') ?? false;
}
#override
void initState() {
super.initState();
_getRememberUser();
if (rememberMe) {
usernameController.text = userName;
}
}
#override
Widget build(BuildContext context) {
final userField = UserTextField(style: style, usernameController: usernameController);
final passwordField = PasswordTextField(style: style, passwordController: passwordController);
final rememberMeCheckbox = Checkbox(
value: rememberMe,
onChanged: (newValue) {
setState(() {
rememberMe = newValue;
});
},
);
Because the SharedPreferences instantiation is asynchronous and the build method itself is not, by the time the instance is created and the value is accessed, the build method would have already been called and your widgets built.
However, For things like SharedPreferences and databases, the best way to implement them is to use the Singleton approach, i.e, one instance that you can use across the entire application.
In this case instead of creating a new SharedPreferences instance whenever either method is called, it will be best to create a single instance of it and use that instance to update the set and get the values.
You could also create a service for the SharedPreferences which you could use across the entire application.
class SharedPreferencesService {
final SharedPreferences _prefs;
SharedPreferencesService(this._prefs);
// define methods here
}
Then in your main method, you can create an instance of SharedPreferences and use it to initialize the SharedPreferencesService.
eg.
SharedPreferencesService service;
Future<void> main() async {
// flutter will complain if this isn't present
WidgetsFlutterBinding.ensureInitialized();
final prefs = await SharedPreferences.getInstance();
service = SharedPreferencesService(prefs);
runApp(YourApp());
}
Then wherever you want to use it in your app, you can call the method name on the service. It is best to use Dependency Injection for the SharedPreferencesService though, you can try the get_it library.
Just a brief look.... but
You are calling _getRememberUser synchronously within initState() when it is an async method
initState() isn't the correct place to be calling it as initState() itself is a synchronus #override.
My solution would be to use a FutureBuilder in your build() method, and call _getRememberUser there.
You just need to update the state that's it check the below solution:
bool rememberMe = false;
String userName = '';
#override
void initState() {
// TODO: implement initState
super.initState();
_getRememberUser();
}
_getRememberUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
userName = prefs.getString('username') ?? '';
rememberMe = prefs.getBool('remember')?? false;
});
if (rememberMe) {
usernameController.text = userName;
}
print(userName +'-->'+rememberMe.toString());
}
Happy Coding!!
I'm learning Flutter and I have in my app, two textFields linked to textControllers in an AlertDialog to get the input from a user as text and display it in cards in the body of the screen. My problem, that I can't solve on my own, is that after I added setState(() {}) in the 'Save' button of the AlertDialog, for the text to acutally get displayed on the screen in body, well after this change the text entered in the TextFields doesn't get cleared aymore after pressing 'Save'.
My Code:
class _HomeScreenState extends State<HomeScreen> {
final TextEditingController titleController = TextEditingController();
final TextEditingController textController = TextEditingController();
DummyDataProvider notes;
#override
void dispose() {
// Clean up the controller when the widget is disposed.
titleController.dispose();
textController.dispose();
super.dispose();
}
The textControllers in question:
MaterialButton(
onPressed: () {
setState(() {
final title = titleController.text;
final text = textController.text;
NoteProvider.insertNote({'title': title, 'text': text});
Navigator.pop(context);
});
What i mean by text not disposing:
https://imgur.com/a/8pyTPM7,
https://imgur.com/a/lr8a3Eh
Thank you in advance!
Why not just use clear()?
final _textController = TextEditingController();
.....
.....
onPressed: () {
_textController.clear();
}
You can reset your text controllers.
For example in onpressed:
titleController = new TextEditingController();
textController = new TextEditingController();
Set state is not required for this.
TextEditingController
Is very expensive object, don't create it often
just use
TextEditingController.text == '';
to clear the text,