android: AsyncTask onPostExecute keep working even if start new activity on doInBackground - android-asynctask

i am building an application for clients to get questions from server and answer it, if the server doesn't have questions i want to go to new screen and print message that try again in few minutes, getting questions is in AsyncTask , if the server doesn't have questions , it will sends in the header of the responds, a header isFindAQuestion with the value false, here is the code on client to ensure if false , i print on LogCat and i see the message = false, but my problems that even if i start new activity with the intent, this activity keep working and show me exception and it is null pointer exception because on the onPostExceute will take a parmeter null and try to process it, i put finish() in the end of false statement but doesn't finish the activity
if (response.getFirstHeader("isFindAQuestion").getValue()
.toString().equals("false")) {
Log.d("message", "false");
Bundle basket = new Bundle();
basket.putString("Message", "sorry no enought questions");
Intent goToAnswerQuestion = new Intent(AnswerQuestion.this,
FinishTime.class);
goToAnswerQuestion.putExtras(basket);
startActivity(goToAnswerQuestion);
finish();
}
Editis it because AsyncTask is working on thread so if the activity is finished, that thread will keep working? and if so how can i stop that thread?

doInBackground is not executed in the UI thread, but in a separeted thread:
invoked on the background thread immediately after onPreExecute()
finishes executing. This step is used to perform background
computation that can take a long time.
If you want to stop your background operation and perform some activities on the UI thread the better thing is to call cancel() and then perform all the stuff you want in the onCancelled callback wich is executed on the UI thread.
From the AsyncTask documentation:
A task can be cancelled at any time by invoking cancel(boolean).
Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns.
To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.)
protected void onCancelled (Result result)
Runs on the UI thread after cancel(boolean) is invoked and doInBackground(Object[]) has finished.
The default implementation simply invokes onCancelled() and ignores the result. If you write your own implementation, do not call super.onCancelled(result).

Related

quarkus/mutiny how to trigger a side job without waiting it

quarkus reactive uses mutiny to handle task asynchronously.
But, the flow is always wait every job to finish, then returns the result.
Sometime, I just want to trigger a job and let it run in the background without waiting it to be done.
Any suggestion or example?
Uni<Integer> mainJob() {
// fake logic
return Uni.createFrom().item(1);
}
Uni<Void> sideJob(int n) {
// fake logic
logger.log("result = " + n);
}
#Path("test")
Uni<Integer> testExample() {
return mainJob().onItem().call(n -> sideJob(n));
}
The upper code only returns after sideJob() is done. But, I just want to return the result immediately once mainJob is done, with sideJob triggered and run in background.
Any suggestion on it?
ManagedExecutor may be a way to do but it seems not natural in this case. The side job may/not be long running.
According to the Uni interface documentation:
To trigger the computation, a UniSubscriber must subscribe to the Uni. It will be notified of the outcome once there is an item or failure event fired by the observed Uni. A subscriber receives (asynchronously) a UniSubscription and can cancel the demand at any time.
Thus, the only way to start the execution of a Uni is by subscribing to it, even by calling uni.await().indefinitely() you are, in fact, subscribing to the Uni as we can see in the documentation of the indefinitely() method:
Subscribes to the Uni and waits (blocking the caller thread) indefinitely until a item event is fired or a failure event is fired by the upstream uni.
Invoking the call() method is nothing more than chaining a new function that will be included in the stream that will be executed when the Uni is subscribed. This way, when the testExample() method returns the result of the call(), it is not executing and waiting for the Uni to finish, it is actually returning the result immediately.
However, whoever is going to receive the final result must wait for the Uni stream to finish, so the client waiting for the HTTP response will be waiting for the sideJob() to finish in order to receive the original value, but once again, your testExample() method is not waiting for anything, it returns the Uni immediately without waiting for it to be executed.

Finish workflow when activity goes wrong

I have a workflow that executes a couple of activities. When the activity finish, it returns an Outcome either Done or Cancel, from outside and before running the next activity, I need to check if the previous activity was ok or not, in case not, I need to cancel the workflow. I have this
public class CreateEmployee : IWorkflow
{
public void Build(IWorkflowBuilder builder)
{
builder
.WithDisplayName(this.GetType().Name)
.Then<GetDataById>(x => x.WithDisplayName(x.ActivityType.Name))
.When(OutcomeNames.Cancel).Finish()
.Then<InsertEmployee>(x => x.WithDisplayName(x.ActivityType.Name))
.When(OutcomeNames.Cancel).Finish()
.Then<InsertMapping>(x => x.WithDisplayName(x.ActivityType.Name))
.When(OutcomeNames.Cancel).Finish();
}
}
For example, after executing activity GetDataById, if the return is "Cancel", I call Finish(), is this going to stop just the activity and continue the workflow or the workflow will stop completely? I'm not able to test it because I'm using DI and I need to prepare the whole unit test, because I didn't find anything directly related to cancel the whole workflow
I'm not sure if I have fully understood your question, but in the documentation about finish activity it's stated that:
when this activity is used within a workflow, the workflow instance
will enter the Finished state. When used in a child composite
activity, that activity will stop execution and yield back control to
its container. However, it will not stop workflow execution itself.

What does an await Task.Yield do when in a Xamarin Forms OnAppearing?

