Async Co-Routine in Kotlin - asynchronous

I never use async in Kotlin. I'm not sure whether I understand is correctly.
I need that the method buttonChange(result) wait the thread is finish, to obtain the result.
fun sendConnection(view: View) {
var result = ""
if (!connected) {
async {
val runnable = Runnable()
{
result = me.connect("connection")
}
val threadSend = Thread(runnable)
threadSend.start()
}
buttonChange(result)
}
catch (e: Exception) {}
} else {
try {
async {
val runnable = Runnable()
{
result = me.connect("disconnection")
}
val threadSend = Thread(runnable)
threadSend.start()
}
buttonChange(result)
} catch (e: Exception) {
}
}

The pattern you should use is async/await.
It'll return a Deferred from async { } which you can use to call await() on. Since buttonChange seems to need the UI context, you might need to launch the coroutines as well.
launch(UI) {
try {
val result = async { me.connect("disconnection") }
buttonChange(result.await())
} catch (_: Exception) { }
}
You should not create a thread manually.

Related

How to timeout Firebase Task in Unity

This issue is driving me nuts :)
Assuming that I have a simple async Task:
async Task AddPoints()
{
await usersDbReference.Child(currentUser).Child("Score").SetValueAsync(newScore).ContinueWith(task =>
{
if(task.IsFaulted || task.IsCanceled)
{
Debug.Log("Couldn't complete task");
}
});
}
What is the simplest way to add the timeout, for example 10 seconds, after which I will show pop up to the user to check his/her internet connection?
Thank you in advance!
EDIT:
I tried below code but it makes the unity crash:
int timeout = 1000;
var task = SomeOperationAsync();
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
} else {
// timeout logic
}
I'm using Unity (api compatibility level .Net Standard 2.0, I assume that crash is because of this?)
What I want to achieve:
In case the user doesn't have the internet connection I want to either timeout the task and cancel it or just cancel it after finding out there is no internet connection.
EDIT:
I modified the code. So I have a simple task with cancel token:
async Task CheckTask(CancellationToken csToken)
{
string firstChild = "user";
string secondChild = "testuser";
await FirebaseDatabase.DefaultInstance.RootReference.Child(firstChild).Child(secondChild).GetValueAsync().ContinueWith(task =>
{
if(task.IsFaulted || task.IsCanceled)
{
Debug.Log("Task was canceled");
}
});
}
Then I'm calling it from async void:
public async void FirebaseLogin()
{
bool taskDidntComplete = false;
Debug.Log("Started task");
CancellationTokenSource cs = new CancellationTokenSource();
try
{
var loginTask = CheckTask(cs.Token);
if(loginTask.IsCanceled)
{
Debug.Log("Canceled");
}
if (await Task.WhenAny(loginTask, Task.Delay(10000)) == loginTask)
{
taskDidntComplete = false;
}
else
{
taskDidntComplete = true;
Debug.Log(taskDidntComplete);
cs.Cancel();
throw new TimeoutException();
}
}
catch (Exception e)
{
Debug.Log(e);
}
finally
{
}
}
And while everything works fine and it shows the exception, it doesn't cancel the task. Would be very grateful if someone could tell me what I'm doing wrong.
EDIT2: Works perfect in Unity, doesnt work on Android... Anyone can help? I'm desperate now haha
public async void FirebaseLogin()
{
Debug.Log("Started task");
CancellationTokenSource cs = new CancellationTokenSource();
try
{
var loginTask = CheckTask(cs.Token);
if(loginTask.IsCanceled)
{
Debug.Log("Canceled");
netTestCheck.text = "Canceled";
}
if (await Task.WhenAny(loginTask, Task.Delay(10000)) == loginTask)
{
//netTestCheck.text = "Completed";
}
else
{
netTestCheck.text = "Failed";
cs.Cancel(false);
//throw new TimeoutException();
}
cs.Token.ThrowIfCancellationRequested();
}
catch (Exception e)
{
netTestCheck.text = "Failed2";
Debug.Log(e);
}
finally
{
}
It would help if you could share the exception or stack trace of the crash (integrating Crashlytics could help if you're already in the Firebase ecosystem).
Although I can't spy anything that looks particularly bad in your sample code, if the actual Task fails for whatever reason (say you turn on airplane mode to test, and a suitable exception is raised before your timeout) an exception will get raised there that you aren't handling.
I'd suggest putting a try/catch around your block like:
try {
int timeout = 1000;
var task = SomeOperationAsync();
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
} else {
// timeout logic
}
} catch (Exception e) {
Debug.LogError($"{e} occurred!");
}
It's likely to be a DatabaseException, but I'd check first before you get more specific than Exception.
Let me know if that helps!
--Patrick
It unfortunately won't work on Android because app will keep on calling to Firebase. Fortunately found the way around :D

Calling Async task in button click in xamarin.forms

I have xamarin.forms app contains a listview which will load values from Rest API.Which is working fine.I have button just above the listview.When I click on the button, the listview API call will be placed again and the listview should update. But stuck at this update part.I am not using MVVM pattern.The listview listing portion is an async Task.I am calling the async task again when the button click, but App gets crash. Is it due to calling the async task again from button click? Any help is appreciated.
Here is My code.
namespace app
{
public partial class List : ContentPage
{
PendingWeekRange pendingWeekRange = new PendingWeekRange();
public TimeSheetList()
{
InitializeComponent();
Task.Run(async () =>
{
await LoadScreenItems();
});
}
async Task LoadScreenItems()
{
await Task.Run(async () => {
try
{
// Doing some stuff
await loadTimeSheetList();
}
catch (Exception)
{
}
});
}
async Task loadTimeSheetList()
{
await Task.Run(() => { + string postdataForPendingList = "{\"date\":\"" + "1" + "\"}";
APICall callForAPICallResult = new APICall("/API/ListMobile/ListForApproval", postdataForList, loadingIndicator);
try
{
List<ListData> resultObjForPendingTimeSheetList = callForAPICallResult<List<ListData>>();
if (resultObjForPendingTimeSheetList != null)
{
TimesheetList.ItemsSource = resultObjForPendingTimeSheetList;
screenStackLayout.VerticalOptions = LayoutOptions.FillAndExpand;
TimesheetList.IsVisible = true;
}
else
{
}
}
catch (Exception)
{
}
});
}
async void Button_Tapped(object sender, EventArgs e)
{
try
{
// Calling my listview again. After calling app gets crash
Task.Run(async () => await loadTimeSheetList());
}
catch (Exception ex) { }
}
}
}
A few things before getting to the problem. You've got async/await all wrong, go though Async Programming
Task.Run runs the passed action on a different thread, if you make changes to UI elements on this thread, your app will definitely(take my word) crash.
If you want to make async call at page launch, make use of OnAppearing method (if you only want to call once, maintain a flag)
Do not change the ItemsSource of a list view frequently, just clear and add items to it.
namespace app
{
public partial class List : ContentPage
{
PendingWeekRange pendingWeekRange = new PendingWeekRange();
private ObservableCollection<ListData> TimesheetObservableCollection = new ObservableCollection<ListData>();
public TimeSheetList()
{
InitializeComponent();
TimesheetList.ItemsSource = TimesheetObservableCollection;
}
protected override async OnAppearing()
{
// flag for first launch?
await LoadScreenItems();
}
async Task LoadScreenItems()
{
try
{
// Doing some stuff
TimesheetObservableCollection.Clear();
TimesheetObservableCollection.AddRange(await GetTimeSheetList());
}
catch (Exception)
{
//handle exception
}
}
async Task<List<ListData>> GetTimeSheetList()
{
string postdataForPendingList = "{\"date\":\"" + "1" + "\"}";
APICall callForAPICallResult = new APICall("/API/ListMobile/ListForApproval", postdataForList, loadingIndicator);
try
{
return callForAPICallResult<List<ListData>>();
}
catch (Exception)
{
// handle exception
}
}
async void Button_Tapped(object sender, EventArgs e)
{
try
{
// Calling my listview again. After calling app gets crash
TimesheetObservableCollection.Clear();
TimesheetObservableCollection.AddRange(await GetTimeSheetList());
}
catch (Exception ex) { }
}
}
}
#Androdevil,
Update your loadTimeSheetList with this,
async Task loadTimeSheetList()
{
try
{
// I am calling my API for Listview here.
List<TimeSheetListData> resultObjForPendingTimeSheetList = await callForPendingTimeSheetList.APICallResult<List<TimeSheetListData>>();
if (resultObjForPendingTimeSheetList != null)
{
TimesheetList.ItemsSource = resultObjForPendingTimeSheetList;
screenStackLayout.VerticalOptions = LayoutOptions.FillAndExpand;
TimesheetList.IsVisible = true;
}
else
{
}
}
catch (Exception)
{
}
}

Issues appending text to a TextArea (JavaFX 8)

I am receiving strings from my server that I want to append into a Textarea on the client side (Think chat window). Problem is, when I receive the string, the client freezes.
insertUserNameButton.setOnAction((event) -> {
userName=userNameField.getText();
try {
connect();
} catch (IOException e) {
e.printStackTrace();
}
});
public Client() {
userInput.setOnAction((event) -> {
out.println(userInput.getText());
userInput.setText("");
});
}
private void connect() throws IOException {
String serverAddress = hostName;
Socket socket = new Socket(serverAddress, portNumber);
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
while (true) {
String line = in.readLine();
if (line.startsWith("SUBMITNAME")) {
out.println(userName);
} else if (line.startsWith("MESSAGE")) {
Platform.runLater(()->serverOutput.appendText(line.substring(8) + "\n"));
} else if (line.startsWith("QUESTION")) {
Platform.runLater(()->serverOutput.appendText(line.substring(8) + "\n"));
} else if (line.startsWith("CORRECTANSWER")) {
Platform.runLater(()->serverOutput.appendText(line.substring(14) + "\n"));
}
}
}
public static void main(String[] args) {
launch(args);
}
I have done some research and it seems that using Platform.runLater on each append should fix the problem. It doesn't for me.
Anyone has an idea of what it can be caused by? Thank you!
You are calling connect() on the FX Application Thread. Since it blocks indefinitely via the
while(true) {
String line = in.readLine();
// ...
}
construct, you block the FX Application Thread and prevent it from doing any of its usual work (rendering the UI, responding to user events, etc).
You need to run this on a background thread. It's best to use a Executor to manage the threads:
private final Executor exec = Executors.newCachedThreadPool(runnable -> {
Thread t = new Thread(runnable);
t.setDaemon(true);
return t ;
});
and then do
insertUserNameButton.setOnAction((event) -> {
userName=userNameField.getText();
exec.execute(() -> {
try {
connect();
} catch (IOException e) {
e.printStackTrace();
}
});
});

How to handle different exceptions in Task?

I'm kinda new in JavaFX, and I didn't find any answer to this.
I'm trying to use Task to do some background calculation in a database. The problem is the following : How can I handle exceptions (SQLException, IOException etc ...) in my task.SetOnFailed(e -> ....) function ?
I tried this : e.getSource().getException().getMessage() but I don't think it is the right way to do this.
You can just check the type of the exception:
Task<Something> myTask = new Task<Something>() {
#Override
public Something call() throws Exception {
// code...
return something ;
}
};
myTask.setOnFailed(e -> {
Throwable exc = myTask.getException();
if (exc instanceof SQLException) {
// ...
} else if (exc instanceof IOException) {
// ...
} else {
// ...
}
});

Make multiple asynchronous calls and do something when they are completed

I have run into this problem across multiple programming languages and I was just wondering what the best way to handle it is.
I have three method calls that fire off asynchronously. Each one has a callback. I want to do something only when all three callbacks have completed.
What is the best way to code this? I usually end up with all these public bool flags and as you add more calls the code gets more convoluted.
Coming from C#, I would probably use WaitHandle.WaitAll. You can create an array of ManualResetEvent objects (one for each task to be completed), and pass that array to WaitAll. The threaded tasks will get one ManualResetEvent object each, and call the Set method when they are ready. WaitAll will block the calling thread until all tasks are done. I'll give a C# code example:
private void SpawnWorkers()
{
ManualResetEvent[] resetEvents = new[] {
new ManualResetEvent(false),
new ManualResetEvent(false)
};
// spawn the workers from a separate thread, so that
// the WaitAll call does not block the main thread
ThreadPool.QueueUserWorkItem((state) =>
{
ThreadPool.QueueUserWorkItem(Worker1, resetEvents[0]);
ThreadPool.QueueUserWorkItem(Worker2, resetEvents[1]);
WaitHandle.WaitAll(resetEvents);
this.BeginInvoke(new Action(AllTasksAreDone));
});
}
private void AllTasksAreDone()
{
// OK, all are done, act accordingly
}
private void Worker1(object state)
{
// do work, and then signal the waiting thread
((ManualResetEvent) state).Set();
}
private void Worker2(object state)
{
// do work, and then signal the waiting thread
((ManualResetEvent)state).Set();
}
Note that the AllTasksAreDone method will execute on the thread pool thread that was used to spawn the workers, and not on the main thread... I assume that many other languages have similar constructs.
If you really only want to wait for all to finish:
Create volatile counter
Synchronize access to counter
Increase counter on start
Decrease on callback fired
Wait for counter to reach 0
Use a semaphore.
Futures are very easy to use. Futures look like normal functions, except that they execute asynch.
The classes:
public struct FutureResult<T>
{
public T Value;
public Exception Error;
}
public class Future<T>
{
public delegate R FutureDelegate<R>();
public Future(FutureDelegate<T> del)
{
_del = del;
_result = del.BeginInvoke(null, null);
}
private FutureDelegate<T> _del;
private IAsyncResult _result;
private T _persistedValue;
private bool _hasValue = false;
private T Value
{
get
{
if (!_hasValue)
{
if (!_result.IsCompleted)
_result.AsyncWaitHandle.WaitOne();
_persistedValue = _del.EndInvoke(_result);
_hasValue = true;
}
return _persistedValue;
}
}
public static implicit operator T(Future<T> f)
{
return f.Value;
}
}
Here I use futures to simulate a deadlock:
void SimulateDeadlock()
{
Future> deadlockFuture1 = new Future>(() =>
{
try
{
new SystemData(ConfigurationManager.ConnectionStrings["DbConnectionString"].ConnectionString)
.SimulateDeadlock1(new DateTime(2000, 1, 1, 0, 0, 2));
return new FutureResult { Value = true };
}
catch (Exception ex)
{
return new FutureResult { Value = false, Error = ex };
}
});
Future> deadlockFuture2 = new Future>(() =>
{
try
{
new SystemData(ConfigurationManager.ConnectionStrings["DbConnectionString"].ConnectionString)
.SimulateDeadlock2(new DateTime(2000, 1, 1, 0, 0, 2));
return new FutureResult { Value = true };
}
catch (Exception ex)
{
return new FutureResult { Value = false, Error = ex };
}
});
FutureResult result1 = deadlockFuture1;
FutureResult result2 = deadlockFuture2;
if (result1.Error != null)
{
if (result1.Error is SqlException && ((SqlException)result1.Error).Number == 1205)
Console.WriteLine("Deadlock!");
else
Console.WriteLine(result1.Error.ToString());
}
else if (result2.Error != null)
{
if (result2.Error is SqlException && ((SqlException)result2.Error).Number == 1205)
Console.WriteLine("Deadlock!");
else
Console.WriteLine(result2.Error.ToString());
}
}
For those using JavaScript, consider using the pattern discussed at this Stackoverflow question:
javascript: execute a bunch of asynchronous method with one callback

Resources