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.
Related
I currently have a thread/AsyncTask that I start in Activity A. Before that AsyncTask is started though, Activity A makes an object which takes in Activity A's Context so it can instantiate a NotificationCompat.Builder. The object uses this builder to make/show a notification.
This object is then passed to the AsyncTask as the AsyncTask is created and started. This allows the AsyncTask to update the object (and the notification) with its progress.
Once the AsyncTask has been started though, Activity A calls finish(), and the activity that started it, Activity B, resumes. What I would now like to happen is to have the object send/attempt to send a message to Activity B once the AsyncTask has said it is 100% complete. How can I achieve this?
PS: let me know if a picture would make the scenario more clear.
As far as I have understood your question Activity A is started from Activity B. You can start A from B via startActivityForResult then rather finishing A when AsyncTask starts you finish() A when 100% task is loaded by AsyncTask and send result to A. You can implement callback interface to send result to Activity A from AsyncTask. Now call finish() to Activity A with setResult() and pass the result in intent to Activity B.
You can use the onPostExecute() method of the AsyncTask.
private class DownloadFilesTask extends AsyncTask<Void, Void, MyObject> {
protected Void doInBackground(Void... params) {
//do whatever you need to do
}
protected void onPostExecute(MyObject myObject) {
myObject.sendMessage(activityB);
}
}
Note that onPostExecute() runs on the main UI thread, so it will be able to handle UI updates.
Typing up my own answer both because it was the result of discussion that happened in the comments of my question, and so there is a thorough overview of what I did for a solution.
I ended up going with callbacks as suggested by rusted brain. It is important to note that I am referring to the use of android.os.Handler to create a callback, not the callback pattern that is commonly used with things such as buttons. Anyway, onto the solution.
Step 1 was to set up a handler in Activity B:
messageHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
refreshList();
}
};
Whatever is in handleMessage is what will be called when a message is sent to the handler.
Step 2 is to send a android.os.Messenger object to Activity A. This can easily be done with the Intentused to start Activity A:
Intent intent = new Intent(AlbumGalleryActivity.this, CreateNewPhotoHuntActivity.class);
intent.putExtra("callbackMessenger", new Messenger(messageHandler));
startActivityForResult(intent, Constants.REQUEST_CREATE_NEW_PHOTO_HUNT);
Now, any messages sent by the android.os.Messenger will go to our android.os.Handler.
Step 3, the final step is to create a android.os.Message from the android.os.Messenger which can be sent back to the handler. In the context of my question, this is done inside of the object that controls updating the progress of the notification:
if(totalProgress >= 100) {
notificationBuilder.setContentText("Upload complete! ");
notificationBuilder.setSmallIcon(R.drawable.ic_done_black_24dp);
notificationBuilder.setProgress(0, 0, false);
notificationManager.notify(1, notificationBuilder.build());
Message msg = Message.obtain();
msg.arg1 = 1;
try {
callbackMessenger.send(msg);
}
catch (android.os.RemoteException e1) {
Log.d(Constants.UploadProgressNotificationTag, e1.toString());
}
}
So yep that's it. Feel free to comment if you have a Q or if you see a mistake in what I've posted. Also, I think using Broadcasts would also solve this issue, but that would require a bit more time/effort to implement. Thank you to everyone who suggested a solution!
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.
I have an Android Service that does some background processing on an image using a separate Thread. If an error occurs in this Service or even worse in the thread, what is the best practice to inform the launching Activity of the problem and allow the application to recover to a stable state (i.e. the state it was in before launching the service).
From within the Service I could post a Toast or a Notification, but that doesn't help me. I would like to inform the user about the problem but at the same time recover the application to a stable state.
In case anyone searches for this I will explain what I ended up doing.
Inside the service I added a private class that extends AsyncTask. This is were all the processing is done.
In this class I have a private variable 'exception'. The content of the doInBackground method is surrounded by a try/catch and any exception catched is stored in 'exception'. In the onPostExecute method I check if 'exception' is set and if that is the case I send a broadcast PROCESSING_ERROR with the exception details so that the calling Activity will be informed.
If you don't know what AsyncTask, doInBackground or onPostExecute are you should read following:
http://developer.android.com/guide/components/processes-and-threads.html#AsyncTask
http://developer.android.com/reference/android/os/AsyncTask.html
You can use a Messenger to pass information between the service and main application.
Define a messenger in your main activity, as follow:
private Messenger = mMessengerCliente = new Messenger(new IncomingHandler());
/**
* Handler of incoming messages from service.
*/
private class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_1:
//actions to perform on message type 1
break;
case MSG_2:
//actions to perform on message type 2
break;
default:
super.handleMessage(msg);
}
}
}
Pass the Messenger object as a Extra or when binding to your service.
In your service, recover the Messenger object and use it to communicate back:
mMsgClientMain = (Messenger)intent.getExtras().get(EXTRA_MESSENGER);
Message msg = Message.obtain(null, MSG_1, arg1, arg2);
msg.replyTo=reply_to; // if you need to have bidirectional communication, pass here the service messenger object
mMsgClientMain.send(msg);
Regards.
What i am trying to do over here is that I want to call a webservice and based on its response i might invoke another webservice or start an activity.I am already writing the web service in a separate thread but the issue is that i am calling the activity in a worker thread,
To make myself more clear i have put my pseudo code.
if (User ID and Password present in the shared preference) THEN
Utils.checkauthorisation(API) //Web Service Call
if(respsonse is Paswordexpired)
erase password from DB
Goto (LOGIN SCREEN)//startActivity Call
else if(download of images hasnt happened today)) THEN
UTILS.DownloadImages//Web service call
if(response==connectivityorOtherError)
Toast respective Message
GOTO (GALLERY SCREEN)//startActivity Call
else if (response==confilicted Data)
Goto (CHANGES SCREEN)//startActivity Call
endif
endif
endif
I was planning to show a progress bar and do all these events in a thread like this
progressDialog = ProgressDialog.show(this, "Loading",
"Authenticating Please wait.");
new Thread() {
public void run() {
///execute the pseudo code
startActivity(intent); //Is this a good practice
Message msg = Message.obtain();
msg.what = 1;
messagHandler.sendMessage(msg);
}
}.start();
private static Handler messagHandler = new Handler() {
public void handleMessage(Message message) {
super.handleMessage(message);
switch (message.what) {
case 1:
progressDialog.dismiss();
break;
default:
break;
}
}
};
But something that disturbs me is that I have to start an activity in a worker thread here. Is this good practice? I initially thought that we could only start an activity from the UI thread. What is the process happening in the back end here(in the thread sense)? If this is not a good practice what are the other alternatives to implement my pseudocode?
P.S.:Sorry about asking this question again.I had asked the same question earlier but had failed to convey what i wanted exactly so had received answers for alternatives to starting activity on worker thread(part of my question) but didn't recieve any answer on "is this a good practice"
Thanks
I can't fully understand where you're starting the activity, but assuming it's in the "GOTO" lines of your pseudo-code, I would advise you to set the msg.what with different values for each activity you want to launch and then launch it on the handleMessage(Message).
This is assumes that the Handler is created in the UI thread. If it's not, you shouldn't dismiss the ProgressDialog as well since both things should be done from the UI thread. Create one on the UI thread and get it there.
I'm running an activity, which has to download a fairly large image from the Internet, and then display it. This works: the download is done via an AsyncTask, and a progress dialog is shown. And when the download is finished, the activity showing the image is called.
The problem I have is that the real work is done in an external class. This as other activities call the same routine to fetch an image. So I can not immediately call postUpdate() to set the update as this call would be done in another class. Now I wonder how I can get the progress updates back to my AsyncTask so my progress dialog can show the actual progress made
The AsyncTask subclass currently looks like this:
private class StartShowImage extends AsyncTask<String, Integer, String> {
private ProgressDialog dialog;
#Override
protected void onPreExecute() {
// Toon een dialog met draaiend wiel terwijl we de foto
// aan het ophalen zijn.
dialog = new ProgressDialog(ShowDeaddrop.this);
dialog.setTitle(R.string.progress_dialog_title);
dialog.setMessage(getResources().getString(
R.string.progress_dialog_fetching_image));
dialog.show();
}
/**
* De hoofdroutine; haalt de foto op.
*/
#Override
protected String doInBackground(final String... params) {
final String imageName = params[0];
String result = null;
try {
result = DeaddropUtil.getImage(context, imageName, ""
+ deaddropID, true);
} catch (final IOException e) {
Log.v(TAG, "Failed to download image " + imageName);
Log.v(TAG, "" + e);
}
return result;
}
/**
* Als we de foto hebben, start ShowImage.
*/
#Override
protected void onPostExecute(final String imageName) {
dialog.dismiss();
if (isActive)
if (imageName == null)
Toast.makeText(context, R.string.toast_show_image_failed,
Toast.LENGTH_SHORT).show();
else {
final Intent i = new Intent(ShowDeaddrop.this,
ShowImage.class);
i.putExtra("imageName", imageName);
startActivityForResult(i, SHOW_IMAGE);
}
}
}
isActive is a boolean that keeps track of whether this activity is active - it's set in onCreate and onResume and unset in onPause.
I've been looking into a broadcast intent - I've seen an example on how to send back such an intent to the main activity, but the problem is that the listener has to be registered/unregstered in onResume/onPause - and AsyncTask is a separate thread. So it seems this method can not be used safely that way.
Edit restating the question, hoping to get answers that address my question.
AsyncTask sets up progress dialog.
The onExecute() thread can directly update the progress dialog. No problem there.
The actual work is done in an external class, so the progress information is known by that external class, which has to communicate it back to the AsyncTask one way or another.
AsyncTask will have to have some kind of listener, or handler, or something that the external class can call back to, in order to give progress updates.
The question is: how to perform this last part of the process? What is a suitable listener? How to implement such a listener? Which thread does the listener end up in - the UI thread like .onPreExecute() and .onPostExecute(), or the work thread from .doInBackground()?
Solved by using a BroadcastIntent.
Main activity creates BroadcastReceiver, IntentFilter and progress dialog; AsyncTask registers/unregisters this receiver and shows/dismisses the dialog in onPreExecute/onPostExecute respectively.
With extra bits in onResume and onPause to not have active receivers when the activity itself is inactive.
It took me a while to understand this intent broadcast, but after that it was a very quick and easy implementation.
If I understand correctly you are wanting to update the progress bar from the async task. I would probably look at the onProgressUpdate of async task. http://developer.android.com/reference/android/os/AsyncTask.html
Your class StartShowImage doesn't have member. This object you have used to create toast also. if you make member Activity and construction declaration for it you can initialize it by constructor like this before you call it's public method which you want to do :
private Activity context;
public StartShowImage(Activity context){
this.context=context;
}
StartShowImage object=new StartShowImage(this)
object.postUpdate();
This should work and your calling class should extent Activity