MonoDroid ProgressDialog - android

All I want to do is make sure the user knows that a webservice is processing so they don't repeatedly mash buttons while it tries to work.
EditText partnumber = (EditText)FindViewById(Resource.Id.itemNumber);
partnumber.FocusChange += (object sender, View.FocusChangeEventArgs e) =>
{
if (!e.HasFocus)
{
var pd = ProgressDialog.Show(this, "Processing", "Please Wait...", false);
var res = new InventoryApp();
res.partValidateCompleted += delegate { pd.Hide(); };
var isValid = res.partValidate(partnumber.Text);
if (isValid == "Not Found")
{
partnumber.Text = "";
partnumber.RequestFocus();
partqty.ClearFocus();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.SetTitle("Invalid Part");
builder.SetMessage("Part number does not exist in database. Please ensure you are entering the correct part number and try again");
builder.SetPositiveButton("OK", delegate { });
var dialog = builder.Create();
dialog.Show();
}
else
{
partdesc.Text = isValid;
}
}
};
If I leave pd.Hide() in the code then I never see the progressdialog. If I take it out, I only see the progressdialog after the webservice returns its results and then stays up because I haven't hidden it anywhere. How do I get it to show while the app waits for partValidate and when can I hide it?

Judging from your code, it looks like the partValidate() method is synchronous. Since this code is being executed on the UI thread, the app's UI will be blocked for the duration of that method call, which would explain why you don't see any UI updates until it finishes. You could get around this by running the call on a background thread, and then moving back to the UI thread once you need to update the UI:
partnumber.FocusChange += (object sender, View.FocusChangeEventArgs e) =>
{
if (!e.HasFocus)
{
var pd = ProgressDialog.Show(this, "Processing", "Please Wait...", false);
var res = new InventoryApp();
res.partValidateCompleted += delegate { pd.Hide(); };
ThreadPool.QueueUserWorkItem(state =>
{
var isValid = res.partValidate(partnumber.Text);
RunOnUiThread(() =>
{
if (isValid == "Not Found")
{
partnumber.Text = "";
partnumber.RequestFocus();
partqty.ClearFocus();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.SetTitle("Invalid Part");
builder.SetMessage("Part number does not exist in database. Please ensure you are entering the correct part number and try again");
builder.SetPositiveButton("OK", delegate { });
var dialog = builder.Create();
dialog.Show();
}
else
{
partdesc.Text = isValid;
}
}
}
}
};
I have a blog post up here that explains various methods of dealing with this scenario on Mono for Android applications.

As i understood from your question code in partValidate is async but there is no parameter for OnComplete callback. You can solve your problem adding it and your code will be something like this:
var isValid = res.partValidate(partnumber.Text,() => {pd.Hide();});
But the better way is to create implementation of AsyncTask class for you web service call.
Here you can find demo

Related

Ionic - toast message not working inside 'loaderror' eventlistner function of inappbrowser

I'm trying to show toast message when the given url fails to load in inappbrowser,
this is my code
function BrowserLoadError(event) {
browser.close();
loading.dismiss();
this.toast.show("Can't Load the app", '3000', 'center').subscribe(
toast => {
console.log(toast);
}
);
//alert("This App can't be reached now");
}
but however its not working, the toast message is not showing, but it is displaying when we are calling from anyother place other than eventlistner function.
how to make it work within the function?
This is my full code
urlLink(data, target, options): void {
let loading = this.loadingCtrl.create({
spinner: 'bubbles',
content: 'Processing',
duration: 5000
});
let browser = cordova.InAppBrowser.open(data, target, options);
browser.hide();
loading.present();
browser.addEventListener('loaderror', BrowserLoadError);
function BrowserLoadError(event) {
browser.close();
loading.dismiss();
this.toast.show("Can't Load the app", '3000', 'center').subscribe(
toast => {
console.log(toast);
}
);
//alert("This App can't be reached now");
}
}
After a little test, the problem comes actually that this is not your controller when used inside the error callback. Saving the reference in a variable should fix this (pun):
urlLink(data, target, options): void {
let self = this; //save the reference before
let loading = this.loadingCtrl.create({
spinner: 'bubbles',
content: 'Processing',
duration: 5000
});
let browser = cordova.InAppBrowser.open(data, target, options);
browser.hide();
loading.present();
browser.addEventListener('loaderror', BrowserLoadError);
function BrowserLoadError(event) {
browser.close();
loading.dismiss();
//use your variable here
self.toast.show("Can't Load the app", '3000', 'center').subscribe(
toast => {
console.log(toast);
}
);
//alert("This App can't be reached now");
}
}
In the mean time i too found the issue and fixed like this
let toast = new Toast();
toast.show("This App can't be launched now", '5000', 'bottom').subscribe(
toast => {
console.log(toast);
}
);

How to make an async button click update a TextView dynamically with Xamarin Android

In Xamarin Native Android app I am calling methodOne() and getting some details. After this I want to updated the details to text view and then calls the methodTwo(). After executing MethodTwo I have to clear the text details from text view. I tried with
RunOnUiThread(() => tColorDetail.SetText("text", TextView.BufferType.Normal));
The details are displaying after finishing all the methods it is not showing immediately after executing MethodOne().
What is missing here?
.....................................................
public class MainActivity : Activity
{
int count = 1;
ticket Ticket;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
Button bClick= FindViewById<Button>(Resource.Id.bSub);
try {
bClick.Click += delegate {
Job Job;
Action act = new Action();
EditText Address = (EditText)FindViewById(Resource.Id.Address);
act.Address = Address.Text.ToString();
if (!ValidateIPv4(act.Address))
{
ShowMessage("Invalid IP");
}
else
{//TextView Mode = (TextView)FindViewById(Resource.Id.Mode);
string httpUrl = act.iPAddress ;
Ticket = act.ExecuteTicket(httpUrl, "Ticket");
//RunOnUiThread(() => tColorMode.SetText("text", TextView.BufferType.Normal));
// this.RunOnUiThread(() => setTicket(true));
setStatus(" Ticket : Success", true);
setTicket(true);
//tColorMode.SetText("text",TextView.BufferType.Normal);
//tColorMode.Invalidate();
Job = act.executeJob(httpUrl, Ticket);
setStatus(" Job : Success", true);
act.File(httpUrl, Ticket, Job);
setStatus("File Retrieval : Success", true);
setTicket(false);
setStatus("File Retrieval : Success", false);
}
};
}
catch (Exception ex)
{
ShowMessage(ex.Message.ToString());
}
}
public bool ValidateIPv4(string ipString)
{
if (String.IsNullOrWhiteSpace(ipString))
{
return false;
}
string[] splitValues = ipString.Split('.');
if (splitValues.Length != 4)
{
return false;
}
return true;
}
public void setTicket(bool b)
{
//TextView tMode = (TextView)FindViewById(Resource.Id.tMode);
// tMode.SetText("text",TextView.BufferType.Normal);
RunOnUiThread(() => {
TextView tMode = (TextView)FindViewById(Resource.Id.Mode);
tColorMode.SetText("text",TextView.BufferType.Normal);// b==true?Ticket.getProcessing():"";
((TextView)this.FindViewById(Resource.Id.tRes)).Text = b == true ? Ticket.getHeight().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tFormat)).Text = b == true ? Ticket.getFormat().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tOrode)).Text = b == true ? Ticket.getType().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tRot)).Text = b == true ? Ticket.getValue().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tSource)).Text = b == true ? Ticket.getSource().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tSize)).Text = b == true ? Ticket.getAutoDetect().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tExpo)).Text = b == true ? Ticket.getAuto().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tSharp)).Text = b == true ? Ticket.getSharp().ToString() : "";
((TextView)this.FindViewById(Resource.Id.tComp)).Text = b == true ? Ticket.getComp().ToString() : "";
//tColorMode.Invalidate();
}); }
private void ShowMessage(string msg)
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog dialog = builder.Create();
dialog.SetMessage(msg);
dialog.SetButton("OK", (s, ev) =>
{
dialog.Cancel();
});
dialog.Show();
}
private void setStatus(string status,bool b)
{
((TextView)this.FindViewById(Resource.Id.tStatus)).Text = b == true ? status : " ";
}
}
Without access to the full code it is tricky to give you an answer but
Ticket = act.ExecuteTicket(httpUrl, "Ticket");
this line has the potential to take a while to complete if it performs network operations and probably runs in a background thread not to freeze the UI.
Presumably when you get to
// this.RunOnUiThread(() => setTicket(true));setStatus(" Ticket : Success", true);
setTicket(true);
the act.ExecuteTicket call might not have finished
also if there are async operations taking place in
Job = act.executeJob(httpUrl, Ticket);
it could take a while to complete
All taken into consideration, you could probably be getting to
setTicket(false);
setStatus("File Retrieval : Success", false);
before the first calls finish
It could be worth checking
ANSWER UPDATE after discussion in comments:
Since your problem is that your asynchronous calls are taking a long time and you are experiencing "race conditions" because of it (your UI thread is proceeding with the updates on the TextViews before it should), you can solve the situation by changing your button click delegate to an async delegate, and forcing an await on the long operations' result before proceeding.
bClick.Click += async delegate {
//...
Job = await act.executeJob(httpUrl, Ticket);
//...
}

