I have a service that I have started from MainActivity with:
Intent intent = new Intent(getBaseContext(), MyService.class);
getBaseContext().startService(intent);
Inside MyService, I create and start a thread, giving it a reference to the Service's Context:
mThread = new MyThread(this);
mThread.start();
Then inside the thread, I want to display a ProgressDialog. I tried this:
mProgressDialog = ProgressDialog.show(mContext,
"", "Receiving file...", true);
mProgressDialog.show();
but I get "RuntimeException: Can't create handler inside thread that has not called Looper.prepare()". This makes sense, so I tried this instead:
HandlerThread progressHandlerThread = new HandlerThread(
"ProgressHandlerThread");
progressHandlerThread.start();
Handler progressHandler = new Handler(
progressHandlerThread.getLooper());
progressHandler.post(new Runnable()
{
#Override
public void run()
{
mProgressDialog = ProgressDialog.show(mContext, "",
"Receiving file...", true);
mProgressDialog.show();
}
});
but I get "BadTokenException: Unable to add window token is not for an application" but I don't understand what that error means.
I have seen this: Show ProgressDialog from thread inside the Service
and the conclusion seems to be that I need to runOnUIThread, but I don't have a reference to an Activity to do that since I am in a Service. Can anyone explain this BadTokenException and suggest a good way to do this?
I think the fact that you're trying to directly manipulate UI from a Service means that You're Doing It Wrong™
Services don't have a UI, and therefore should never directly influence UI. Instead, you should pipe an event from your Service to a listening Activity or Fragment, for instance.
Take a look a https://github.com/square/otto for some extremely flexible and saucy event bussing.
edit) Take a look at the comments below for what the dirty solution was to David's problem.
Not much idea about badTokenException , but I can suggest you to use AsyncTask to solve this kind of problem. You can start the progressdialog in preExecute() method and dismiss it in postExecute() method because these both are running on UI thread.
I just implemented this from a thread here. Please read Rachit Mishra's answer further down the page talking about a ProgressBar:
Communication between Activity and Service
I have this in my service:
public void sendMessage(int state) {
Message message = Message.obtain();
switch (state) {
case 1://SHOW:
message.arg1 = 1;
break;
case 0:
message.arg1 = 0;
break;
}
try {
messageHandler.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
Call sendMessage() with 1 or 0 to show or dismiss the ProgressDialog within your service.
And this is in my Main Activity:
private ProgressDialog progress;
public class MessageHandler extends Handler {
#Override
public void handleMessage(Message message) {
int state = message.arg1;
switch (state) {
case 0://HIDE
progress.dismiss();
break;
case 1://SHOW
progress = ProgressDialog.show(MainActivity.this, (getResources().getString(R.string.CONNECTING) + "..."), (getResources().getString(R.string.PLEASE_WAIT) + "!")); //show a progress dialog
break;
}
}
}
The ProgressDialog cannot be shown from the service, it must be called from the activity or fragment. I hope I added all the code you need and that it works well for your needs. To be honest I'm not sure how the message handler works but it works for me! The naming is probably not the best either lol. Sorry.
Related
In OnResume(), I make web service call in thread here i used progress bar for indicating the process it works fine but suppose i uses the app after sometime i put the device idle after that open the app once again this time progress bar is not dismissed.It's not regularly happens sometimes it happens. Why?
How can i make it to away from this? If you need more info plz let me know.
Code :
Edit:
public void onResume()
{
super.onResume();
pdMessages = ProgressDialog.show(getParent(), "", "Please wait...", true);
Thread thImportbtn = new Thread()
{
public void run()
{
try
{
//Get internal messages
strInternalInboxWSR = GetInternalInboxMessages();
} catch (SoapFault e) {
e.printStackTrace();
}
dh_Messages_Handler.post(checked_internalinbox_response);
handler.sendMessage(handler.obtainMessage());
}
};
thImportbtn.start();
}
private Handler handler = new Handler()
{
#Override
public void handleMessage ( Message message )
{
pdMessages.dismiss();
}
};
You can use Handler Class to dismiss your ProgressDialog, like below
private Handler handler = new Handler()
{
#Override
public void handleMessage ( Message message )
{
progressDialog.dismiss();
}
};
you can use following statement to call Handler class,
handler.sendMessage(handler.obtainMessage());
You are Trying To Dismiss ProgressDialog in Non-UI Thread, So can't Dismiss proper.
you should put your dismiss code( pdMessages.dismiss();) in Handler Using Overriding handleMessage method
Use AsyncTask is better.
I have a Service with registered ContentObserver. When my ContentObserver detects changes it sets Service's boolean variable to true. I also have a Thread running in the service which sleeps for some time and wakes up to check that variable.
When it detects change it needs some time to process some other code and I need to show ProgressDialog during the delay. How can I do this?
You should use AsyncTask instead.
Here is the link to the library. It is fairly simple:
1) onPreExecute() = show ProgressDialog
2) doInBackground() = execute your code
3) onPostExecute() = dismiss ProgressDialog
DONE :-)
The essence of your question is that you want your service to send a message of some kind to your UI (to show a loading dialog).
There are four (or more) ways of going about this:
Intents: have your service send an intent to your activity
AIDL
Using the service object itself (as singleton)
Having your activity be a broadcast receiver
These options may seem familiar: How to have Android Service communicate with Activity
You'll have to read up on those options and take your pick.
AsyncTask is a good alternative, but still if you decided to go with threads, then in order to show the ProgressDialog on UI you will need to call runOnUiThread() method of the activity.
Let suppose you want to display the ProgressDialog in the MainActivity. Inside your Thread from Service you should have something like this:
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// Display ProgressDialog here
}
});
Thanks everyone for answers.
I solve the problem using these steps
- broadcast Intent when my variable was changed
- create BroadcastReceiver for the intent( in Activity )
- inside BroadcastReceiver's method onReceive call runOnUiThread for my activity
I know this is an old thread but I have exactly what you needed because I just implemented this from a thread here. Please read Rachit Mishra's answer further down the page talking about a ProgressBar:
Communication between Activity and Service
I have this in my service:
public void sendMessage(int state) {
Message message = Message.obtain();
switch (state) {
case 1://SHOW:
message.arg1 = 1;
break;
case 0:
message.arg1 = 0;
break;
}
try {
messageHandler.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
Call sendMessage() with 1 or 0 to show or dismiss the ProgressDialog within your service.
And this is in my Main Activity:
private ProgressDialog progress;
public class MessageHandler extends Handler {
#Override
public void handleMessage(Message message) {
int state = message.arg1;
switch (state) {
case 0://HIDE
progress.dismiss();
break;
case 1://SHOW
progress = ProgressDialog.show(MainActivity.this, (getResources().getString(R.string.CONNECTING) + "..."), (getResources().getString(R.string.PLEASE_WAIT) + "!")); //show a progress dialog
break;
}
}
}
The ProgressDialog cannot be shown from the service, it must be called from the activity or fragment. I hope I added all the code you need and that it works well for your needs. To be honest I'm not sure how the message handler works but it works for me! The naming is probably not the best either lol. Sorry.
How to show Dialog in onCreate method ? Is that possible at all, I tried but I got leaked window exception. Can anyone suggest me anything ?
you can use ProgressDialog Class with the Help of Handler Class. This way you can achieve what you want to do.
progDailog = ProgressDialog.show(loginAct,"Process ", "please wait....",true,true);
new Thread ( new Runnable()
{
public void run()
{
// your loading code goes here
}
}).start();
Handler progressHandler = new Handler()
{
public void handleMessage(Message msg1)
{
progDailog.dismiss();
}
}
I am sure that you might be using a bad context there. To show the Dialog on the UI(specific) Activity don't use getApplicationContext() or getBaseContext(). Just create the instance using Activity_Name.this and you will be able to show the Dialog.
There are a number of questions involving the lack of ability to dismiss a ProgressDialog, but none of them seem to cover my situation.
I have a Thread that runs a Runnable object that, when it completes, sends a message to a Handler object which I'm certain is sitting on the same thread as the ProgressDialog. The handler does this:
if(progressDialog != null){
Log.w(TAG, "Progress dialog is dismissed");
progressDialog.dismiss();
}else{
Log.w(TAG, "Progress dialog is null");
}
I've done this a million times before, and it's worked. The ProgressDialog goes away. But, in one particular instance, it doesn't.
In this particular case, a ProgressDialog (we'll call uploadChangesDialog) is showing, then a particular Handler (uploadChangesHandler) is called. After dismissing the uploadChangesDialog, it does a check that, if true, starts a different ProgressDialog (refreshViewDialog) and a Runnable (refreshViewRunnable) in a Thread. However, when it's Handler is called (refreshViewHandler), it can't close the dialog. But it does log Progress dialog is dismissed.
This is particularly strange, because the refreshViewsRunnable is run when the Activity is started, too, but it can get rid of the dialog then, just fine. The progressDialog variable above is the only one of it's kind, which is supposed to hold whatever ProgressDialog is currently showing.
I've done this with AlertDialogs before, but they know how to close themselves, so if I'm doing something wrong, then I wouldn't have noticed.
In the onCreateDialog() method:
case DIALOG_REFRESH_VIEW:
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Loading details...");
progressDialog.setCancelable(false);
return progressDialog;
Copied for each instance, with a different message. I did change it to all dialogs pointing to the same code, and setting the message in onPrepareDialog(), but that didn't change any behaviour.
In the UploadChangesRunnable:
public void run(){
int result = 0;
if(uploadChanges()){
result = 1;
}
uploadChangesHandler.sendEmptyMessage(result);
}
And then in uploadChangesHandler:
public void handleMessage(Message msg){
if(progressDialog != null){
progressDialog.dismiss();
}
if(msg.what == 0){
showDialog(DIALOG_UPLOAD_CHANGES_FAILED); //This is an AlertDialog
}else{
//All this does is showDialog(DIALOG_REFRESH_VIEW) then run the thread.
//This method is in the enclosing Activity class.
refreshViewInThread();
}
}
Finally, the refreshViewInThread method:
private void refreshViewInThread(){
showDialog(DIALOG_REFRESH_VIEW);
Thread thread = new Thread(new RefreshViewRunnable(refreshViewHandler));
thread.start();
}
And the RefreshViewRunnable looks remarkably similar to the UploadChangesRunnable.
There must be some special case that makes me lose the link to my progressDialog, and the dialog that I'm dismissing is likely not the dialog that is showing, but I can't think of how that could be. Any ideas?
my guess is that this is a context/handler issue. I had a similar problem, and decided to use interfaces/callbacks instead of Handler, and it fixed my problem.
However, you could try the following, where you see this: >> But it does log Progress dialog is dismissed.<< , add:
MyActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
progressDialog.dismiss();
}
});
when does the progress dialog not show in android? i want to know the circumstances when the above can happen:
in my case the progress dialog was not showing in this case:
func{
progressdialog.show();
....
.....
anotherfunction();
listview.setAdapter();
progressdialog.dismiss();
}
what is the general rule of thumb with dialog boxes?
thank you in advance.
EDIT
when the .show() command is executed the progress dialog should show. But when the otherfucntion() is called, does the previous command of progressdialog show stop?
Seems like you need to use AsyncTask the UI (including the progressDialog) will not update if the UI thread is still busy. There are many examples in SO for that.
And as a rule of thumb - if you need Progress dialog - you need AsyncTask.
It is not that any command stops, it is just that if you execute a sequence of methods on the UI thread, the UI will probably not be updated until the sequence is over, which is after progressDialog.dismiss(), so the progressDialog should not be displayed anymore.
I think You have to do this in your activity.
ProgressDialog _progressDialog = ProgressDialog.show(this,"Saving Data","Please wait......");
settintAdater();
private void settingAdater(){
Thread _thread = new Thread(){
public void run() {
Message _msg = new Message();
_msg.what = 1;
// Do your task where you want to rerieve data to set in adapet
YourCalss.this._handle.sendMessage(_msg);
};
};
_thread.start();
}
Handler _handle = new Handler(){
public void handleMessage(Message msg) {
switch(msg.what){
case 1:
_progressDialog.dismiss();
listview.setAdapter();
}
}
}
To show a ProgressDialog use
ProgressDialog progressDialog = ProgressDialog.show(PrintMain.this, "",
"Uploading Document. Please wait...", true);
And when you have completed your task use
progressDialog.dismiss();
to dismiss the ProgressDialog ..
You can call to show the ProgressDialog in your onPreExecute method of AsyncTask class and when your done dismiss it in the onPostExecute method