My OnAppearing code looks like this. I don't understand what this is added for:
`await Task.Yield()`
Can someone explain what this does?
protected override async void OnAppearing()
{
base.OnAppearing();
Utils.SetState(Settings.mode.Text(), vm.Mode);
vm.CfsLabel = Settings.cfs.Text();
SetMode(Settings.mode.Text());
Subscribe();
ContentPageStack.IsVisible = true;
if (!openedOnce)
{
// can someone explain what the following line
// is doing here in the code. What's the Task
// that it refers to and what does Yield do?
await Task.Yield();
await scroll.ScrollToAsync(0, 0, false);
openedOnce = true;
}
if (App.devIsUser)
Analytics.TrackEvent(VersionTracking.CurrentVersion + " - On Appearing - home page");
}
In this particular case, await Task.Yield does nothing useful. It is probably a misguided attempt to process Win32 messages like WM_PAINT. I.e., a "poor man's DoEvents".
await Task.Yield is used to force asynchrony. It's a way of forcing await to behave asynchronously, returning to the caller. It also immediately queues the remainder of the method to run.
The reason this doesn't work as a "poor man's DoEvents" is because the Win32 message queue is prioritized. So this is what the await Task.Yield actually does in this particular instance:
Queues the continuation of the async method to the current context (the UI SynchronizationContext), which places the continuation into the Win32 message queue.
Returns from the async method. Since this is an event handler, this returns to the Win32 message processing loop.
The Win32 message process loop pulls the next message from its queue. Since the queue is prioritized, it will always skip over regular Win32 messages and take the continuation message.
The loop processes the message, which runs the continuation of the async method, so the event handler resumes executing right where it left off.
I think the Microsoft docs give you a clear picture of what it does, When you read about Task.Yield its says:
Creates an awaitable task that asynchronously yields back to the current context when awaited.
Returns
YieldAwaitable
A context that, when awaited, will asynchronously transition back into the current context at the time of the await. If the current SynchronizationContext is non-null, it is treated as the current context. Otherwise, the task scheduler that is associated with the currently executing task is treated as the current context.
What this basically means is when you use await Task.Yield in an async method it will force the method to complete asynchronously. And if there is a Synchronization Context available it will execute the remainder of the method's execution back to that context.
Note: The synchronization context that is present on a UI thread in most UI environments will often prioritize work posted to the context higher than input and rendering work. For this reason, do not rely on await Task.Yield(); to keep a UI responsive.

Spring #Async cancel and start?

I have a spring MVC app where a user can kick off a Report generation via button click. This process could take few minutes ~ 10-20 mins.
I use springs #Async annotation around the service call so that report generation happens asynchronously. While I pop a message to user indicating job is currently running.
Now What I want to do is, if another user (Admin) can kick off Report generation via the button which should cancel/stop currently running #Async task and restart the new task.
To do this, I call the
.. ..
future = getCurrentTask(id); // returns the current task for given report id
if (!future.isDone())
future.cancel(true);
service.generateReport(id);
How can make it so that "service.generateReport" waits while the future cancel task kills all the running threads?
According to the documentation, after i call future.cancel(true), isDone will return true as well as isCancelled will return true. So there is no way of knowing the job is actually cancelled.
I can only start new report generation when old one is cancelled or completed so that it would not dirty data.
From documentation about cancel() method,
Subsequent calls to isCancelled() will always return true if this method returned true
Try this.
future = getCurrentTask(id); // returns the current task for given report id
if (!future.isDone()){
boolean terminatedImmediately=future.cancel(true);
if(terminatedImmediately)
service.generateReport(id);
else
//Inform user existing job couldn't be stopped.And to try again later
}
Assuming the code above runs in thread A, and your recently cancelled report is running in thread B, then you need thread A to stop before service.generateReport(id) and wait until thread B is completes / cancelled.
One approach to achieve this is to use Semaphore. Assuming there can be only 1 report running concurrently, first create a semaphore object acccessible by all threads (normally on the report runner service class)
Semaphore semaphore = new Semaphore(1);
At any point on your code where you need to run the report, call the acquire() method. This method will block until a permit is available. Similarly when the report execution is finished / cancelled, make sure release() is called. Release method will put the permit back and wakes up other waiting thread.
semaphore.acquire();
// run report..
semaphore.release();

Windows Forms: thread safe access to GUI?

in the last hours I've struggled with delegates and accessing Windows Forms controls (C++) where I've used this tutorial (the first thread safe method): http://msdn.microsoft.com/en-us/library/ms171728.aspx#Y190
Changing TextBoxes and Labels works perfectly but when I want to show or hide the whole GUI from another thread this fails.
I use the following methode (which is part of the GUI class):
System::Void UI::showUI(boolean value) {
if (this->InvokeRequired) {
SetTextDelegate^ d = gcnew SetTextDelegate(this, &UI::showUI);
this->Invoke(d, gcnew array<Object^> { value });
} else {
if (value == true)
this->Show();
else
this->Hide();
}
}
In the first call the if-clause is true so Invoke is called. But usually the showUI method should be called a second time automatically where the if-clause returns false, but this is not happening. So the GUI is neither shown nor hiden.
Is it necessary to show/hide the GUI with a delegate or can I do it from every possible thread? If a delegate is necessary, why is showUI not executed a second time?
Thanks,
Martin
edit: okay the name SetTextDelegate is not appropriate but this is not the point...
This is a pretty standard case of deadlock, not uncommon with Control::Invoke(). It can only proceed if the UI thread is not busy. Use Debug + Windows + Threads and double-click the Main thread. Look at the call stack to see what it is doing. The typical case is that it is blocking, waiting for the thread to finish the job. That will never happen since the thread can't complete until the Invoke() call returns.
Don't block the UI thread.
Consider using BackgroundWorker, its RunworkerCompleted event is nice to do stuff after the thread completes, removing the need to block.

Resources