Xamarin Forms ListView ItemSelected functionality

Here is a function that gets called when an item gets selected from a ListView:
async void detail_clicked(object sender, SelectedItemChangedEventArgs e){
if (e.SelectedItem == null) {
return;
}
Detail selected = (Detail)e.SelectedItem;
order_vm.List_of_details.Add(selected);
await DisplayAlert ("Item Added",
String.Format ("{0} added to cart.", selected.detail_name), "Okay");
((ListView)sender).SelectedItem = null;
}
I added this function using the ItemSelected event handler
details_list.ItemSelected += detail_clicked;
The first time I click on the Item, the DisplayAlert pops up. After the first click, the DisplayAlert inside detail_clicked no longer pops up. But the other code inside the handler does get called.
Anyone know how to fix this issue? Is it something I am not understanding about event handlers? Is it something about await/async?
The DisplayAlert might be running on a different thread. Try wrapping Display Alert in Device.BeginInvokeOnMainThread. You can ready about that here.
Please check again without async on method and await on DisplayAlert().
Use this following code. It will helps you.
private void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null)
{
return;
}
listView.SelectedItem = null;
DisplayAlert("Alert", e.SelectedItem.ToString(), "Ok");
}

Thread not terminating correctly, I think

public String newUser = "false";
public double lat = 0.0, lon = 0.0;
I have the following function in my android app (called when a Button is clicked) which starts a thread:
public void SignUpFunction(View view) {
assignValues();
String filledAll = checkIfFilled();
if (filledAll.equals("true")) {
Log.d("LIFECYCLE", "calling thread..");
//my thread
new validateThread().start();
Log.d("After thread start","This log call does not occur");
if (newUser.equals("true")) {
Toast.makeText(this, "Please wait as we obtain your location", Toast.LENGTH_SHORT).show();
getMyLocationFunction();
} else {
return;
}
}
}
validateThread:
class validateThread extends Thread {
public void run() {
Log.d("LIFECYCLE", "validateThread entered...");
try {
newUser = "true";
Log.d("validateThread", "Validated and found new user");
} catch (Exception e) {
Log.d("validateThread", "Exception in validateThread: " + e.getMessage());
}
}
}
The thread runs correctly...but after the last line, it does not go back to its point of start. I don't understand why this is happening because I've used threads before and they all work correctly.
I know I can just give the getMyLocation function inside the thread but I really need it this way.
I've searched for similar questions but none helped.. What am I doing wrong here?
Thanks in advance.
It's a race. SignUpFunction should wait until validateThread decides whether or not to set newUser = "true". Even with the race your code may work sometimes, but that is by accident.

