Error calling a widget from one Screen while no erro calling the same widget from another - flutter

Getting the following error:
The method '[]' was called on null.
Receiver: null
Tried calling: []("uid")
The relevant error-causing widget was: Container file:///C:/Users/dkasa/Downloads/MICS%20Download/grocery_app/lib/screens/homeScreen.dart:28:14 When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
#1 _VendorCategoriesState.didChangeDependencies (package:grocery_app/widgets/categories_widget.dart:29:88)
#2 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4653:11)
#3 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4469:5)
The widget below, categories_widget.dart, works when called from vendor_home_screen but gets the error when called from HomeScreen. I am not seeing a difference between the vendor_screen and the HomeScreen as to why the error appears.
categories_widget
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:grocery_app/providers/store_provider.dart';
import 'package:grocery_app/services/product_services.dart';
import 'package:persistent_bottom_nav_bar/persistent-tab-view.dart';
import 'package:grocery_app/screens/product_list_screen.dart';
import 'package:provider/provider.dart';
class VendorCategories extends StatefulWidget {
#override
_VendorCategoriesState createState() => _VendorCategoriesState();
}
class _VendorCategoriesState extends State<VendorCategories> {
ProductServices _services = ProductServices();
List _catList = [];
#override
void didChangeDependencies() {
var _store = Provider.of<StoreProvider>(context);
FirebaseFirestore.instance
.collection('products').where('seller.sellerUid',isEqualTo: _store.storedetails['uid'])
.get()
.then((QuerySnapshot querySnapshot) => {
querySnapshot.docs.forEach((doc) {
//add all this in a list
setState(() {
_catList.add(doc['category']['mainCategory']);
});
}),
});
super.didChangeDependencies();
}
#override
Widget build(BuildContext context) {
var _storeProvider = Provider.of<StoreProvider>(context);
return FutureBuilder(
future: _services.category.get(),
builder: (BuildContext context,AsyncSnapshot<QuerySnapshot>snapshot){
if(snapshot.hasError){
return Center(child: Text('Something went wrong..'));
}
if(_catList.length==0){
return Center(child: CircularProgressIndicator(),);
}
if(!snapshot.hasData){
return Container();
}
return SingleChildScrollView(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Material(
elevation: 4,
borderRadius: BorderRadius.circular(6),
child: Container(
height: 60,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
image: DecorationImage(
fit: BoxFit.cover,
image: AssetImage('images/background.JPG')
)
),
child: Center(
child: Text('Shop by Category',style: TextStyle(
shadows: <Shadow>[
Shadow(
offset: Offset(2.0,2.0),
blurRadius: 3.0,
color: Colors.black
)
],
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 30
),),
),
),
),
),
Wrap(
direction: Axis.horizontal,
children: snapshot.data.docs.map((DocumentSnapshot document){
return _catList.contains(document.data()['name']) ? //only if _catlList contain the category name from selected vendor
InkWell(
onTap: (){
_storeProvider.selectedCategory(document.data()['name']);
_storeProvider.selectedCategorySub(null);
pushNewScreenWithRouteSettings(
context,
settings: RouteSettings(name: ProductListScreen.id),
screen: ProductListScreen(),
withNavBar: true,
pageTransitionAnimation: PageTransitionAnimation.cupertino,
);
},
child: Container(
width: 120,height: 150,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.grey,
width: .5
)
),
child: Column(
children: [
Center(
child: Image.network(document.data()['image']),
),
Padding(
padding: const EdgeInsets.only(left: 8,right: 8),
child: Text(document.data()['name'],textAlign: TextAlign.center,),
),
],
),
),
),
) : Text('');
}).toList(),
),
],
),
);
});
}
}
vendor_home_screen
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:grocery_app/widgets/categories_widget.dart';
import 'package:grocery_app/widgets/vendor_appbar.dart';
import 'package:grocery_app/widgets/vendor_banner.dart';
import 'package:grocery_app/widgets/products/featured_products.dart';
import 'package:grocery_app/widgets/products/best_selling_product.dart';
import 'package:grocery_app/widgets/products/recently_added_products.dart';
class VendorHomeScreen extends StatelessWidget {
static const String id = 'vendor-screen';
#override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
VendorAppBar(),
];
},
body: ListView(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
children: [
VendorBanner(),
VendorCategories(),
//Recently Added Products
//Best Selling Products
//Featured Products
RecentlyAddedProducts(),
FeaturedProducts(),
BestSellingProduct()
],
),
),
);
}
}
HomeScreen
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:grocery_app/providers/store_provider.dart';
import 'package:grocery_app/widgets/categories_widget.dart';
import 'package:grocery_app/widgets/image_slider.dart';
import 'package:grocery_app/widgets/my_appbar.dart';
import 'package:grocery_app/widgets/near_by_store.dart';
import 'package:grocery_app/widgets/top_pick_scree.dart';
import 'package:provider/provider.dart';
class HomeScreen extends StatelessWidget {
static const String id = 'home-screen';
#override
Widget build(BuildContext context) {
Provider.of<StoreProvider>(context,listen:false);
return Scaffold(
backgroundColor: Colors.grey[200],
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled){
return [
MyAppBar()
];
},
body: ListView(
shrinkWrap: true,
padding: EdgeInsets.only(top: 0.0),
children: [
ImageSlider(),
Container(
color: Colors.white,
child: VendorCategories(),
),
Container(
color: Colors.white,
child: TopPickStore(),
),
Padding(
padding: const EdgeInsets.only(top: 6),
child: NearByStores(),
),
],
),
),
);
}
}

