I have an about screen in my app that opens in an AlertDialog, in which I include the text from Google's open source API license. However, it takes almost 30 seconds to load the AlertDialog, and doing so often freezes the UI thread.
private void about() {
AlertDialog.Builder builder= new AlertDialog.Builder(this);
builder.setTitle("About ...");
builder.setNeutralButton("Close",null);
Toast.makeText(this,"Loading...",Toast.LENGTH_LONG).show();
GoogleApiAvailability googleApi=GoogleApiAvailability.getInstance();
String text=googleApi.getOpenSourceSoftwareLicenseInfo(getContext());
String str=getResources().getString(R.string.about_message);
str+=text;
builder.setMessage(str);
builder.show();
}
EDIT: The line that is causing this lag is the one that sets the dialog's text.
Note: I have already tried running the whole thing in an AsyncTask, and doing so did not change anything.
If anyone else is having this problem, one solution that works is to prevent the activity from overlaying another activity (if it uses Theme.Dialog, remove that). While this does not completely speed it up, it prevents the UI thread from being frozen for as long.
Related
Because you must include a legal notice when using google maps on android I added the following code to my fragment:
//in oncreate view method
_noticeMaps.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
Toast.makeText(getActivity().getApplicationContext(), "Loading", Toast.LENGTH_LONG).show();
showLegalNotice();
}
});
public void showLegalNotice(){
_legalNotice = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(getActivity());
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Legal Notice");
builder.setMessage(_legalNotice);
AlertDialog dialog = builder.create();
dialog.show();
}
Because the legal notice takes a long time to be placed in the setMessage the app shows the dialog after a few seconds (5+). Thats why i added the toast before the showLegalNotice to notice the user that its loading. However the toast shows after the dialog is loaded. Why isnt the toast showing before the dialog is loading? I call showLegalNotice AFTER i create the toast. I know i can fix it with threads but I want to understand why the toast is showing after the dialog is created.
The best solution is to put the legalNotice method codes in an AsyncTask. The Toast is shown after the dialog because you are doing the heavy work on the UI thread which is making it busy and that's why the toast is lagging behind.
If you don't know about AsyncTask, you can learn about it here. You can show the Toast in the preExecute() method of the AsyncTask. It will be guaranteed that the toast will be shown before any other action is taken.
UPDATE
Yes, you are right. The code is run in a sequential manner so the Toast should have been shown before the method runs. But try to think in a different way.
The Toast is an system UI component. You call show() on toast and your code moves to the next heavy or long-running task almost instantly.
There is always a slight delay for the toasts to be drawn or initiated on your screen and it also depends on various flavours of Android. So, before the toast starts to draw on the screen, the UI thread gets busy or jammed on performing a long-running task and looses frames.
Just when the long-running task of your method ends, the UI thread gets free once again and is able to resume drawing the toast. That is why, the toast is displayed, but always after the method completed its execution.
I am creating an app MainActivity that can calculate a report from its database to be shown in ReportActivity. All report calculation is done in ReportActivity.onCreate().
When the user click on MainActivity-s menu "generate report" the menĂ¼ remains open for 2 secs until ReportActivity.onCreate() has finished and the report becomes visible.
What is the easiest way to give the user some visual feedback?
I already found ProgressDialog onCreate that shows a progressdialog while doing all calculation in an AsyncTask.
I wonder if there is some easier way to give the user some visual feedbak that the menue was successfully clicked and that the device has not crashed.
in ms windows i would use a waitcursor (hour-glass)
I already tried to open a ProgressDialog() in oncreate of the ReportActivity
final ProgressDialog progressDialog = ProgressDialog.show(this, "MY Dialog", "Please wait...");
but it is not shown at all.
Update final solution:
As the answerss suggested I implemented an AsyncTask for the processing following this tutorial
based on this codesample
You need to move your long-running code into a background thread. Long-running code on the UI thread will lock up the UI, which causes the user to think the app is frozen/crashing. Look into using AsyncTask. This allows you to run a process on a background thread and also give visual feedback to let the user know that your app is working.
Design a layout with ProgressDialog. Use setContentView(Progressdialog). Count time for 2-4 seconds (you choice) again set your older layout in setContentView. Why don't you use AsyncTask?
Use a bar or circle activity indicator. From the official design guide:
Activity indicators are for operations of an indeterminate length.
They ask users to wait a moment while something finishes up, without
getting into specifics about what's happening behind the scenes.
Let's say we have two buttons, each with a OnClickListener. Each of listeners show a ProgressDialog and do some background work. (Behind the scene is an AsyncTask, the dialog is opened in onPreExecute. I don't think it matters, just for the record...). Let's say there is some rule saying no more than one background worker may be active at any given time.
My assumption was that the Dialog prevents two background workers running at the same time. I thought the modal dialog blocks the UI and it's not possible to click another button after the show() method of the dialog is called. I was wrong.
If you click the buttons fast enough, it's possible to trigger both background workers (almost) at the same time. The log shows that it's possible to click two Buttons within a 150 ms time span despite the Dialog:
04-14 18:34:04.390: DEBUG/greenrobot(1860): Clicked: 2131034112
04-14 18:34:04.470: DEBUG/greenrobot(1860): doInBackground2: 2131034112
04-14 18:34:04.540: DEBUG/greenrobot(1860): Clicked: 2131034113
04-14 18:34:04.570: DEBUG/greenrobot(1860): doInBackground2: 2131034113
The dialog code looks like this:
progressDialog = new ProgressDialog(currentActivity);
progressDialog.setMessage(msg);
progressDialog.show();
What did I miss? I hope I missed something really stupid, because if not, I cannot think of a nice and solution preventing UI interaction after the click. Synchronizing the background workers is not a solution because the UI and scenario is more complex.
Disable the button after it is clicked, until it is safe to be clicked again.
show() is asynchronous. The dialog will not appear immediately upon the call to show(). It will occur moments later.
I've searched through Stackoverflow, looked at the examples in Android Developer, and some books and I'm just not getting it.
I'm trying to show an AlertDialog Box that interrupts the program flow. Most of the examples I've seen don't have code after the dialog box and I need my program to stop executing until the AlertDialog button is pressed. Seems as if the AlertDialog is created from another thread and I'm not sure how to retrieve that thread.
Program logic: If the parsing is bad the program will force close. I want to let the user know to restart the program and everything will work. (I'm dropping and recreating tables and they are repopulated when the program starts back up)
Here's some code:
if(database populated)
{
....code.....
if(parseok.contentEquals("Error"))
{
doForceClose();
}
displayDate = "Last: " + parseok; //I don't want the program to continue to here.
//Rest of code in the method. If I continue the program will Force Close
}
else
do something else
Here's the AlertDialog method:
private void doForceClose()
{
String themessage = "Because some of the parameters have changed in the yada yada";
AlertDialog.Builder ad = new AlertDialog.Builder (this);
ad.setTitle("Internal Error");
ad.setMessage(themessage);
ad.setPositiveButton("Sorry", new OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
finish();
return;
}
});
ad.create();
ad.show();
}
except ad doesn't show and the program continues to its force close.
Obviously I'm not getting something. Any ideas?
edit: I am in a Class that extends Activity
I'm trying to show an AlertDialog Box that interrupts the program flow.
That does not exist in Android and various other UI systems.
I need my program to stop executing until the AlertDialog button is pressed.
No, you don't. Event-driven programming has been in use for a couple of decades.
Program logic: If the parsing is bad the program will force close.
That's your code -- rewrite it to behave better.
I don't want the program to continue to here.
Then use an else, or a return, or something.
except ad doesn't show and the program continues to its force close.
Your dialog will not appear until the main application thread gets control again to process your request -- show() is asynchronous. You are crashing before then, most likely.
In short, your strategy for dealing with your parsing problem is fundamentally flawed.
The Commonsware response s correct. Let me try and say the same thing in different words.
An alert dialog does NOT interrupt the flow of control. It is just "left showing" when the program is waiting for input.
thus the sequence
showAlert("this is a message);
showGallery();
return;
this shows only momentarily.
A way out of this is to put the showGallery() function call inside the Positive response from the AlertDialog.
So to put it another way. If you want to interrupt the flow of your app with an AlertDialog (which is wisely pointed out is the wrong thing to want) then put the code you want executed after the dialog into the onClick callback of the AlertDialog.
OK, I had a similar situation. I was expecting a dialog to pop-up but it didn't. Instead, an exception occurred. The place where the exception occurred was positioned a couple of rows behind the place where I was expecting the dialog. I fixed this exception and then my dialog appeared.
It looks strange, and I think the dialog needs time to appear while the program just continues to run and then the program encounter the exception, chronological (but not programatically) before the dialog.
That's why I got dialog after I fixed the exception place.
Is there a generic way to determine if there is dialog currently shown ? Sure, i can keep track of all createDialog and dismissDialog invocations, but that's cumbersome.
thanks
I use this method:
protected void showDialogSafe(int id) {
if (!isFinishing()) {
showDialog(id);
}
}
Which I grabbed from here: http://daniel-codes.blogspot.com/2009/12/activities-and-dialogs.html
When dismissing them I just catch the IllegalArgumentException.
Falmarri, keeping track of the dialogs seems to be easier said than done when you have multiple threads running. I thought my code was perfect, but I get a bunch of crash reports when my app tries to dismiss dialogs that aren't shown or tries to display a dialog when the activity is finished.