Show DialogBox in loop in android

I am trying to show dialog boxes with contents from the database .The fetched data from the database may contain more than 1 data.So I have to show dialog in for loop.But the dialog shows only for the first row in the database.Here is the code
cursor = sqldb.query(Database_Handler.dbdectab, null,"((" + Database_Handler.gendtime + "<='" + after_1hr + "' and " + Database_Handler.gendtime + ">='" + before_1hr + "') and ("
+ Database_Handler.calused + "='Gregorian' or " + Database_Handler.calused + "='both')) ", null, null, null, null);
notif_count = cursor.getCount();
//dec_name_ctr_builder = new StringBuilder("");
if(notif_count>0)
{
dialog1 = new Dialog(this);
cursor.moveToFirst();
do
{
dec_name =cursor.getString(cursor.getColumnIndex(Database_Handler.decname));
dialog1.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog1.setContentView(R.layout.custom_dialog_alert);
TextView tv_alert = (TextView)dialog1.findViewById(R.id.txt_alert);
tv_alert.setText( dec_name );
Button yes = (Button) dialog1.findViewById(R.id.btn_yes);
Button no = (Button) dialog1.findViewById(R.id.btn_no);
yes.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(donateurl));
startActivity(intent);
dialog1.dismiss();
cursor.close();
sqldb.close();
finish();
}
});
no.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
dialog1.dismiss();
cursor.close();
sqldb.close();
finish();
}
});
dialog1.show();
}while(cursor.moveToNext());
Android dialog boxes are not modal (which is to say, they don't block the background processes).Hence your work is done asycnhronuosly and according to :
Romain guy
We've designed Android to prevent developers from writing synchronous dialogs so you don't really have much of a choice.
SO you can not block the while loop execution in between using Dialog.
Karan_Rana is right. The simplest solution for your answer would be storing the results somewhere else and displaying a new dialog each time some data is left and user clicks on a previous dialogs button.
I know this is a bit late, but I had a similar problem once. I used recursion to loop a dialog box. My situation was unique as I needed to detect an internet connection during app startup. So, this approach may not work for you. But I was able to implement the solution without for loops and blocking the main UI thread. Because I was on a splash screen, there was no other UI I needed to contend so I would simple call the dialog box again until the user chooses to "Quit".
I had a splash screen that would only continue to the landing activity of the app if a network connection was detected.
Sample code below to demonstrate the concept. Note that there are custom methods, but you should get the idea to call the prompt again from within onClick method.
protected void onCreate(Bundle savedInstanceState) {
if (isNetworkAvailable()) {
launchApp();
} else {
retryPrompt();
}
}
private void retryPrompt() {
if (isNetworkAvailable()) {
launchApp();
} else {
final ConfirmDialog dialog = new ConfirmDialog.CustomAlertBuilder(this,
"Internet Connection",
"Internet Connection not detected. Please check your connection.",
"Retry").
setNegBtnLabel("Quit").
setCustomCallback(new CustomDialogCallback() {
#Override
public void onClickPositiveBtn(DialogInterface dialogInterface, int which) {
// go around again.
retryPrompt(); // <<== Call method recursively
}
#Override
public void onClickNegativeBtn(DialogInterface dialogInterface, int which) {
// abort app.
finish();
}
}).build();
dialog.show();
}
}

Categories

Resources