How do I show a ProgressDialog while an HttpRequest executes on Android? - java

I have the following code, which I got by looking at the sample on the Android developer documentation. However, it doesn't actually show the dialog. If I take the dismiss() call out, it displays the dialog AFTER the call to doLogin() finishes, and then never goes away. I don't need it to be fancy, I just want to display something while the request executes.
ProgressDialog dialog = ProgressDialog.show(GameList.this, "",
"Connecting. Please wait...", true);
int r = app.doLogin();
dialog.dismiss();
doLogin() is a method that makes an HTTP request against the server and it returns a status code to indicate if the request was successful.

It's never a good idea to run HTTP requests on a main thread. Spin a worker thread, use a Handler to dismiss the dialog back in the UI thread. Something like this:
ProgressDialog dialog = ProgressDialog.show(GameList.this, "", "Connecting. Please wait...", true);
final Handler h = new Handler(); //will execute on the main thread
new Thread(new Runnable(){
public void run()
{
app.doLogin();
h.post(new Runnable()
{
public void run()
{
dialog.dismiss();
}
}
}
}).start();
The three-level nesting is not necessary, of course. Just trying to illustrate the technique here.

Related

How to start and stop progressbar in android?

I have an activity that calls a second java class. I want after the second class is called to show a progressbar and then return to normal activity execution. I found some other threads but i couldn't make the progressbar to stop.
There's a full example over here.
Quote:
Declare your progress dialog:
ProgressDialog progress;
When you're ready to start the progress dialog:
progress = ProgressDialog.show(this, "dialog title",
"dialog message", true);
and to make it go away when you're done:
progress.dismiss();
Here's a little thread example for you:
// Note: declare ProgressDialog progress as a field in your class.
progress = ProgressDialog.show(this, "dialog title",
"dialog message", true);
new Thread(new Runnable() {
#Override
public void run()
{
// do the thing that takes a long time
runOnUiThread(new Runnable() {
#Override
public void run()
{
progress.dismiss();
}
});
}
}).start();
ProgressDialog is deprecated, so you might want to use a ProgressBar.
I've found this post about deleting one of them.
Well, I think this is rather ridiculous, but here is how I fixed it.
In my xml for the ProgressBar, I added android:visibility="gone"
to hide it by default. Then, in my code, I first told it to display
(View.VISIBLE) before it tried getting the server list, then I told
it to hide (View.GONE) after it was done. This worked (I could see
the progress indicator while the data loaded, then it went away). So
I suppose I couldn't get it to hide in the code because the code is
not what forced it to be visible to begin with... That seems like a
bug to me.
Its very Simple:
to show a Progress
ProgressDialog dialog = ProgressDialog.show(getContext(), "Title", "Message");
and to stop it:
dialog.dismiss();

Sleep() in Android Java

I am following this tutorial to have a loading screen in my program. The tutorial says my activity should Sleep() using the Sleep() command, however it does not recognize Sleep() as a function and provides me with an error, asking if I would like to create a method called Sleep().
Here is the code sample:
public class LoadingScreenActivity extends Activity {
//Introduce an delay
private final int WAIT_TIME = 2500;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
System.out.println("LoadingScreenActivity screen started");
setContentView(R.layout.loading_screen);
findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE);
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
//Simulating a long running task
this.Sleep(1000);
System.out.println("Going to Profile Data");
/* Create an Intent that will start the ProfileData-Activity. */
Intent mainIntent = new Intent(LoadingScreenActivity.this,ProfileData.class);
LoadingScreenActivity.this.startActivity(mainIntent);
LoadingScreenActivity.this.finish();
}
}, WAIT_TIME);
}
}
You can use one of the folllowing methods:
Thread.sleep(timeInMills);
or
SystemClock.sleep(timeInMills);
SystemClock.sleep(milliseconds) is a utility function very similar to Thread.sleep(milliseconds), but it ignores InterruptedException. Use this function for delays if you do not use Thread.interrupt(), as it will preserve the interrupted state of the thread.
The function is Thread.sleep(long).
Note, however, that you should not perform a sleep on the UI thread.
The code you posted is horrible. Please don't use that on an actual device. You will get an "Application Not Responding" error if you run something similar to this.
If you're using Handlers, keep in mind that a Handler is created on the thread where it runs. So calling new Handler().post(... on the UI thread will execute the runnable on the UI thread, including this "long running operation". The advantage is that you can create a Handler to the UI Thread which you can use later, as shown below.
To put the long running operation into a background thread, you need to create a Thread around the runnable, as shown below. Now if you want to update the UI once the long running operation is complete, you need to post that to the UI Thread, using a Handler.
Note that this functionality is a perfect fit for an AsyncTask which will make this look a lot cleaner than the pattern below. However, I included this to show how Handlers, Threads and Runnables relate.
public class LoadingScreenActivity extends Activity {
//Introduce a delay
private final int WAIT_TIME = 2500;
private Handler uiHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
uiHandler = new Handler(); // anything posted to this handler will run on the UI Thread
System.out.println("LoadingScreenActivity screen started");
setContentView(R.layout.loading_screen);
findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE);
Runnable onUi = new Runnable() {
#Override
public void run() {
// this will run on the main UI thread
Intent mainIntent = new Intent(LoadingScreenActivity.this,ProfileData.class);
LoadingScreenActivity.this.startActivity(mainIntent);
LoadingScreenActivity.this.finish();
}
};
Runnable background = new Runnable() {
#Override
public void run() {
// This is the delay
Thread.Sleep( WAIT_TIME );
// This will run on a background thread
//Simulating a long running task
Thread.Sleep(1000);
System.out.println("Going to Profile Data");
uiHandler.post( onUi );
}
};
new Thread( background ).start();
}
use Thread.sleep(1000);
1000 is the number of milliseconds that the program will pause.
try
{
Thread.sleep(1000);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
Keep in mind: Using this code is not recommended, because it is a delay of time but without control and may need more or less time.

Using a progressdialog and handler

I'm working on an app that connect to a webpage to get some content. I want to show a progressdialog, but I think I'm doing something wrong.
This is my code:
final ProgressDialog myProgressDialog = ProgressDialog.show(WhoisBeyondActivity.this, "Wait...", "Fetching data...", true);
Handler handler=new Handler();
handler.post(new Runnable()
{
public void run()
{
try {
// code to execute
Thread.sleep(2000);
} catch (Exception e) {
}
myProgressDialog.dismiss();
}
});
The problem is that the progressdialog is only shown one second at the end of the operation I want to make. I think the progressdialog is only executing when I execute the dismiss() because it appears and dissapears quickly. Is like the progressdialog appears only to dissapear ... help me please!!! I have read a lot of tutorials, and I have try a lot of option, like THREAD instead of HANDLER, but it is not usefull for me, because I have to edit UI.
There's an excellent example and tutorial here:
http://www.helloandroid.com/tutorials/using-threads-and-progressdialog
That's what I used the first time I did a threaded dialog in Android, and I bookmarked it. Hopefully it helps.
The reason you are getting the described behaviour is that the post method will just execute the passed in runnable against the thread to which the Handler is attached. In your case this is the UI thread.
You are calling ProgressDialog.show(), which is asynchronous. This does not actually show the dialog as soon as the method returns, rather you have just requested that the UI display a dialog. You then immediately post a thread that sleeps for 2 seconds, which is added to the UI queue and blocks the UI from performing the dialog show. The UI then wakes from your sleep, shows the dialog then is dismissed.
You should perform any network operation in either a new Thread or in an AsyncTask. Have a look at these links for more details:
AsyncTask
Painless threading
Threading
Designing for responsiveness
Thread documentation
Handler documentation
You don't want to use a separate thread per-say. What you really want is an AsynTask. This will allow you to create the progress dialog and do the background processing right there in the task. Simple to write and easier to implement. If your refer to the link, what you need is actually really similar to your question. With a little tweaking, it should work just fine for you.
public class HelloActivity extends Activity {
protected static final String TAG = "HelloActivity";
ProgressDialog myProgressDialog;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//
showDialog(1);
final Handler handler=new Handler(){
#Override
public void handleMessage(Message msg) {
//update UI here depending on what message is received.
switch(msg.what){
case 0:
myProgressDialog.dismiss();
}
super.handleMessage(msg);
}
};
Thread t = new Thread(){
public void run(){
try {
// code to execute
Thread.sleep(5000);
} catch (Exception e) {
}
handler.sendEmptyMessage(0);//nothing to send
}
};
t.start();
}
#Override
protected Dialog onCreateDialog(int id) {
myProgressDialog = ProgressDialog.show(HelloActivity.this, "Wait...", "Fetching data...", true);
return myProgressDialog;
}
}

