How to refresh Widget data?
You can't use the ObservedObject
like you'd normally use in your App.
In Widgets you use a TimelineProvider
which creates an Entry
for your view.
- Add another property to your
TimelineEntry
, let's call itclubName
:
struct SimpleEntry: TimelineEntry {
let date: Date
let clubName: String
}
- Update the
NetworkManager
and return results in thecompletion
:
class NetworkManager {
func fetchData(completion: @escaping ([Post]) -> Void) {
...
URLSession(configuration: .default).dataTask(with: url) { data, _, error in
...
let result = try JSONDecoder().decode(Results.self, from: data)
completion(result.data)
...
}
.resume()
}
}
- Use the
NetworkManager
in theTimelineProvider
and create timelines entries when thefetchData
completes:
struct Provider: TimelineProvider {
var networkManager = NetworkManager()
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), clubName: "Club name")
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) {
let entry = SimpleEntry(date: Date(), clubName: "Club name")
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
networkManager.fetchData { posts in
let entries = [
SimpleEntry(date: Date(), clubName: posts[0].home_name)
]
let timeline = Timeline(entries: entries, policy: .never)
completion(timeline)
}
}
}
- Use
entry.clubName
in the view body:
struct WidgetNeuEntryView: View {
var entry: Provider.Entry
var body: some View {
VStack {
Text(entry.date, style: .time)
Text("Club: \(entry.clubName)")
}
}
}
Note that in the above example the reload policy is set to never
to only load the data once.
You can easily change it to atEnd
or after(date:)
if you want to reload the timeline automatically.
If you need to reload the timeline manually at any point you can just call:
WidgetCenter.shared.reloadAllTimelines()
This will work in both App and Widget.
Here is a GitHub repository with different Widget examples including the Network Widget.
How to refresh Widget when Main App is used?
WidgetCenter.shared.reloadAllTimelines()
is independent from the UI framework you use. You can use it from SwiftUI or UIKit.
If you're worried about making too many requests you could call that method only once your app goes to the background.
How do I make my widget update more frequently or update when an action happens within the app
You can always update your widget from your app with the code block below. Please be aware you need to import WidgetKit
to your class for calling this function.
WidgetCenter.shared.reloadAllTimelines()
flutter refresh widget's content but it remains old data
use todoFutureBuilder.clear()
function
Flutter - How to refresh a Widget on button Click?
I fixed this, I was passing constructor parameters of Portfolio
to _PortfolioState
, this won't update the values the next time. Instead of passing these values to _PortfolioState
, I used widget.coin
and widget.days
to extract the data from the Portfolio
class.
Thanks to this StackOverflow link: Passing Data to a Stateful Widget in Flutter
How can i refresh data immediately after updating it in flutter?
i found the solution i just had to change it in the ui seperatly by changing "quantityData" to an int and increment it in the setstate, this way it keeps updating in the screen
class ProductsInInventoryWidget extends StatefulWidget
{
ProductsInInventory? model;
BuildContext? context;
ProductsInInventoryWidget({this.model,this.context});
@override
_ProductsInInventoryWidgetState createState() => _ProductsInInventoryWidgetState();
}
class _ProductsInInventoryWidgetState extends State<ProductsInInventoryWidget> {
int quantityData =1;
Future addQuantity(int mydata) async
{
String Product_BarCode = widget.model!.productBarcode.toString();
String Inventory_id = widget.model!.inventoryId.toString();
var response = await http.put(
Uri.parse("http://192.168.1.188:8000/api/user/IncrementProduct/$Product_BarCode/$Inventory_id/$mydata",),
body:jsonEncode(<String, String>{
'quantity': mydata.toString(),
}),
);
var body = jsonDecode(response.body);
}
Future<http.Response> DeleteProductFromInventoryProducts(int join_id) async
{
final http.Response response = await http.delete(
Uri.parse("http://192.168.1.188:8000/api/user/deleteProductsFromInventory/$join_id",)
);
return response;
}
@override
void initState() {
// TODO: implement initState
quantityData = widget.model!.quantity; // 2# assign the incoming data here
super.initState();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top:0.0),
child : Card(
margin: EdgeInsets.fromLTRB(5, 6, 5, 0),
child: Padding(
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
child: Column(
children: [
ListTile(
leading: CircleAvatar(
radius:40,
backgroundColor: Colors.black38,
child: Text(quantityData.toString()
,style: TextStyle(
color: Colors.white
),),
),
title: Text(widget.model!.productName), //(widget.model!.ProductName!,),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("code bar : " + widget.model!.productBarcode ),
Text("updated : " + DateFormat('yyyy-MM-dd kk:mm').format(widget.model!.updatedAt)),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
IconButton(
icon: Icon(Icons.add,color: Colors.blue,),
onPressed: () async{
// await addQuantity(quantityData);
setState(() {
quantityData+=1;
print(quantityData.toString());
addQuantity(quantityData);
});
}
),
IconButton(
icon: Icon(Icons.remove,color: Colors.blue,),
onPressed: () {
// Perform some action
},
),
FlatButton(
child: const Text('Delete',style: TextStyle(color: Colors.blue),),
onPressed: () {
// Perform some action
setState(() {
// DeleteProductFromInventoryProducts(widget.model!.id.toString());
});
},
),
],
),
],
),
),
],
),
),
)
);
}
}```
iOS 14 Widget auto-refresh every day
Actually, it seems to be I overlooked it, the widget actually refreshes, it was me, who didn't refresh the data itself. (I'm using UserDefaults to share data between my app and the widget, and even though the widget refreshed properly, as the data in UserDefaults was not updated, the same was shown over and over again.)
How to refresh a widget with stream builder in flutter
Every time your widget rebuilds, you get a new stream. This is a mistake. You should obtain the stream only once (for example, in initState)
@override
void initState() {
_stream = quotesdata.fetchdata().asStream();
}
and use that stream variable with StreamBuilder
StreamBuilder(
stream: _stream,
Later, when you want to update the stream, you can do
setState(() {
_stream = quotesdata.fetchdata().asStream();
})
to change the stream and force a refresh.
Please go over your code and change all such usages
StreamBuilder(
stream: quotesdata.fetchdata().asStream(),
to this kind of usage.
StreamBuilder(
stream: _stream,
Otherwise you may get a high backend bill someday. Right now every screen refresh does a new query to the backend.
Related Topics
How to Check If a String Contains Another String in Swift
How to Print the Type or Class of a Variable in Swift
Swift - Resolving a Math Operation in a String
How to Make a Weak Protocol Reference in 'Pure' Swift (Without @Objc)
Saving Picked Image to Coredata
Getting Keyboard Size from Userinfo in Swift
Swift 4 Decodable - Dictionary With Enum as Key
Knowing Where Retain Cycles Are and Removing Them
How to Fix Cocoapod .Modulemap File Not Found
How to Make a Swiftui List Scroll Automatically
How to Store 1.66 in Nsdecimalnumber
Nsurlsession Concurrent Requests With Alamofire