We're building some integration tests with FlutterDriver, and would like to verify the state of the application.
It seems flutter drive runs in a totally different instance than the app, so they can not communicate indirectly by stashing data in some shared static class.
Are there any common strategies to passing data to the test layer, from the app?
Some ideas I thought of:
We could write json values to disk, but can the test side actually read it?
Have a hidden text widget, that shows a special ui view that renders state so we can then read it from the test layer
fwiw, we have solved this currently by json-encoding some of our app state into an invisible Text widget that we place on screen.
The test can then lookup that text, decode the json, and read the current app state.
Pretty hacky but it works!
test('Check flutter driver health', () async {
Health health = await driver.checkHealth();
print(health.status);
});
Related
So i have a situation where i make an request from the server for one widget.
The widget is at the home page, lets take the worst case where the data is huge and the request take time.
Should i change the widget to stateless and make a provider which i will initialize before i run the app with all the initial data?
Should i contain all the data of the widgets at home page and deliver theme as props, i miss understood the concept of managing the state here, I'm coming from vue and i try to write my first app and I'm struggling how to structure my data through the routes.
I would like if some one explain or give a good source that show how to initialize data from third party
before the home page reload.
Which approach is better getting all the app data before the app reload or request data every time from db with cash
You might have seen this approach in other apps as well which is to show a splash screen until the data has been loaded and ready to be shown. This approach is mostly used by apps which got large data to load at the start. You could achieve this in your initState like the following.
#override
void initState() {
loadData();
splashTimer = Timer(Duration(seconds: 4), () {
_goToHome();
});
super.initState();
}
State management in flutter is a topic with hot debate, there is no best approach, but using one for sure is better than nothing. However there are exceptions to this, sometime adding a state management to a simple part of the app is not recommended. Regarding your case, it can be done without a full state management solution, by using a FutureBuilder for example. Or it can be also done with Provider, BloC, Redux...
As a naïve general rule, if the state is to be passed down the widget tree more than 1 or 2 levels, you should probably start looking for a state management solution depending on the use case. As I already have said, there is no one best state management solution.
Also, it is ok to use more than one as long as you know what you are doing but in general as a best practice it is not recommended to use more than one.
Regarding the second part of the question, it totally depends on the nature of the data and it's size. If the data is big and it is a small possibility that the user will be using all of it, it is better to load it on demand, also loading all the data upfront will increase the cost on the backend side.
However getting the data upfront, makes the experience more seamless to the user (Not waiting while using the app, but he will have to wait a little extra when the app is first loading).
So as you see it is a balance. Also it is good for the server and the app to do some type of caching since it helps reduce the work on the server side and decrease the bandwidth usage on the phone.
An example for caching images you can use Cached Network Image Link, example from flutter cookbook Link.
Within our flutter app we are doing some background processing. For that, we need to create new flutter isolate in our native code so we can run code when activity is not open, based on this guide: https://medium.com/#chetan882777/initiating-calls-to-dart-from-the-native-side-in-the-background-with-flutter-plugin-7d46aed32c47
Now, to not duplicate code and to not cause any concurrency issues, we would also like to have access to that background processing isolate from main flutter UI isolate. That way we can begin processing from both native code and from flutter UI code.
However, there does not seem to be a way for native to pass this Isolate / ControlPort to the main UI side so it can communicate with it. Is there a way I can achieve this (communicate to the same Isolate from both native and UI side)?
From what I see, only way to do this would require native to be the broker between the two sides (send the task to native and then native sends it back to the other side), but it seems like a lot of hassle for one flutter talking to another flutter.
Solution to this is the IsolateNameServer.
One side can call IsolateNameServer.registerPortWithName() and other side can then send messages to that port via IsolateNameServer.lookupPortByName()
my app needs latest data but, possibly, the main app has old data.
so i want to request to the main app to update its data.
is it possible?
if it is not I would like to know any alternative way.
(should the widget requests latest data to the server??)
thanks
===
UPDATE
I found many tutorials and all of them use http request from getTimeline method for getting newest data (not from the main app). it is not what i want.
Someone said easest way for sharing data between main app and widgets is using UserDefaults. But the data can be old if the main app does not update userdefaults values or update values using old data. (beside server data is always latest data)
So what i want to know is the way 'widget makes main app updates its data and updates userdefault and call reloadTimelines. so widget can use latest data.
There's no way for a Widget to tell its parent App to refresh its data.
You can either:
fetch data directly in the Widget - see: How to refresh Widget data?
enable background notifications in the App (see How to run code when your app is terminated) and, when received one, force the Widget to refresh its timeline using:
WidgetCenter.shared.reloadAllTimelines()
In reality it's probably better to just fetch data directly in the Widget. This way you can fetch only the necessary data - Widget views usually display a lot less information than App views.
Yes, you can like this;
When you create a TimelineProvider for widget update, you have to implement this func,
func getTimeline(in context: Context, completion: #escaping (Timeline<Entry>) -> ())
This function waits to create your widget update timeline. You can sen a request, after the response, you can create a timeline and return func's completion.
You can configure an App Group and store the database in that shared group directory. That way, if you update data in the main app or in the widget, those new data are available for both, it's not necessary to call the other one to load the same data again. Just be aware that you should still use
WidgetCenter.shared.reloadAllTimelines()
after you updated the data in your main app to refresh the widget immediately. Just have some handling for when the last request was performed, so you don't create an unnecessary request in your widget, and instead fetch them from the database.
If you move your request-performing code into a modul, you can also use it in the widget, as you do in your app. Finally you'll just have another call of the same updating code you are used to from your main app.
Since I don't have any of your code to update and present here, I'll just link some helpful sources for the way to the described destination.
Apple Documentation: Configuring App-Groups
Sharing data within App-Groups
I'm starting learning Flutter as I want to port my iOS app to Flutter to also run on Android.
I use Firebase real time database for the back-end and I saw that the firebase_database package should suit my needs, allowing me to use the db I already have.
I'm also learning to use the BLoC pattern but all the bloc tutorials I found are for Firestore and all the Event/State/Bloc/Repository/Streaming is still quite confusing to me right now.
What should be the right implementation of the bloc pattern?
To a basic level I do understand it and I like it very much, but thinking of a way to implement it for my needs is resulting a bit overwhelming.
Following this diagram the 6 connections data flow should be:
(UI -> BLoC) An event will be sent to the bloc.
(BLoC -> Repository) The Bloc maps the event to a Repository method.
(Repository -> Database) The Repository methods are database Create/Update/Delete methods.
(Database -> Repository) The Repository database Read method gets database Data.
(Repository -> BLoC) The return from Repository database Read method takes the Data into BLoC.
(BLoC -> UI) The BlocProvider uses the Data to rebuild the UI.
Now what I'm not sure I figured out is the data going back to the UI.
At step 2 if I map the event to a method that returns the data as a Stream<List<Object>> then via a BlocProvider at step 6 the UI(stateless widget) gets rebuilt accordingly.
Now, as I see it, that would be a lot of unnecessary repeating data downloads if for any change, the whole node gets downloaded, also Google's bills you on downloads.
In the Firebase iOS SDK you can attach observers to a node, so you just get a snapshot with the .childAdded/.childRomovedetc etc, and use it to modify your UI.
To avoid useless downloads and keep my account safe, I'd rather make a query on a node with the keepSynced bool set to true ( https://pub.dev/documentation/firebase_database/latest/firebase_database/Query-class.html ). This should (as the iOS SDK) return at first firing, a snapshot with the whole node and than snapshots with just new/updated/delete when something changes right?
To implement this way instead, should I use a List<Object> that I update manually when getting the snapshot and a stateful widget? This is actually how my iOS app works at the moment.
Thank you very much for the help and sorry for the long question, making the switch from Swift is taking it's time.
Firebase listeners only transfer the minimal amount of data that actually changed at the node being listened to. It does NOT transfer the entire node and all of its children each time anything changes. So, it's not as expensive as you're imagining it to be.
I need to load a small settings file before showing the first screen.
I'm curently using the PathProvider plugin, but all the functions in it are async.
Is there any way to find the application documents directory synchroniously and then use dart:io sync functions on it? Instead of showing a placeholder for infinite decimal of a second.
EDIT: considering the first 2 answers, probably my explaination was really bad. The answers suggested me to still use async code. Problem is, I need the directory before runApp(), and I dont want my void main() to be async, because this ruins any splash animation for sure.
And the PathProvider API is async, as far as I can see, only because it utilizes MethodChannel, which is async, but functions behind it in PathProvider are pretty much synchronious.
What I'm asking is - is there a way, on Android or IOS, to know ApplicationDocumentsDirectory in sync code? Maybe without using platform-specific code at all?
You can use FutureBuilder for the same purpose without having to worry about execution.
It will allow you to do your process in the background and allows you to show a splash screen UI until your specified process is complete and data is ready to use.
Note: Any plugin or code which needs access to the device's native method channel will be async by default, since access of the method channel itself is supposed to be async.