Android thread confusion

I have written a function to create a splash screen with a 5 second timeout for my app.
The code works fine, but when the timeout reaches zero and I want to redirect to my main activity, the app crashes with the following error:
Only the original thread that created a view hierarchy can touch its views.
So I looked around a bit and someone suggested nesting this inside my function. It seems like a good Idea, but now methods like sleep / stop won't work.
My code is below, I can provide more / explain more in details if it isn't clear enough just let me know. Thanks for the help.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
showSplashScreen();
}
protected boolean _active = true;
protected int _splashTime = 5000; // Splash screen is 5 seconds
public void showSplashScreen() {
setContentView(R.layout.splash_layout);
// Thread splashThread = new Thread() {
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
int waited = 0;
while (_active && (waited < _splashTime)) {
Thread.sleep(100);
if (_active) {
waited += 100;
}
}
} catch (InterruptedException e) {
// do nothing
} finally {
showApplication();
}
}
});
}
Probably not what you want to hear, but you should never put a splash screen on your mobile app. With the exception of games, when people use a mobile app they want to get in, do what ever it is they need to do, and get out. If you make that process take longer, people are just going to get frustrated with you app. You should probably reconsider just not using a splash screen.
This will perform sleep on the UI thread. That's never a good idea.
Why not something like this?
new Handler().postDelayed(new Runnable() {
public void run() {
// start application ...
}
}, _splashTime);
But this answer has a good point. Displaying a splash screen for 5 seconds can be very annoying.
I believe you want AsyncTask for this. The method called on completion of the task will be called on your UI thread, making modifying UI elements much easier.
Use a Handler to post an event to the UI thread that will remove the splash.
Code should be something like...
splash.show()
new Handler().postDelayed(
new Runnable() {
void run() {
splash.remove();
},
delayTime);
I suggest you to make new activity for your spalsh screen, show it in a regular way (with startActivityForResult) and place in it such code (in it, not in your main activity):
new Handler().postDelayed( new Runnable()
{
public void run()
{ finish(); }
}, 5000 );
Also you can handle in this new activity click events for giving opportunity to user to close it faster, tapping on it.

Access a thread to notify it from another method (Android application)

I'm developping an android application and trying to deal with threads without really knowing a lot about them... (Yeah bit stupid of me, I know)
I'll try to explain it properly and quite quickly.
In the onCreate method of my activity, I'm calling an AlertDialog to make the user choose to either load data from the internet or directly access the application using the data previously stored in database.
For that, in the onCreate, I call my method to raise the AlertDialog, positive button should start the worker thread to download, and negative button should call intent to move to next activity. So far, I got this :
by not calling wait() anywhere, my AlertDialog appears but the thread starts anyway
by calling wait() at the first line of my thread, I have to declare it static to access it from the listeners of my AlertDialog and be able to notify() it or interrupt(), I receive the error: object not locked by thread before wait().
worker = new Thread(new Runnable() {
public void run() {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
[rest of my run method]
private void miseAJourDesDonnes() {
confirmInscrip = new AlertDialog.Builder(this).setMessage(
"Voulez-vous mettre à jour l'intégralité des données de l'application? (Connexion internet requise").setPositiveButton("Mettre à jour",
okListener).setNegativeButton("Continuer sans", nonListener);
confirmInscrip.create();
confirmInscrip.show();
}
OnClickListener okListener = new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
Toast.makeText(AccueilSplash.this, "Mise à jour en cours", Toast.LENGTH_SHORT).show();
worker.notify();
return;
}
};
OnClickListener nonListener = new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
Toast.makeText(AccueilSplash.this, "Accès direct à l'application", Toast.LENGTH_SHORT).show();
worker.interrupt();
Intent entre = new Intent(AccueilSplash.this, Androt.class);
startActivity(entre);
}
};
worker is my instance of Thread (the bbackground one)
Am I just being dumb or Is there a subtility I havent grasped?
thanks for any answer...
Below is a quick explanation of how wait() and notify() works but might I suggest that you just don't create the worker thread unless the user clicks ok? You may still want to cancel the thread later if they want to stop the download but creating the thread before you even know if it going to be used doesn't seem like the best approach.
In order to call wait(), notify(), or notifyAll() on an object you must first own the monitor of the object you wish to call the method on, so in you case within the runnable this would be how you would need to do it:
Runnable runnable = new Runnable() {
public void run() {
// wait(); This call wouldn't work
syncronized (this) {
wait(); // This call will work
}
}
};
To notify that runnable you would also have to have the monitor
// runnable.notifyAll(); this call will not work
syncronized (runnable) {
runnable.notifyAll(); // this call will work
}
For more information about threads and concurrency in Java I would suggest Java Concurrency in Practice
There may be some built in framework for background tasks in Android that I don't know about but using pure java the easiest approach to this seems like it would be something like this:
private Thread downloadThread;
OnClickListener okListener = new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
Runnable download = new Runnable() {
public void run() {
// Create your input streams and such
boolean downloadComplete = false;
while(!downloadComplete && !Thread.currentThread().isInterruped()) {
// Do some downloading
}
if (!Thread.currentThread().isInterruped()) {
// Alert user of success.
}
}
};
downloadThread = new Thread(download);
downloadThread.start();
}
};
OnClickListener cancelListener = new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
downloadThread.interrupt();
}
};
I'm new to using threads as well, but you could try reading this example to give you a good starting point. It's about progress dialogs, but it illustrates how to manage threads and start them up at the right time. The really useful code is collapsed under the 'see more about Progress Dialgos with a second Thread' section.
Going to your code, I think your mistake is in how you declare your thread. Try instead creating is as a class extending Thread. e.g.
private class Worker extends Thread{
Handled mHandler; //See the example linked above for how to use handlers
int progress;
//and whatever other variables it might need
worker(Handled h){
mHandler = h;
//and any other initialisation you need
}
public void run(){
//and all your code here
}
}
Then nothing happens with this Thread until you instantiate it with the following, in your onClickListeners.
Worker worker = new Worker(handler)
Even after that it won't actually start until you call worker.start(). Define your handler along the lines of
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
int progress = msg.getData().getInt("progress");
loadingDialog.setProgress(progress);
if (progress >= 100){
dismissDialog(LOADING_DIALOG);
}
}
};
Hope that helps you get started! Do read the link above, as I imagine you'll want some kind of progress dialog as well when it's actually doing the loading from the website. Or perhaps it would be done in a background service, but I couldn't help you with that.

Categories