As the Home has already a list, So when adding another list that comes a problem :
body: ListView(
ShrinkWrap: true,
padding: EdgeInsets.only(top: 0.0),
children: [
ImageSlider(),
Container(
color: Colors.white,
child: VendorCategories(),
),
add
sinkWrap :true in your Home Page then Try again hope this will solve your problem .

Related

How can I save messages on firestore and display the messages on screen?

I have been working on the messaging functionality of an app that I am currently working on. I have implemented the Firestore code however, it is storing the messages in the collection and as well as not displaying the messages on-screen. The message is still left on the Text Field. Below is the code and any assistance will be highly appreciated.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
class MessageCenter extends StatefulWidget {
const MessageCenter({super.key});
#override
State<MessageCenter> createState() => _MessageCenterState();
}
class _MessageCenterState extends State<MessageCenter> {
final TextEditingController _text = TextEditingController();
final firestore = FirebaseFirestore.instance;
final auth = FirebaseAuth.instance;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
StreamBuilder(
stream: firestore
.collection('chatrooms')
.doc()
.collection('message')
.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
return snapshot.hasData
? Expanded(
child: ListView.builder(
reverse: true,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, i) {
return Card(
child: Text(
snapshot.data!.docs[i]['msg'],
),
);
}),
)
: Container();
}),
SizedBox(
height: 55,
child: Row(
children: [
Expanded(
flex: 5,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white30,
borderRadius: BorderRadius.circular(11),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: _text,
decoration: const InputDecoration(
hintText: 'Write Message',
)),
),
),
),
),
Expanded(
flex: 2,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: InkWell(
onTap: () {
firestore
.collection('chatrooms')
.doc('chatrooms')
.collection('message')
.add({
'sender': auth.currentUser!.email,
'time': DateFormat('hh:mm').format(DateTime.now()),
'msg': _text.text,
});
},
child: Container(
decoration: BoxDecoration(
color: Colors.deepOrange,
borderRadius: BorderRadius.circular(11),
),
child: const Center(
child: Icon(
Icons.send,
size: 30,
),
),
),
),
),
),
],
),
),
],
),
);
}
}
to save message to firestore, you need first of all create model class, firestoreService class, chatRoomRepository class, chatRepository class, chatService class, and controller class`. this is for proper separation of concern and organizing business logic. But for the purposes of this demo, here is the basic function for saving your message to firestore.
Future<void> saveMessage() async {
final chatRoomId = 'your_chatRoom_id_here';
final messageId = 'your_message_id_here';
final path = 'chatRooms/$chatRoomId/messages/$messageId';
final _service = FirebaseFirestore.instance.doc(path);
final sender = auth.currentUser!.email;
final time = DateFormat('hh:mm').format(DateTime.now());
final msg = _text.text;
try{
await _service
.set({
"id": messageId,
'sender': sender,
'time': time,
'msg': msg
});
} on FirebaseException catch(e){
print(e);
}
}

Box not found ERROR when calling Hive.openBox()

Box not found. Did you forget to call Hive.openBox()? is the result of a call to Hive.openBox(). It is shown in the console. However the widget works fine and the contents of the box is shown correctly! I mean I know that the box is NOT open, that's why I open it...
Error message:
======== Exception caught by widgets library =======================================================
The following HiveError was thrown building FutureBuilder<Box<CreditCardOverview>>(dirty, state: _FutureBuilderState<Box<CreditCardOverview>>#d0a4f):
Box not found. Did you forget to call Hive.openBox()?
My flutter code:
// ...
Expanded(
child: FutureBuilder(
future: Hive.openBox<CreditCardOverview>('ccOverview'),
builder: (BuildContext context, AsyncSnapshot snapshot) {
// ... builder function checking snapshot etc.
}
// ....
UPDATE
This is the complete code of the state :
class _FinancialsListSmallState extends State<FinancialsListSmall> {
#override
Widget build(BuildContext context) {
final sizeX = MediaQuery.of(context).size.width;
final sizeY = MediaQuery.of(context).size.height - MediaQuery.of(context).viewInsets.bottom;
return SafeArea(
child: Container(
width: sizeX,
height: sizeY,
child: Column(
children: [
PageTitleSmall(titleText: 'My Credit Cards', leadingIcon: Icon(Icons.credit_card)),
Expanded(
child: FutureBuilder(
future: Hive.openBox<CreditCardOverview>('ccOverview'),
builder: (BuildContext context, AsyncSnapshot snapshot) {
List<Widget> children;
if (snapshot.hasData) {
children = <Widget>[
const Icon(
Icons.check_circle_outline,
color: Colors.green,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Result: ${snapshot.data}'),
)
];
} else if (snapshot.hasError) {
children = <Widget>[
const Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
} else {
children = const <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
];
}
return ListView(
children: showCreditCardOverview(),
);
},
),
),
],
),
),
);
}
Any ideal what is going on here?
Open the box in main.dart instead of a particular file.
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
Void main()async{
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
Hive.registerAdapter(TAdapter());
await Hive.openBox<T>('boxName');
}
And now you can use this box in any file you want. For instance :
In example.dart
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
class _ExampleScreenState extends State<ExampleScreen>{
Box<T> boxName = Hive.box<T>('boxName');
#override
Widget build(BuildContext context) {
//your code here
}
}

Flutter Unhandled Exception: NoSuchMethodError: The getter 'uid' was called on null

First of all, I would like to say I have seen all the previous posts on this error but none of them resolved my issue and that's why I am posting it.
Actually, I have understood the problem but unable to resolve it. So, the below dart file is my HomeScreen().
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:mukti/authentication/firestore_service.dart';
import 'package:mukti/schedule/task.dart';
import 'package:mukti/schedule/taskdata.dart';
import 'package:provider/provider.dart';
import 'add_class.dart';
import 'package:firebase_auth/firebase_auth.dart' as auth;
class HomeScreen extends StatefulWidget {
static final String routeName = 'homeScreen';
final auth.User firebaseUser;
HomeScreen({this.firebaseUser});
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final FirestoreService firestoreService = FirestoreService();
#override
Widget build(BuildContext context) {
print("HomeScreen");
print(widget.firebaseUser);
return Scaffold(
body: SafeArea(
child: SizedBox.expand(
child: Padding(
padding: const EdgeInsets.all(48.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleChildScrollView(
child: Container(
width: MediaQuery.of(context).size.width,
height: 450,
color: Colors.yellow[100],
child: generateTaskList(),
),
),
SizedBox(height: 45),
/* Add Class Button */
Center(
child: GestureDetector(
onTap: () {
Navigator.push(
context, MaterialPageRoute(
builder: (context) => AddClass(),
),
);
},
child: Container(
height: 75,
width: 75,
decoration: BoxDecoration(
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.grey,
offset: Offset(0, 4), //(x,y)
blurRadius: 1.0,
),
],
color: Color(0xFFF9A826),
),
child: Icon(
Icons.add,
size: 35,
color: Colors.white,
),
),
),
),
],
),
),
),
),
);
}
Widget generateTaskList() {
//print("Firebase User : ${widget.firebaseUser.uid}");
Provider.of<TaskData>(context, listen: false).loadTaskList(widget.firebaseUser);
print('List Generated');
var taskListLength = Provider.of<TaskData>(context, listen: false).getTaskListCount();
return Consumer<TaskData>(
builder: (context, taskData, child) => ListView.builder(
itemCount: taskData.taskList.length,
itemBuilder: (context, index) {
print("TaskList");
return Container(
padding: EdgeInsets.all(16.0),
decoration: new BoxDecoration (
borderRadius: BorderRadius.circular(10),
color: Color(0xFFF9A826),
),
child: ListTile(
title: Text(
taskData.taskList[index].description ?? 'default',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
subtitle: Text(
"${Util.getFormattedDate(taskData.taskList[index].scheduledDateTime)}" ?? 'default',
style: TextStyle(
color: Colors.white54,
),
),
),
);
}
)
);
}
}
class Util {
static String getFormattedDate(DateTime dateTime) {
return new DateFormat("EEE, MMM d, y").format(dateTime);
}
}
Initially, firebaseUser is not null, I have crossed checked it and it is printing the data in the app but when I add more entries from AddClass() and returns to HomeScreen() again, firebaseUser becomes null and no data is shown in the app anymore.
The below code is my AddClass() code:
import 'package:flutter/material.dart';
import 'package:mukti/authentication/authService.dart';
import 'package:mukti/authentication/firestore_service.dart';
import 'package:mukti/schedule/scheduled_date.dart';
import 'package:mukti/schedule/task.dart';
import 'package:mukti/ui_pages/main_screen/timepicker.dart';
import 'package:provider/provider.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'home_screen.dart';
class AddClass extends StatefulWidget {
static final String routeName = 'addClass';
#override
_AddClassState createState() => _AddClassState();
}
class _AddClassState extends State<AddClass> {
final FirestoreService firestoreService = FirestoreService();
#override
Widget build(BuildContext context) {
print("Add Class Screen");
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Color(0xFFFFFFE5),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
/* Meeting url TextField Widget */
/* Description TextField Widget */
/* Calender */
/* Add Class Button */
Expanded(
child: GestureDetector(
onTap: () async{
auth.User firebaseUser = await Provider.of<AuthService>(context, listen: false).getUser();
DateTime scheduledDateTime = Provider.of<ScheduledDate>(context, listen: false).scheduledDateTime;
print(scheduledDateTime);
print(firebaseUser);
final task = Task(
link: 'xyz',
isDone: false,
description: 'xyz',
scheduledDateTime: scheduledDateTime,
);
firestoreService.addTask(firebaseUser, task);
print('Task Added');
Navigator.popAndPushNamed(context,
HomeScreen.routeName,
arguments: firebaseUser,
);
},
child: Align(
alignment: FractionalOffset.bottomCenter,
child: Container(
height: 50,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Color(0xFFF9A826),
),
child: Center(
child: Text(
'SCHEDULE CLASS',
style: Theme.of(context).textTheme.bodyText1.copyWith(
color: Colors.white,
fontWeight: FontWeight.w700,
fontSize: 16,
letterSpacing: 0.5,
),
)
)
),
),
),
),
],
),
),
);
}
}
Actually, I have removed unnecessary codes, so after adding one more class to the database, I return to HomeScreen but this time firebaseUser becomes null, although I am sending it in the argument of the routes HomeScreen is receiving null. This is my problem.
How can I resolve this..?
If anyone needs more information, feel free to ask me.
Thanks

How to save downloaded data from an API to RAM in Flutter?

I'm writing a really simple app in Flutter, but I have a problem with state management.
Here's the video of what I have. Link: https://streamable.com/ir3ztr
The video shows my application, but when I switch a screen using Bottom Navigation Bar, the data loads again and again from the API. I don't want that. I want the once downloaded data to be saved in RAM and not being downloaded again from the API. Is that possible? I heard about Provider, but I don't know how to use that in my case.
Is there anyone who can help me?
My code:
World
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_placeholder_textlines/flutter_placeholder_textlines.dart';
import '../../models/world.dart';
import '../../data/world_service.dart';
class WorldScreenAndroid extends StatefulWidget {
#override
_WorldScreenAndroidState createState() => _WorldScreenAndroidState();
}
class _WorldScreenAndroidState extends State<WorldScreenAndroid> {
Future<World> futureWorld;
#override
void initState() {
super.initState();
futureWorld = fetchWorld();
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8.0),
child: FutureBuilder<World> (
future: futureWorld,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView(
children: [
Card(
child: ListTile(
leading: Icon(Icons.public),
title: Text('coronavirus_cases').tr(context: context),
subtitle: Text(NumberFormat('#,###,###', 'en_US').format(snapshot.data.cases).toString())
),
),
Card(
child: ListTile(
leading: Icon(Icons.public),
title: Text('deaths').tr(context: context),
subtitle: Text(NumberFormat('#,###,###', 'en_US').format(snapshot.data.deaths).toString())
),
),
Card(
child: ListTile(
leading: Icon(Icons.public),
title: Text('recovered').tr(context: context),
subtitle: Text(NumberFormat('#,###,###', 'en_US').format(snapshot.data.recovered).toString())
),
)
],
);
}
return ListView(
children: [
Card(
child: ListTile(
leading: Icon(Icons.public),
title: Text('coronavirus_cases').tr(context: context),
subtitle: PlaceholderLines(
count: 1,
animate: true,
color: Colors.grey,
minWidth: 0.10,
maxWidth: 0.50,
),
),
),
Card(
child: ListTile(
leading: Icon(Icons.public),
title: Text('deaths').tr(context: context),
subtitle: PlaceholderLines(
count: 1,
animate: true,
color: Colors.grey,
minWidth: 0.10,
maxWidth: 0.50,
),
),
),
Card(
child: ListTile(
leading: Icon(Icons.public),
title: Text('recovered').tr(context: context),
subtitle: PlaceholderLines(
count: 1,
animate: true,
color: Colors.grey,
minWidth: 0.10,
maxWidth: 0.50,
),
),
)
],
);
},
)
);
}
}
Countries
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import '../../models/country.dart';
import '../../data/countries_service.dart';
class CountriesScreenAndroid extends StatefulWidget {
#override
_CountriesScreenAndroidState createState() => _CountriesScreenAndroidState();
}
class _CountriesScreenAndroidState extends State<CountriesScreenAndroid> {
Future<List<Country>> futureCountries;
#override
void initState() {
super.initState();
futureCountries = fetchCountries();
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8.0),
child: FutureBuilder(
future: futureCountries,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: [
TextField(),
SizedBox(height: 10.0),
Expanded(
child: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
final List<String> _countriesAllArgs = [
NumberFormat('#,###,###', 'en_US').format(snapshot.data[index].cases),
NumberFormat('#,###,###', 'en_US').format(snapshot.data[index].todayCases),
NumberFormat('#,###,###', 'en_US').format(snapshot.data[index].active),
NumberFormat('#,###,###', 'en_US').format(snapshot.data[index].deaths),
NumberFormat('#,###,###', 'en_US').format(snapshot.data[index].todayDeaths),
NumberFormat('#,###,###', 'en_US').format(snapshot.data[index].recovered),
NumberFormat('#,###,###', 'en_US').format(snapshot.data[index].critical)
];
return Card(
child: Padding(
padding: EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
snapshot.data[index].country,
style: TextStyle(
fontSize: 18.0,
color: Colors.grey[600],
),
),
SizedBox(height: 6.0),
Text(
'countries_all',
style: TextStyle(
fontSize: 14.0,
color: Colors.grey[800],
),
).tr(args: _countriesAllArgs),
],
),
)
);
}
),
)
],
);
}
return Center(
child: CircularProgressIndicator(),
);
},
)
);
}
}
Make sure to keep the loaded data in a parent widget, not in the widget your switching.
Have you considered using the BLOC framework?
In that case, you could nicely sepearte Business Logic from UI code and keep the loaded data in the bloc.
In detail have a blocProvider on top, wrapping your app.
https://bloclibrary.dev/#/flutterbloccoreconcepts?id=blocprovider
Alternatively, but be carefull with the handling though, you can just create an object, anywhere outside of any widget, and access it from anywhere.
class Data {
List<String> stringsLoadedFromWeb;
}
Data data = Data();
// from anywhere else, where you import the above file
data.stringsLoadedFromWeb = ...

Scoped Model initialized when Key Board is popped up for TextField

I have two tabs with a Default Tab bar. I have used Scoped-model for passing data between two tabs. When I insert data in one tab and press text Field again so that keyboard pops up but whole model gets reinitialized.
I have tried AutomaticKeepAliveClientMixin but no result. I have found out that every time I press the Text Field, keyBoard pops up and the Scoped model gets initialized. I have checked that by printing string in Scoped-Model constructor.
Here is my TabView
import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
import 'package:basicflutter/tabs/FirstScreen.dart';
import 'package:basicflutter/tabs/SecondScreen.dart';
import 'package:basicflutter/models/product.dart';
import 'package:basicflutter/scopedModel/addproduct.dart';
import 'package:scoped_model/scoped_model.dart';
class MyTabs extends StatelessWidget {
static String tag = 'tab-page';
#override
Widget build(BuildContext context) {
return ScopedModel<ProductsModel>(
model: ProductsModel(),
child: MaterialApp(
home: DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car)),
Tab(icon: Icon(Icons.directions_transit)),
],
),
title: Text('Flutter Tabs Example'),
),
body: TabBarView(
children: [
FirstScreen(),
SecondScreen(),
],
),
),
),
),
);
}
}
Here is my FirstScreen which takes Name and Image as input and then inserts them in an ArrayList
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:basicflutter/tabs/SecondScreen.dart';
import 'package:basicflutter/models/product.dart';
import 'package:basicflutter/scopedModel/addproduct.dart';
import 'package:scoped_model/scoped_model.dart';
class FirstScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen>
with AutomaticKeepAliveClientMixin<FirstScreen> {
File _image;
final NameController = TextEditingController();
#override
void initState() {
super.initState();
print("InitState called") ;
}
#override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
final ProductName = TextFormField(
controller: NameController,
autofocus: false,
obscureText: false,
decoration: InputDecoration(
hintText: 'Prodcut Name',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
),
);
final AddProduct = Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Column(
children: <Widget>[
ScopedModelDescendant<ProductsModel>(
rebuildOnChange: false,
builder: (context, child, model) => Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
),
onPressed: (){
ModelProduct newProduct = ModelProduct(NameController.text,_image);
model.AddNewProduct(newProduct) ;
setState(() {
NameController.clear();
_image = null ;
});
},
padding: EdgeInsets.all(12),
color: Colors.lightBlueAccent,
child: Text('Add product', style: TextStyle(color: Colors.white)),
),
)
)
],
),
);
Future getImage() async {
var taken_image = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
_image = taken_image;
});
}
return Scaffold(
body: GestureDetector(
onTap: (){FocusScope.of(context).requestFocus(new FocusNode());},
child: Container(
padding: EdgeInsets.all(20),
child: new ListView(
children: [
SizedBox(height: 20.0),
Text(
'Add your product here',
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
),
SizedBox(height: 20.0),
ProductName,
SizedBox(height: 20.0),
_image == null
? Center(
child: new Container(
padding: EdgeInsets.all(20),
child: Text('No image selected.')))
: Image.file(_image),
SizedBox(
height: 20.0,
),
AddProduct,
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: getImage,
child: Icon(Icons.camera),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Here is my SecondScreen which show the data in ListView
import 'package:flutter/material.dart';
import 'package:basicflutter/tabs/FirstScreen.dart';
import 'package:basicflutter/models/product.dart';
import 'package:basicflutter/scopedModel/addproduct.dart';
import 'package:scoped_model/scoped_model.dart';
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new ScopedModelDescendant<ProductsModel>(
builder: (context, child, model) => Container(
child: new ListView.builder(
itemCount: model.count,
itemBuilder: (BuildContext context, int index) {
return new Card(
child: Column(
children: <Widget>[
Text(model.GetAllProducts[index].name),
Container(
width: 250.0,
height: 250.0,
alignment: Alignment.center,
child:
model.GetAllProducts[index].image == null
? Center(
child: new Container(
padding: EdgeInsets.all(20),
child: Text('No image selected.')))
: Image.file(model.GetAllProducts[index].image ),
),
],
),
);
},
),
)));
}
}
Here is my PODO which
import 'dart:io' ;
class ModelProduct {
String name ;
File image ;
ModelProduct(this.name,this.image);
}
And lastly here is my Scoped-Model
import 'package:flutter/material.dart';
import 'package:basicflutter/tabs/FirstScreen.dart';
import 'package:basicflutter/tabs/SecondScreen.dart';
import 'package:basicflutter/models/product.dart';
import 'package:basicflutter/scopedModel/addproduct.dart';
import 'package:scoped_model/scoped_model.dart';
import 'dart:io';
class ProductsModel extends Model {
final List<ModelProduct> productList = List<ModelProduct>();
ProductsModel(){
print("ProductsModel init") ;
}
void AddNewProduct(ModelProduct p) {
productList.add(p);
notifyListeners() ;
print(this.count);
}
int get count => productList.length ;
List<ModelProduct> get GetAllProducts => productList ;
}
Widget build(BuildContext context) {
return ScopedModel<ProductsModel>(
model: ProductsModel(),
You've likely solved this by now but... this is your problem. You're initializing your model in the build method. It needs to be initialized outside of that.
For instance :
ProductsModel productsModel = ProductsModel();
Widget build(BuildContext context) {
return ScopedModel<ProductsModel>(
model: productsModel,