i have an app that contains a dialog
i want to close this dialog after x second, when user haven't any interact with app, like volume seekbar popup(that's open when the volume button clicked, and closed after 2 second of inactivity).
what is the simplest way to implement this?
thank you
You could for example use a Handler and call its .removeCallbacks() and .postDelayed() method everytime the user interacts with the dialog.
Upon an interaction, the .removeCallbacks() method will cancel the execution of .postDelayed(), and right after that, u start a new Runnable with .postDelayed()
Inside this Runnable, you could close the dialog.
// a dialog
final Dialog dialog = new Dialog(getApplicationContext());
// the code inside run() will be executed if .postDelayed() reaches its delay time
final Runnable runnable = new Runnable() {
#Override
public void run() {
dialog.dismiss(); // hide dialog
}
};
Button interaction = (Button) findViewById(R.id.bottom);
final Handler h = new Handler();
// pressing the button is an "interaction" for example
interaction.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
h.removeCallbacks(runnable); // cancel the running action (the hiding process)
h.postDelayed(runnable, 5000); // start a new hiding process that will trigger after 5 seconds
}
});
For tracking user interaction, you could use:
#Override
public void onUserInteraction(){
h.removeCallbacks(runnable); // cancel the running action (the hiding process)
h.postDelayed(runnable, 5000); // start a new hiding process that will trigger after 5 seconds
}
Which is available in your activity.
I like to do this with AsyncTask:
class ProgressDialogTask extends AsyncTask<Integer, Void, Void> {
public static final int WAIT_LENGTH = 2000;
private ProgressDialog dialog;
public ProgressDialogTask(Activity activity) {
dialog = new ProgressDialog(activity);
}
#Override
protected void onPreExecute() {
dialog.setMessage("Loading");
}
#Override
protected Void doInBackground(final Integer... i) {
long start = System.currentTimeMillis();
while(!isCancelled()&&System.currentTimeMillis()-start< WAIT_LENGTH){}
return null;
}
#Override
protected void onPostExecute(final Void v) {
if(dialog.isShowing()) {
dialog.dismiss();
}
}
}
Then trigger it from your Activity on click:
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ProgressDialogTask task = new ProgressDialogTask(this);
task.execute(0);
}
});
If you need better precision you can also use System.nanoTime()
I am also new at android, but I recommend creating a timer, and when lets say the timer t is greater than or equal to 2, then you do something. It would look kind of like this
if (t >= 2.0){
//Do whatever you want it to do
}
This may not work for your purposes, but it's just something that may require less lines of code in the end. (as I always say, less code is more code) I know that timers are basically easy to make, but I have never used one in an app. I wouldn't specifically know how to make the timer, but I'm sure you can find a tutorial on youtube.
This is the question that came up when I was looking up things regarding timing out. I have implemented an answer which uses AsyncTask, Handler, and Runnable. I am providing my answer here as a potential template for future answer searchers.
private class DownloadTask extends AsyncTask<Void, CharSequence, Void> {
//timeout timer set here for 2 seconds
public static final int timerEnd = 2000;
private Handler timeHandler = new Handler();
#Override
protected void onPreExecute() {
ProgressDialog dProgress = new ProgressDialog(/*Context*/);
dProgress.setMessage("Connecting...");
dProgress.setCancelable(false);
dProgress.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//Dismissing dProgress
dialog.dismiss();
//Removing any Runnables
timeHandler.removeCallbacks(handleTimeout);
//cancelling the AsyncTask
cancel(true);
//Displaying a confirmation dialog
AlertDialog.Builder builder = new AlertDialog.Builder(/*Context*/);
builder.setMessage("Download cancelled.");
builder.setCancelable(false);
builder.setPositiveButton("OK", null);
builder.show();
} //End onClick()
}); //End new OnClickListener()
dProgress.show();
} //End onPreExecute()
#Override
protected Void doInBackground(Void... params) {
//Do code stuff here
//Somewhere, where you need, call this line to start the timer.
timeHandler.postDelayed(handleTimeout, timerEnd);
//when you need, call onProgressUpdate() to reset the timer and
//output an updated message on dProgress.
//...
//When you're done, remove the timer runnable.
timeHandler.removeCallbacks(handleTimeout);
return null;
} //End doInBackground()
#Override
protected void onProgressUpdate(CharSequence... values) {
//Update dProgress's text
dProgress.setMessage(values[0]);
//Reset the timer (remove and re-add)
timeHandler.removeCallbacks(handleTimeout);
timeHandler.postDelayed(handleTimeout, timerEnd);
} //End onProgressUpdate()
private Runnable handleTimeout = new Runnable() {
public void run() {
//Dismiss dProgress and bring up the timeout dialog
dProgress.dismiss();
AlertDialog.Builder builder = new AlertDialog.Builder(/*Context*/);
builder.setMessage("Download timed out.");
builder.setCancelable(false);
builder.setPositiveButton("OK", null);
builder.show();
}
}; //End Runnable()
} //End DownloadTask class
To those somewhat new to using AsyncTask, you must make a DownloadTask object and call .execute().
For example:
DownloadTask dTaskObject = new DownloadTask();
dTaskObject.execute();
I actually also took this code further than what you see by having all my doInBackground() code be done via a function, so I actually had to call onProgressUpdate() and other functions using the DownloadTask object.
Related
I'm creating a simple app that will stream the internet radio station. So when the user clicks the play button I want to show a progress bar (loading circle) until the stream is being played.
I have two Runnables, one to show the progress bar, other to load audio stream and play. This is a progress bar Runnable:
private Runnable showProgressBar = new Runnable() {
#Override
public void run() {
progBar.setVisibility(View.VISIBLE);
}
};
Than on button click:
buttonPlay.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Handler show_progress_h = new Handler();
show_progress_h.post(showProgressBar);
Handler play_h = new Handler();
play_h.post(startPlayingThread);
}
});
But... the progress bar loads much to late. It loads when the radio is almost loaded, so you only see it for a blink. Is it possible to show it immediately after the button was clicked? I have no idea what is slowing it down. Should I use something else instead of Handler?
Oh and btw... I also tried both with no handlers, but the response is the same.
The problem is you are posting long running task on UI thread immidiatly after showing progressbar:
buttonPlay.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Handler show_progress_h = new Handler();
show_progress_h.post(showProgressBar);
Handler play_h = new Handler();
play_h.post(startPlayingThread);//<< issue is here
}
});
Instead do something similar to this:
buttonPlay.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Handler show_progress_h = new Handler();
show_progress_h.post(showProgressBar);
new AsyncTask<Void, Void, Void>(){
#Override
protected void doInBackground(Void v){
// perform long runningtask here that you are performing in
//startPlayingThread
}
}.execute();
}
});
For more detail check this tutorial: http://www.vogella.com/articles/AndroidBackgroundProcessing/article.html#concurrency_asynchtask
You can use new Thread(your_runnable).start() as an alternative, and try debugging it.
I know that there are many similar AsyncTask questions already, but in my case something is very unusual or am I missing something !?
As the AsyncTask is not allowed to run more than once. I call it with new B().execute(); so it should create a separated instance on each run !? Right?
The problem is after the B class is created and executed once, it wont work the second time the user calls the startBClass() method (just opens the dialog, but the actual work is not happening).
I just Debugged the code and realize that after the Dialog is closed, the Thread is still running in the background. What is the proper way to stop the background thread when the Dialog is closing? - And since I'm closing the first Dialog inside B class and create another instance of the B class, why is the second one not working? Can't multiple AsyncTasks run in parallel !?
I simplified the classes for easier understanding what I'm trying:
public class A {
/* Is called when user clicks a button */
private void startBClass() {
new B().execute();
}
/* Opens a Dialog with a countdown TextView (works first call only) */
private class B extends AsyncTask<Void, Integer, Void> {
private int secondsPassed = 0;
private double totalToPay = 0;
private Dialog dialog;
private TextView tvCost;
private Button dialogBtn;
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new Dialog(ConfigurationActivity.this);
dialog.setCancelable(true);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.dialog);
dialog.setCanceledOnTouchOutside(false);
dialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
onPostExecute(null);
}
});
tvCost = (TextView) dialog.findViewById(R.id.textCounter);
dialogBtn = (Button) dialog.findViewById(R.id.button1);
dialogBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
dialog.cancel();
}
});
dialog.show();
}
#Override
protected Void doInBackground(Void... arg0) {
while(true){
publishProgress(secondsPassed++);
SystemClock.sleep(1000);
}
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
totalToPay = 12.00;
tvCost.setText(totalToPay + " USD");
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
final AlertDialog alert = new AlertDialog.Builder(ConfigurationActivity.this).create();
alert.setTitle("Information");
alert.setMessage("You should pay about " + totalToPay + " USD.");
alert.setButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface alertDialog, int which) {
alertDialog.dismiss();
}
});
alert.show();
}
}
}
dialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
onPostExecute(null);
}
});
This is no good. Per the docs:
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
To end it, I'd change both the code above, and the while loop in doInBackground().
protected Void doInBackground(Void... arg0) {
while(running){
publishProgress(secondsPassed++);
SystemClock.sleep(1000);
}
}
running is a boolean you set to true in onPreExecute(). Set it to false when you want to end it. Then your loop will exit and onPostExecute() will be called correctly.
Side note: Where is secondsPassed ever used?
my code:
OnClickListener()//onclicklistener for button
{
ProgressBar = new ProgressDialog(LoginPageActivity.this);
ProgressBar.setMessage("please wait..");
ProgressBar.show();
TcpConnection loginConnect = new TcpConnection();//TcpConnection is a class
loginConnect.run();
ProgressBar.dismiss();
}
i tried to show progress dialog before calling another class and dismiss it after the call is over. but progressbar will not showing and it dismissed early . but i want to show progress bar for certain period of time.
Inside tcp connection class: having socket connection for user name password thats y i need to display progress for certain period of time
i dont know how to do it!
How I understand you need to use threads. Like this
ProgressBar p = new ProgressDialog(LoginPageActivity.this);
Private Handler handler = new Handler();
p.setVisibality(0); //makes visible
new Thread(new Runnable() {
public void run() {
TcpConnection loginConnect = new TcpConnection();
loginConnect.run();
handler.post(new Runnable() {
public void run() {
p.setVisibility(8);//Makes Invisible
}
});
}
}).start();
I think it will help you
Use AsyncTask to achieve your objective. You can show the progressbar(inside onPreExecute()) until your task gets over(inside doInBackground()) and then you can dismiss it after the task is finished(inside onPostExecute()).
Check this link for more details:
http://developer.android.com/reference/android/os/AsyncTask.html
My guess is that loginConnect.run() is running in its own thread. That's why the progress dialog is being dismissed instantly.
Here's what you should do instead:
class LoginTask extends AsyncTask<Void, Void, Void>{
ProgressDialog d;
#Override
protected void onPreExecute() {
super.onPreExecute();
d = new ProgressDialog(LoginPageActivity.this);
d.setMessage("please wait..");
d.show();
}
#Override
protected Void doInBackground(Void... params) {
TcpConnection loginConnect = new TcpConnection();
loginConnect.run();
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
d.dismiss();
}
}
And in your onClickListener call new LoginTask().execute();
I have created a ProgressDialog in android and it works when I do a simple example.
For example, this works.
public void onClick(View v)
{
// Perform action on click
System.out.println("Progess Bar");
final ProgressDialog myProgressDialog = ProgressDialog.show(AndroidTestApplicationActivity.this,
"Please wait...", "Getting updates...", true);
new Thread()
{
public void run()
{
try
{
// Do some Fake-Work
sleep(5000);
}
catch (Exception e)
{
}
// Dismiss the Dialog
myProgressDialog.dismiss();
}
}.start();
}
But once I add in a reference to my custom class, it just stops running this new thread.
button1.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
// Perform action on click
System.out.println("Progess Bar");
// Display an indeterminate Progress-Dialog
final ProgressDialog myProgressDialog = ProgressDialog.show(AndroidTestApplicationActivity.this,
"Please wait...", "Getting Updates...", true);
new Thread()
{
public void run()
{
try
{
HealthySubObject hsObject = new HealthySubObject();
// Do some more work with my hsObject - nothing happens after this point.
sleep(5000);
}
catch (Exception e)
{
}
// Dismiss the Dialog
myProgressDialog.dismiss();
}
}.start();
}
});
What happens is that as soon as I click this button, the progress dialog flashes up on the screen real quick and then disappears. But if you look at my code, it should wait 5 seconds before disappearing. I have put debug statements before and after the reference to my custom class and I can see the statements before but not the ones after. Does anyone have any idea why that is happening? As long as my class is public I should be able to call it from a new thread, right?
I am still pretty new to android and this is my first adventure into multi-threaded android apps. Any help would be much appreciated.
SOLUTION
Thanks for your help everyone. It is working now.
button1.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
// Perform action on click
System.out.println("Progess Bar");
//ProgressDialog dialog = ProgressDialog.show(AndroidTestApplicationActivity.this, "", "Loading. Please wait...", true);
// Display an indeterminate Progress-Dialog
final ProgressDialog myProgressDialog = ProgressDialog.show(AndroidTestApplicationActivity.this,
"Please wait...", "Doing Extreme Calculations...", true);
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
#Override
public void run()
{
HealthySubObject hsObject = new HealthySubObject();
ArrayList<HashMap<String, String>> onlineDB = hsObject.jsonToArray();
//
// more stuff goes here.
//
//
myProgressDialog.dismiss();
}
}, 1500);
}
});
I would really recommend to use Handler instead of Thread. Using the Thread.sleep method is actually discouraged. Something like this is much better:
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
HealthySubObject hsObject = new HealthySubObject();
myProgressDialog.dismiss();
}
}, 5000);
The problem is that you need to be on the UI thread to do modify the UI, and inside the run() method of your Thread you are in a "background" thread. Try using a handler inside your thread when you need to access the UI thread.
My application fetches some html code from the internet and when done , displays it on the devices screen. Since it takes about 3-4 seconds to do that , in this time the screen stays black , I'd like to use a progress dialog. This is my code :
package com.nextlogic.golfnews;
// ALL THE IMPORTS ....
public class Activity1 extends Activity {
private ProgressDialog progressDialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main2);
progressDialog = ProgressDialog.show(Activity1.this, "", "Loading...");
new Thread()
{
public void run()
{
try
{
sleep(2000);
// HERE I'VE PUT ALL THE FUNCTIONS THAT WORK FOR ME
}
catch (Exception e)
{
Log.e("tag",e.getMessage());
}
// dismiss the progressdialog
progressDialog.dismiss();
}
}.start();
The program works but it doesn't display anything anymore. I have one error in logcat :
Only the original thread that created a view hierarchy can touch its views.
Could you please help me ? Thanks in advance.
The error is explicative enough. To update one visual object you must run the changes inside main thread. A quick and dirty fix could be calling the update code inside runOnUiThread().
However in your case I would use an AsyncTask to download and update the progress of the progress bar. The task has the property to run on UI thread when it ends (so you can update the views there, such as dismissing the progress dialog)
Here is an example how to use an AsyncTask to display a download progress dialog.
Update
Stackoverflow already has the answers to all your question. Here is an example of an AsyncTask to download some content and display the download progress. Just what you want.
Update 2
Ok here is your code using an AsyncTask:
public class Activity1 extends Activity
{
private ProgressDialog progressDialog;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new AsyncTask<Integer, Integer, Boolean>()
{
ProgressDialog progressDialog;
#Override
protected void onPreExecute()
{
/*
* This is executed on UI thread before doInBackground(). It is
* the perfect place to show the progress dialog.
*/
progressDialog = ProgressDialog.show(Activity1.this, "",
"Loading...");
}
#Override
protected Boolean doInBackground(Integer... params)
{
if (params == null)
{
return false;
}
try
{
/*
* This is run on a background thread, so we can sleep here
* or do whatever we want without blocking UI thread. A more
* advanced use would download chunks of fixed size and call
* publishProgress();
*/
Thread.sleep(params[0]);
// HERE I'VE PUT ALL THE FUNCTIONS THAT WORK FOR ME
}
catch (Exception e)
{
Log.e("tag", e.getMessage());
/*
* The task failed
*/
return false;
}
/*
* The task succeeded
*/
return true;
}
#Override
protected void onPostExecute(Boolean result)
{
progressDialog.dismiss();
/*
* Update here your view objects with content from download. It
* is save to dismiss dialogs, update views, etc., since we are
* working on UI thread.
*/
AlertDialog.Builder b = new AlertDialog.Builder(Activity1.this);
b.setTitle(android.R.string.dialog_alert_title);
if (result)
{
b.setMessage("Download succeeded");
}
else
{
b.setMessage("Download failed");
}
b.setPositiveButton(getString(android.R.string.ok),
new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dlg, int arg1)
{
dlg.dismiss();
}
});
b.create().show();
}
}.execute(2000);
new Thread()
{
#Override
public void run()
{
// dismiss the progressdialog
progressDialog.dismiss();
}
}.start();
}
}
You need to do this way
runOnUiThread(new Runnable() {
public void run() {
// Do Your Stuff
}});
Dismiss your dialog like this:
Handler handler = new Handler();
handler.post(new Runnable(){
public void run(){
progressDialog.dismiss();
}
});
Create a UI thread after completing network operation
runOnUiThread(new Runnable() {
#Override
public void run() {
progressDialog.dismiss();
}
});
The top answer works great, so here is an example to implement an AsyncTask in MonoDroid (thanks to Greg Shackels): http://mono-for-android.1047100.n5.nabble.com/AsyncTask-td4346647.html