sqflite is taking too long time to fetch data from database - flutter

This is the code which i used to fetch data from database
Future<List<ShadeColorDatabase>?> getShadeColorData() async {
Database? db = await instance.database;
try {
var data = await db!.query(table4);
List<ShadeColorDatabase>? shadeColorDataList = data.isNotEmpty
? data.map((e) => ShadeColorDatabase.fromMap(e)).toList()
: [];
return shadeColorDataList;
} catch (e) {
rethrow;
}
}
and i called this function in my screen like this
filterDatabaseData() async {
final databaseData = await DatabaseHelper.instance.getShadeColorData();
for (int i = 0; i < databaseData!.length; i++) {
print("${databaseData[i].colorName}");
setState(() {
allColorCodeList.add(databaseData[i].colorName);
});
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
filterDatabaseData();
}
but i get this warning saying:- warning-database-has-been-locked-for-00010-000000-make-sure-you-always-use-th. this says when i run my app for the first time. Meaning if someone is running the app for the first time this warning is showing and related data is not showing is there any way i can fix this problem need some help. Thanks

Related

Flutter: _TypeError

I'm trying to get datas from api and add them a list. But at this moment, I see datas i got but I can't get it out of the function. What should i do?
function
List<dynamic> xxx = [];
#override
void initState() {
super.initState();
Future<List<dynamic>> fetchCompanies(List<dynamic> datas) async {
var response = await Dio().get(CompaniesPath().url);
if (response.statusCode == HttpStatus.ok) {
Map<String, dynamic> company = jsonDecode(response.data);
for (int i = 0; i < company['Data'].length; i++) {
datas.add(company['Data'][i]);
}
//print(datas); //=> I see datas here
} else {
throw Exception();
}
return datas;
}
print(fetchCompanies(xxx));
}
When I run print(fetchCompanies(xxx)); I got "Instance of 'Future<List<dynamic>>'". How can i get data inside fetchCompanies to my xxx list?
You're trying to print future instance of List that's why you got
Instance of Future<List>
You have to wait until function finish executing.
Catch here is you can't call wait in initState() so you have to use .then method
try this:
fetchCompanies(xxx)
.then((result) {
print("result: $result");
});
It should already work fine like it is. But you probably want to call a setState to refresh the page. Try this:
#override
void initState() {
super.initState();
Future<List<dynamic>> fetchCompanies(List<dynamic> datas) async {
var response = await Dio().get(CompaniesPath().url);
if (response.statusCode == HttpStatus.ok) {
Map<String, dynamic> company = jsonDecode(response.data);
for (int i = 0; i < company['Data'].length; i++) {
datas.add(company['Data'][i]);
}
//print(datas); //=> I see datas here
setState(() {}); // added this
} else {
throw Exception();
}
return datas;
}
print(fetchCompanies(xxx));
}

Pagination with streams in flutter

I have implemented a pagination scheme in my flutter app but im not sure if its performance friendly and if it may result to trouble on production in future so i would like to get advice on it.
here is my implementation
First, i get data using a stream provider in my parent widget.
class BuyerSellerPostsPage extends StatefulWidget {
#override
_BuyerSellerPostsPageState createState() => _BuyerSellerPostsPageState();
}
class _BuyerSellerPostsPageState extends State<BuyerSellerPostsPage> {
...some code here...
bool isAtBottom = false;
int postToDisplay=10;
#override
void initState() {
super.initState();
// Setup the listener.
_scrollController.addListener(() {
if (_scrollController.position.atEdge) {
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
setState(() {
isAtBottom=true;
postToDisplay+=10;
print('now true');
});
}else{
setState(() {
print('now false');
isAtBottom=false;
});
}
}
});
}
#override
void dispose(){
_scrollController.dispose();
super.dispose();
}
...some code here..
#override
Widget build(BuildContext context) {
Position coordinates=Provider.of<Position>(context);
...some code here...
body: SingleChildScrollView(
controller: _scrollController,
child: StreamProvider<List<SellerPost>>.value(
value: SellerDatabaseService(
currentLocation: new GeoPoint(coordinates.latitude, coordinates.longitude,)
,filters: _setFilters,
selectedCategory: _selectedCategory,
selectedTag: _selectedTag,
postsToDisplay: postToDisplay
).inRangeSellerPosts ,
...some code here...
);
}else{
return Container(
);
}
},
),
),
//post list
BSellerPostList(),
...some code here...
}
}
The initial posts to display are 10.
In my initstate i have used a listener to my scroll controller so that when the user scrolls to the bottom more items(+10) are loaded on screen.
In my stream provider i pass the postsToDisplay int to my stream in the backend below
Stream <List<SellerPost>> get inRangeSellerPosts {
try {
return sellerPostCollection
.where("expireTime" , isGreaterThan: DateTime.now())
.orderBy('expireTime',descending: true)
.snapshots()
.map(yieldSellerPosts);
} catch (e) {
print(e.toString());
return null;
}
}
List<SellerPost> yieldSellerPosts(QuerySnapshot snapshot) {
List<String> l = [];
print(snapshot.documents.length);
try {
return snapshot.documents.map((doc) {
return SellerPost(
...some code here...
);
}).take(postsToDisplay)
.toList();
} catch (e) {
print(e.toString());
return null;
}
}
I now get the snapshots and use the take method on the list to get only the required number(postsToDisplay).
This method works fine in my debug mode. Im not sure how it will behave in production or with large data sets. Could someone scrutinise it, i would appreciate alot.
I personally used a modified version of this answer posted in a previous similar question.
Both my implementation and that other guys implementation have the pros and cons.
His method leads to listening to document changes for documents you may never need to use considering you may need only 10 paginated items. My method on the other hand does not work along with the stream. It uses a future to query for document snapshots to update the list as you proceed.
Here is the sample code
bool _isRequesting = false;
bool _isFinish = false;
final _scrollController = ScrollController();
List<DocumentSnapshot> _posts = [];
#override
void initState() {
_scrollController.addListener(() {
if (_scrollController.position.atEdge) {
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
setState(() {
requestNextPage();
});
}
}
});
requestNextPage();
super.initState();
}
void requestNextPage() async {
try{
if (!_isRequesting && !_isFinish) {
QuerySnapshot querySnapshot;
_isRequesting = true;
if (_posts.isEmpty) {
//check if _posts list is empty so that we may render the first list of 10 items.
querySnapshot = await Firestore.instance
.collection('sellerPost')
.limit(10)
.getDocuments();
} else {
//if _posts list is not empty it means we have already rendered the first 10 items so we start querying from where we left off to avoid repetition.
querySnapshot = await Firestore.instance
.collection('sellerPost')
.startAfterDocument(_posts[_posts.length - 1])
.limit(10)
.getDocuments();
}
if (querySnapshot != null) {
int oldSize = _posts.length;
_posts.addAll(querySnapshot.documents);
int newSize = _posts.length;
if (oldSize == newSize) {
_isFinish = true;
}
_isRequesting = false;
}else{
_isFinish = false;
_isRequesting = false;
}
}catch(e){
print(e.toString());
}
}
So in this above code i used the scroll controller to detect when the user scrolls to the bottom of the page with the paginated items e.g 10 posts. This event triggers my function requestNextPage(); Note that on inititState we also call the requestNextPage(); to render the initial 10 posts.
So now, the each time a scroll to bottom is detected, 10 extra posts are added to
_posts

Pedometer package in flutter doesn't work with some devices

I used the pedometer package version ^1.2.0 in my flutter app and I noticed that it doesn't work with some devices like Samsung A30 and others, the version I used doesn't need any permissions and it worked on my device OPPO F7 (Used Android 10) so what is the problem?
Here's the code
StreamSubscription<int> _subscription;
Box<int> stepsBox = Hive.box('steps');
int todaySteps;
#override
void initState() {
super.initState();
startListening();
}
#override
void dispose() {
stopListening();
super.dispose();
}
void startListening() {
_pedometer = Pedometer();
_subscription = _pedometer.pedometerStream.listen(
getTodaySteps,
onError: _onError,
onDone: _onDone,
cancelOnError: true,
);
}
void _onDone() => print("Finished pedometer tracking");
void _onError(error) => print("Flutter Pedometer Error: $error");
Future<int> getTodaySteps(int value) async {
print(value);
int savedStepsCountKey = 999999;
int savedStepsCount = stepsBox.get(savedStepsCountKey, defaultValue: 0);
int todayDayNo = Jiffy(DateTime.now()).dayOfYear;
if (value < savedStepsCount) {
// Upon device reboot, pedometer resets. When this happens, the saved counter must be reset as well.
savedStepsCount = 0;
// persist this value using a package of your choice here
stepsBox.put(savedStepsCountKey, savedStepsCount);
}
// load the last day saved using a package of your choice here
int lastDaySavedKey = 888888;
int lastDaySaved = stepsBox.get(lastDaySavedKey, defaultValue: 0);
// When the day changes, reset the daily steps count
// and Update the last day saved as the day changes.
if (lastDaySaved < todayDayNo) {
lastDaySaved = todayDayNo;
savedStepsCount = value;
stepsBox
..put(lastDaySavedKey, lastDaySaved)
..put(savedStepsCountKey, savedStepsCount);
}
setState(() {
todaySteps = value - savedStepsCount;
});
stepsBox.put(todayDayNo, todaySteps);
return todaySteps; // this is your daily steps value.
}
void stopListening() {
_subscription.cancel();
}
check for permission.
await Permission.activityRecognition.request().isGranted
this will check for permission and request permission if the permission is not allowed
if (await Permission.activityRecognition.request().isGranted) {
_pedestrianStatusStream = Pedometer.pedestrianStatusStream;
_pedestrianStatusStream
.listen(onPedestrianStatusChanged)
.onError(onPedestrianStatusError);
_stepCountStream = Pedometer.stepCountStream;
_stepCountStream.listen(onStepCount).onError(onStepCountError);
}else{
}
if (!mounted) return;
I think that in this case it would be better to ask the question directly in the lib repository, open an issue with your problem.
https://github.com/cph-cachet/flutter-plugins/issues

it couldn't update the list

that data disapear.but i want whenever i hit on delete button it remove immediately not restart the application.how i solve this problem any one sugget me?
Here init state code
#override
void initState() {
super.initState();
setState(() {
getPostsData();
});
controller.addListener(() {
double value = controller.offset / 119;
setState(() {
topContainer = value;
closeTopContainer = controller.offset > 50;
});
});
_currentScreen();
}
Here is my delete method code
void _delete(BuildContext context, int id) async {
int result = await dbHelper.deletedata(id);
if (result != 0) {
_showSnackBar(context, 'Data Deleted Successfully');
updateListView();
}
}
Here is my update list code
void updateListView() {
final Future<Database> dbFuture = dbHelper.initializeDatabase();
dbFuture.then((database) {});
}
I think adding setState to updateListView() should do it.
void updateListView() {
final Future<Database> dbFuture = dbHelper.initializeDatabase();
dbFuture.then((database) {});
setState((){});
}
Edit: Looks like you only get the data of your database once in initState. Maybe you need to reexecute the function that gets the data everytime you delete something.
Call getPostsData in updateListView.
void updateListView() {
final Future<Database> dbFuture = dbHelper.initializeDatabase();
dbFuture.then((database) {});
getPostsData();
}
Not the base way but you can add a button for refresh the list after deletion and call setState with getPostsData which will refresh items. For better solution you can use provider and notify listeners each time when you make deletion.

Flutter flutter_in_app_purchases subscription FlutterInAppPurchses.instance.getSubscriptions() is not retrieving any items for IAPItem

I'm trying to implement a renewable subscription in flutter using the flutter_in_app_purchases plugin. When I click on the screen that this is declared in, it goes through the initState() function and then gets to the initPlatformState() and goes through that successfully, but when it gets to the getProducts() function, it's returning an empty item list for the List items = FlutterInappPurchase.instance.getSubscriptions([productID]); call. I've added the monthly subscription in both the App Store Connect and Google Play Store and completed the tax forms. Any help would be appreciated.
List<IAPItem> _items = [];
static const String productID = 'monthly_subscription';
#override
void initState() {
super.initState();
print("IN INIT STATE");
initPlatformState();
}
Future<void> initPlatformState() async {
print("In init platform state");
// prepare
final bool available = await InAppPurchaseConnection.instance.isAvailable();
print(available);
var close = await FlutterInappPurchase.instance.endConnection;
var result = await FlutterInappPurchase.instance.initConnection;
print('result: $result');
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) {
print('In not mounded');
return;
}
// refresh items for android
/*try {
String msg = await FlutterInappPurchase.instance.consumeAllItems;
print('consumeAllItems: $msg');
} catch(e){
print(e.toString());
}*/
await _getProduct();
}
Future<Null> _getProduct() async {
print("In get products");
try {
List<IAPItem> items = await FlutterInappPurchase.instance.getSubscriptions([productID]);
print("Items is: $items");
for (var item in items) {
print('${item.toString()}');
this._items.add(item);
}
setState(() {
this._items = items;
});
} catch(e) {
print(e.toString());
}
}
Here you have a working example from app in production. Disclaimer: I'm not using it anymore but the last time I did it worked fine:
class _InAppState extends State<InApp> {
StreamSubscription _purchaseUpdatedSubscription;
StreamSubscription _purchaseErrorSubscription;
StreamSubscription _conectionSubscription;
final List<String> _productLists = Platform.isAndroid
? [
'subs_premium', 'subs_user'
]
: ['subs_premium', 'subs_boss', 'subscripcion_user'];
String _platformVersion = 'Unknown';
List<IAPItem> _items = [];
List<IAPItem> _subscripions = [];
List<PurchasedItem> _purchases = [];
#override
void initState() {
super.initState();
initPlatformState();
}
#override
void dispose() {
super.dispose();
if (_conectionSubscription != null) {
_conectionSubscription.cancel();
_conectionSubscription = null;
}
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
platformVersion = await FlutterInappPurchase.instance.platformVersion;
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// prepare
var result = await FlutterInappPurchase.instance.initConnection;
print('result: $result');
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
// refresh items for android
try {
String msg = await FlutterInappPurchase.instance.consumeAllItems;
print('consumeAllItems: $msg');
} catch (err) {
print('consumeAllItems error: $err');
}
_conectionSubscription = FlutterInappPurchase.connectionUpdated.listen((connected) {
print('connected: $connected');
});
_purchaseUpdatedSubscription = FlutterInappPurchase.purchaseUpdated.listen((productItem) {
print('purchase-updated: $productItem');
});
_purchaseErrorSubscription = FlutterInappPurchase.purchaseError.listen((purchaseError) {
print('purchase-error: $purchaseError');
});
final List<String> _SKUS = widget.premium ? ['subs_boss']
: ['subs_user'] ;
_getSubscriptions(_SKUS);
}
void _requestPurchase(IAPItem item) {
FlutterInappPurchase.instance.requestPurchase(item.productId);
}
Future _getProduct() async {
print('TEST 1 HERE ${_productLists.length}, ${_productLists.first.toString()}');
List<IAPItem> items = await FlutterInappPurchase.instance.getProducts(_productLists);
print('TEST 2 HERE ${items.length}');
for (var item in items) {
print('${item.toString()}');
this._items.add(item);
}
setState(() {
this._items = items;
this._purchases = [];
});
}
Future _getPurchases() async {
List<PurchasedItem> items =
await FlutterInappPurchase.instance.getAvailablePurchases();
for (var item in items) {
print('${item.toString()}');
this._purchases.add(item);
}
setState(() {
this._items = [];
this._purchases = items;
});
}
Future _getSubscriptions(_SKUS) async {
List<IAPItem> items =
await FlutterInappPurchase.instance.getSubscriptions(_SKUS);
for (var item in items) {
print('${item.toString()}');
this._subscripions.add(item);
}
setState(() {
this._items = [];
this._subscripions = items;
});
}
Future _getPurchaseHistory() async {
List<PurchasedItem> items = await FlutterInappPurchase.instance.getPurchaseHistory();
for (var item in items) {
print('${item.toString()}');
this._purchases.add(item);
}
setState(() {
this._items = [];
this._purchases = items;
});
}