I am using MvvmCross 4.2.3 and I have a query about when it is safe to call ShowViewModel
I am trying to call ShowViewModel to navigate in the Start method of ViewModelA to navigate to ViewModelB, however I get the following exception
Java.Lang.IllegalStateException: Recursive entry to executePendingTransactions
I assumed I was doing it too early in the lifecycle of ViewA\ViewModelA. So I put the call into the OnResume of ViewA. I assumed at this point any transactions required to show ViewA would have been commited.
But I still get the same error.
Has anyone come accross this problem. If so how do I solve it.
Thanks in Advance
I am not being specific here , just trying to solve what you asked .
I think there could be two scenario .
scenerio first .
you want to navigate on user interaction lets say tapping on a button .
Inside view you can put this code in OnCreate or ViewModelSet method overrides .
var set = this.CreateBindingSet<MyView, MyViewModel>();
set.Bind(MyButton).For(zz => zz.BindClick()).To(vm => vm.MyCommand);
Inside your viewmodel, you would need this .
private ICommand myCommand;
public virtual ICommand MyCommand
{
get
{
return myCommand = myCommand ?? new MvxCommand(() => {
Task.Factory.StartNew(() => {
ShowViewModel<MyNextViewModel>();
});
});
}
}
Scenario 2 ,
You have some Async task going on based on completion of that you want to navigate .
Inside your viewmodel constructor you call a method like below .
Public MyViewModel(){
LoadActivation()
}
private async void LoadActivation()
{
await Task.Run(async () =>
{
try {
response = await _Myservice.LoadMyData();
if(response != null ) {
ShowViewModel<MyNextViewModel>():
}
}
catch (Exception ex) {
Debug.WriteLine(ex);
}
});
}
Related
try {
//CheckPermission
if (await Permission.storage
.request()
.isGranted) {
final result = await SaveImageToKoi(post.fimgUrl!.url!);
print(result);
if (result != null)
BotToast.showText(text: "Success");
else
BotToast.showText(text: "Error");
}
} catch (e) {}
},
dynamic SaveImageToKoi (koi_url) async {
print(koi_url);
var response = await Dio().get(
koi_url,
options: Options(responseType: ResponseType.bytes));
final result = await ImageGallerySaver.saveImage(
Uint8List.fromList(response.data),
quality: 100);
}
I am trying to use the below library:
https://pub.dev/packages/image_gallery_saver
And when I am saving picture, it will cause the UI thread to get stuck. The stuck time depends on the size of the image
An error will be reported when trying to create a new thread by using compute to save. I don't know how to solve it, I just started learning Flutter and hope to receive
I guess the plug-in was written by Kotlin, and there was a problem when the interface communication was created by Dart
Thanks.
This is an error when I use compute
In platform_channal.dart
Thrown by
BinaryMessenger get binaryMessenger => _binaryMessenger ??
ServicesBinding.instance!.defaultBinaryMessenger;
exception = {_CastError} Null check operator used on a null value
Errors when using Compute
From your question it is not clear where your try/catch block code executes, but from what you describe I assume it is in a UI method such as build. If that is the case then indeed this code will block the UI, because while your statement final result = await SaveImageToKoi will yield to allow other methods to run, it won't proceed past this statement until the save is done.
You should perform the save function elsewhere (not blocking UI), and upon completion of the save trigger the UI to rebuild (typically by calling setState() in a Stateful Widget. For example, if you had a button in your UI that you want to trigger the save, then in your build function you might have this widget:
RaisedButton(
onPressed: () => {
SaveImageToKoi(post.fimgUrl!.url!).then((result) {
print(result);
setState(() {}); // this will trigger the UI redraw
});
},
child: new Text('Click me'),
),
The SaveImageToKoi statement here will not block, and upon completion of the save the code in the then argument is executed, with the result of the save operation. It is there that you call setState to trigger the UI refresh (if necessary - for example if you wanted to show the result in some way)
I initiate network request in GetXController, after network call back, I should judge this controller/this page is dealloc or not. If this page is not dealloced, update Page. If this page is dealloced, I do noting. As I know, I can write below codes in flutter origin:
if (mounted) {
// update page
setState({
});
}
So my question is how to write in GetX controller?
There is a property called isClosed in GetxController
so you can use it instead of mounted
class MyController extends GetxController{
...
fun() {
// some code
if(this.isClosed) return;
// code that you want not execute it
}
...
}
mounted can only be called inside Stateful widgets, so you can't use it inside a Controller.
If you are using named routes I think you can get the current name of the page and do something.
if(Get.routing.current == "/home"){
doSomething();
}
the mounted bool is specific only for the StateFulWidget, I could think of passing it as a Stream<bool>to the controller, then use it, But, this is not the ideal solution and it can be very problematic.
On the other hand, you can check on mounted before calling the method, like this:
// ....
onPressed: () {
if (mounted) {
controller.sendRequest();
}
},
// ....
Thank you very much in advance for your help! Please let me know if the question is not clear i would be happy to add more details if needed.
I have a Finite State Machine that handles some audio recognition. This FSM is wrapped by a "manager" whose job is to handle the state transitions (processState, nextState). The FSM manager exposes a stream which is updated every time nextState is called
FSM/Manager layout
class FSM_Manager{
StreamController<RecognitionState> _stateStream =
StreamController<RecognitionState>();
Sink<RecognitionState> get _inState => _stateStream.sink;
Stream<RecognitionState> get outState => _stateStream.stream;
RecognitionState _currentState, _previousState;
void setState(RecognitionState state) {
_previousState = _currentState;
_currentState = state;
_addCurrentStateToStream();
}
void _addCurrentStateToStream() {
_inState.add(_currentState);
}
Future nextState() async {
_currentState.nextState(this);
}
Future processState(itemToRecognize) async {
await _currentState.processState(itemToRecognize);
}
}
abstract class BaseState {
RecognitionStateID get stateID; //enum with each state's ID
Future processState(itemToRecognize);
Future nextState(FSM_Manager manager);
}
class FSM_State1 implements BaseState{
bool isSuccess = false;
void processState(itemToRecognize) async {
isSuccess = await performRecognition(itemToRecognize);
}
void nextState (FSM_Manager fsmManager) {
if(isSuccess){
// go to next State
fsmManager.setState(NEXT_STATE);
} else {
//go to some other state
fsmManager.setState(SOME_OTHER_STATE);
}
}
}
class FSM_State2 implements BaseState{
bool isSuccess = false;
void processState(itemToRecognize) async {
isSuccess = await performRecognition(itemToRecognize);
}
void nextState () {
if(isSuccess){
// go to next State
} else {
// go to another State
}
}
}
I have a screen (Stateful Widget) which uses a StreamBuidler to listen to the "outState" stream in order to rebuild the screen with the information in the new State.
Stateful Widget
class _RecognitionScreenState extends State<RecognitionScreen> {
ItemToRecognize item;
var currStateiD;
FSM_Manager _fsmManager;
RecognitionScreenState(
ItemToRecognize item, FSM_Manager fsmManager) {
this.item = item;
this._fsmManager = fsmManager;
}
#override
Widget build(BuildContext context) {
String outString = '';
return StreamBuilder<RecognitionState>(
stream: _stateContext.outState,
builder: (BuildContext context,
AsyncSnapshot<RecognitionState> snapshot) {
if (snapshot.hasData) {
outString = snapshot.data.stateID.toString();
return Text(outString);
} else {
return Text('');
}
});
}
}
Now, I do not know where/how to call processState and nextState from, I cant do it from the build method so i Tried to use initState() and didUpdateWidget in the StatefulWidget so that the states are processed in the beginning and after every build respectively. This approach didnt work, the nextState method was never called. I feel like im missing something trivial but i just dont see where to call those functions from outside of the Stateful Widget in order to trigger a rebuild only after the state has changed
Thanks again for your help
EDIT
I apologize for the confusion,
I added the BaseState definition (just an abstract class with some method so that i dont forget to implement them)
the nextState method takes an FSM_Manager as a parameter and calls setState on success or failure and sets the next state
the States "implement" the BaseState class, they dont "extend" it
It's difficult for me to tell from your code because I don't know what your BaseState does but inside your builder - presumably from some event or callback - you would do:
inState.add(<--Some RecognitionState-->);
This would trigger the StreamBuilder to rebuild.
If everything else in your code is put together properly.
I am creating a list of businesses through RestAPI in initstate. I need to use sharedpreference value as one of its parameter but when i try to load data, the sharepreference value is null initial but that value can be used in other widgets easily.
The problem is how to read sharepreference value and use at the same time in initstate.?
I have tried many options like taking my api out of initstate and defining with async function and call it in initstate.
**#override
void initState() {
super.initState();
loadData();
getBizList();
}
getBizList() async {
await api
.bizListAPI(widget.subCatid, savedCityID, supSubFinal, areaFinal)
.then((response) {
setState(() {
bizListOBJ = response;
});
});
}
loadData() async {
SharedPreferences savedPref = await SharedPreferences.getInstance();
setState(() {
savedCity = (savedPref.getString('savedCity') ?? "Mumbai");
savedCityID = (savedPref.getString('savedCityID') ?? "1");
});
}**
in above code i am able to get or read data and show city name from sharedpreference(savedCity) which is in appbar but i want to use savedcityID data to pass in my api in initstate.
I also tried to use following plugin
[https://medium.com/#greg.perry/a-flutter-class-for-app-preferences-a256166ecc63.][1]
With this I was able to do what i wanted but each time i close my app and open again ...
i got following error
"_prefsInstance != null,
"Maybe call Prefs.getKeysF() instead. SharedPreferences not ready yet!");"
after that when i go back and open page again, the app and biz list works perfect till again i close my app.
[1]: https://medium.com/#greg.perry/a-flutter-class-for-app-preferences-a256166ecc63
sorry for my any noob explanation or question. Actually this is my 1st question in stack and I am beginner in flutter.
Can you try this?
void initState() {
super.initState();
loadData().then((_) {
getBizList();
});
}
You need to use set state inside init state because
loadData();
getBizList();
are async function so you need to refresh page to get value.
Try this
#override
void initState() {
// TODO: implement initState
super.initState();
setState(() {
loadData();
getBizList();
});
}
I'm working in the PCL with the last stable version of Xamarin Forms. For the moment, the targeted platform is Android.
First, I get the results from my HTTP POST request which is working perfectly fine.
Then, when I try to update the UI, the scrollview in which the results are displayed is lagging when I scroll down.
I think it might be a threading problem : the update of the UI may not be executed in the right thread.
I tried to use Device.BeginInvokeOnMainThread(() => { //Update the UI }); but it is not working.
Thanks.
Here is some of my code to help us :
Main Method:
private async void Search() {
ResponseService results = await libSearch.getResults(this.searchEntry.Text);
if (results.error != true) {
List<Choice> list = (List<Choice>)results.obj;
if(list.Count != 0) {
foreach(Choice choice in list) {
Device.BeginInvokeOnMainThread(() => {
addNewChoice(choice);
});
}
}
}
AddNewChoice Method:
private void addNewChoiceOnUI(Choice choice) {
ChoiceTemplate Choice = new ChoiceTemplate(choice.name, choice.img, choice.address);
this.Choices.Children.Add(Choice);
}
The Web Service Call Method seems to work. It looks like this :
public async Task<ResponseService> getResults(string zipcode) {
(...)
JObject results = await JsonWebRequest.getDataFromService(queryString).ConfigureAwait(false);
(...)
As you can see, I'm using an await on the web service call method and on the main method only. I'm also using ConfigureAwait(false); on the web service call method. I already tried numerous solutions. I would be so grateful if we could find a solution to avoid the lag.