How to let Asynctask update UI in different ways - android

This is a problem that I keep running into often with using Asyntask. The way to contact the UI thread is to call publishProgress() & this method accepts an array of only one TYPE of parameter.
A thread running in the background doing complicated computations might need to update the UI at different points using different types of object.
Let me illustrate with an example:
...do some processing...
// Send UI thread the integer values of the width & height of the image
...do some more processing...
// Send UI thread a String with custom message.
...do some more processing...
// Send UI thread an instance of MyObject so it can extract & display certain values
...do some cleanup job & finish...
However, onProgressUpdate() accepts an array of only one type.
So do I make that an all encompassing Object type? How do I know how to downcast it since this method can be called from line 1, 2 or 3 so which time is it?
Surely there must be a good way to achieve this?
EDIT: What I'd really love to see, if it were possible in Android, would be some way of defining publishProgress1(user-defined args1), publishProgress2(user-defined args2), publishProgress3(user-defined args3) ...

In your 3rd case...
// Send UI thread an instance of MyObject
...there's an argument to say you would do this in onPostExecute() although that depends on what you meant from your illustration.
You could easily do as you suggest in passing an all encompassing object. The object could have various fields (integer, string, object) plus an 'action' to take describing which of those fields are valid and need to be processed.
You could simply pass an int enum such as PROCESS_INT_WIDTH_AND_HEIGHT, PROCESS_STRING_MESSAGE, PROCESS_OBJECT etc. There's nothing to stop you doing this...
private static class MyAsyncTask extends AsyncTask<String, int, Void> {
private int width;
private int height;
private String customMessage;
private MyObject myObject;
#Override
protected Void doInBackground(String... params) {
width = 10;
height = 10;
publishProgress(PROCESS_INT_WIDTH_AND_HEIGHT);
}
protected void onProgressUpdate(int... progress) {
if (progress == PROCESS_INT_WIDTH_AND_HEIGHT)
// Process width and height
}
}
In other words, the onProgressUpdate() method simply responds to a 'command' and processes the relevant private fields accordingly.

If you want to stick with AsyncTask, another option is use a different class at different times, and test the type with instanceof.
However, this sounds like a relatively complex task, so I'd suggest looking at using Handler and posting it [Runnable]s2 from a regular Thread, or using runOnUiThread.
You might also want to read Painless Threading
Hope this helps,
Phil Lello

I don't think there is any other way of doing this. Create a base class with a getType method and then use this as your type for appropriate casting.

Would a generic type work in this scenario? You could typecast the values as needed. Example AsyncTask prototype:
new AsyncTask<String, Object, List<?>>(){
...
I also recall reading that AsyncTask is most suited only for short tasks. Consider the other thread models for complex and long-running operations.

If the values you're returning have a corresponding state in the AsyncTask processing, you could create a private member inside the AsyncTask for each datum/type you need, then assign an integer to each state and in onProgressUpdate(Integer...) put a switch(state) that does the job based on the int state it gets from publishProgress(state).
(this might not be the clearest answer I gave)

Related

What is the purpose of adding parameters to an AsyncTask?

Sorry for being a newbie, I've looked everywhere and I just don't get it.
Asynctask needs 3 parameters; e.g.
but what is the point of these parameters?
I am trying to run a geocoder in a separate thread and I have this
private class GetCurrentCity extends AsyncTask<String, Void, Void>{
but I literally made those parameters up. I have no idea what I'm supposed to put there. I don't need a progress bar or anything to be transferred to the other thread except for the line of code that is already in doInBackground() . Then I need a string to be returned from that, and I am using onPostExecute(String returnedAddress) for that.
I am confused. Help please!
From the doc of AsyncTask
The three types used by an asynchronous task are the following:
Params, the type of the parameters sent to the task upon execution.
Progress, the type of the progress units published during the
background computation.
Result, the type of the result of the background computation
Not all types are always used by an asynchronous task. To mark a type as unused, simply use the type Void:
private class MyTask extends AsyncTask<Void, Void, Void> { ... }
Rather than an API reference, here's a little more description. First, many people will use an AsyncTask inline as an anonymous class; keep that in mind. It looks like you've extended it with your own class (which is totally fine), but it likely means you're passing the necessary data in the constructor and referencing it as class variables. In that case, some of the arguments won't make as much sense.
So picture an anonymous inline class of AsyncTask. The first thing it's going to do is run some processing in the background. To do that, you need a way to pass data to the doInBackground method (because you don't have a constructor to call and pass it data). So the first argument is the type of data you're going to pass to it. If you don't have to pass anything, use Void, or use Object, or anything at all, really, because it has to be part of the method signature but you'd ignore it anyway.
For many situations, one will want to provide progress updates. For example, you might use the Float type to represent percent complete, or Long to represent bytes read from a file, or String for general messages to a user. You use the progress type to pass out interim progress information (think of uploading a file to facebook or downloading a file, where it updates the notification status with the progress - this is where/how you'd do that). You've said you don't care about it in your case, so use Void and don't bother implementing any progress methods.
Finally, when the task completes, you need to get to the result in the onPostExecute. So your doInBackground will return a value (of this type) and the AsyncTask framework will pass it to onPostExecute. Again, this makes more sense for an anonymous class with no further body. If you'd hold any results in a class member, that's fine also (but unnecessary). If you don't need to do anything on complete, or don't need to pass any data, use Void (and return null from doInBackground). I find it's useful at the least to return a Boolean for "completed successfully or failed," so you have that information (which might influence whether you post a success or failure notification, as notification of task complete is a common onPostExecute operation).
Hope some more explanation with examples helps.
Those are for when you want to pass something to it at time of execution or passing between runInBackground and onPostExecute. You can simply make all three Void in class declaration.
AsyncTask | Android Developers
The three types used by an asynchronous task are the following:
Params, the type of the parameters sent to the task upon execution.
Progress, the type of the progress units published during the
background computation.
Result, the type of the result of the background computation.
Not all types are always used by an asynchronous task. To mark a type as unused, simply use the type Void:
private class MyTask extends AsyncTask<Void, Void, Void> { ... }

How to set value to TextView from class which is out of activity?

How to set value to TextView from class which is out of activity? The value we get at an undetermined time, so it is important to set the value from that class.
All advice would be helpful. Thank you.
P.S.:
For example, in Actvity I have method, which sets the value to a TextView.
public void textViewSetText (String value){
tv.setText(value);
} //how correctly to transfer value from my class to get the desired effect?
If you dont have hold of your Activity, then its not possible because TextView is available in Activity. So when you dont have reference to activity, you cant alter it's contents too. In case you pass your activity reference to a static method, then its possible for that method to do the modifications.
Normally, the content of TextView should only be set inside a activity. Though you can set that value outside of the activity, it is not quite useful.
As for your question, you got the value at an undetermined time, there are some choices.For example, you can register a callback to that class, and when the other class got that value, you can send a message through that callback. But be careful about the threading problem, setting a value to a TextView is a UI operation, which should only be done in a UI thread.
Do not access the Android UI toolkit from outside the UI thread
AsyncTask allows you to perform asynchronous work on your user interface. It performs the blocking operations in a worker thread and then publishes the results on the UI thread, without requiring you to handle threads and/or handlers yourself.
Here is an example:
public void onClick(View v) {
new SomeTask().execute(something);
}
private class SomeTask extends AsyncTask<Something, Void, String> {
/** The system calls this to perform work in a worker thread and
* delivers it the parameters given to AsyncTask.execute() */
protected Bitmap doInBackground(Something something) {
return string; // the TextView's text
}
/** The system calls this to perform work in the UI thread and delivers
* the result from doInBackground() */
protected void onPostExecute(String result) {
textView.setText(result);
}
}
However, if you don't give your case more detailed, no exact answer may satisfy you.
You can use an external Static Class to save the value of the String to modify (and set the value once you return to your TextView_Class), only access to the Static Class to get the value.
You may also save the "this" (Activity) in the Static Class and access to that Activity from everywhere, so you can modify the TextView. (I don't thinks this would be recommended).
Depending the case (you didnt explained enought), the normal thing to do is to Bundle the String if they're parent-child classes.
I m not sure about your question but
try like this may be it will work
((MainActivity) activity).textViewSetText();
public void textViewSetText (String value){
tv.setText(value);
}
but your activity have to extends The MainActivity.

Android Context Passing on doInBackground

I sent "Scores Activity" to doinbackground then run a function on Scores Activity but getting
"Only the original thread that created a view hierarchy can touch its views." on "birinci.setText(txt);" line.
what am I missing here looks using same context?
Scores Activity
{
Object[] stuff = {this.dhn, Scores.this};
ConnectXML runXML = new ConnectXML();
runXML.execute(stuff);
}
public void setScoreListUpdate(String txt)
{
birinci.setText(txt);
}
private Scores myScores;
protected String doInBackground(Object... arguments) {
myScores = (Scores)stuff[1];
myScores.setScoreListUpdate(result);
}
The error message already gives the answer: you can't touch (edit/modify/update/etc.) any views from a thread that did not create them. Since anything that is executed in the doInBackgrund(...) of an AsyncTask is done by a separate thread, you can't do any direct view manipulations in there.
The solution is quite simple: override the other methods an AsyncTask provides, depending on your needs. If you're trying to update a view after all work is done, simply override onPostExecute(...). If you want to indicate some sort of progress while the work is being done in the background, use onProgressUpdate(...). Everything in there is being executed by the main UI thread (which created all views).
Please have read through the documentation on AsyncTask, since that describes the different steps and possibilities quite clearly.

What arguments are passed into AsyncTask<arg1, arg2, arg3>?

I don't understand what I am supposed to put in here and where these arguments end up? What exactly should I put, and where exactly will it go? Do I need to include all 3 or can I include 1,2,20?
Google's Android Documentation Says that :
An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.
AsyncTask's generic types :
The three types used by an asynchronous task are the following:
Params, the type of the parameters sent to the task upon execution.
Progress, the type of the progress units published during the background computation.
Result, the type of the result of the background computation.
Not all types are always used by an asynchronous task. To mark a type as unused, simply use the type Void:
private class MyTask extends AsyncTask<Void, Void, Void> { ... }
You Can further refer : http://developer.android.com/reference/android/os/AsyncTask.html
Or You Can clear whats the role of AsyncTask by refering Sankar-Ganesh's Blog
Well The structure of a typical AsyncTask class goes like :
private class MyTask extends AsyncTask<X, Y, Z>
protected void onPreExecute(){
}
This method is executed before starting the new Thread. There is no input/output values, so just initialize variables or whatever you think you need to do.
protected Z doInBackground(X...x){
}
The most important method in the AsyncTask class. You have to place here all the stuff you want to do in the background, in a different thread from the main one. Here we have as an input value an array of objects from the type “X” (Do you see in the header? We have “...extends AsyncTask” These are the TYPES of the input parameters) and returns an object from the type “Z”.
protected void onProgressUpdate(Y y){
}
This method is called using the method publishProgress(y) and it is usually used when you want to show any progress or information in the main screen, like a progress bar showing the progress of the operation you are doing in the background.
protected void onPostExecute(Z z){
}
This method is called after the operation in the background is done. As an input parameter you will receive the output parameter of the doInBackground method.
What about the X, Y and Z types?
As you can deduce from the above structure:
X – The type of the input variables value you want to set to the background process. This can be an array of objects.
Y – The type of the objects you are going to enter in the onProgressUpdate method.
Z – The type of the result from the operations you have done in the background process.
How do we call this task from an outside class? Just with the following two lines:
MyTask myTask = new MyTask();
myTask.execute(x);
Where x is the input parameter of the type X.
Once we have our task running, we can find out its status from “outside”. Using the “getStatus()” method.
myTask.getStatus();
and we can receive the following status:
RUNNING - Indicates that the task is running.
PENDING - Indicates that the task has not been executed yet.
FINISHED - Indicates that onPostExecute(Z) has finished.
Hints about using AsyncTask
Do not call the methods onPreExecute, doInBackground and onPostExecute manually. This is automatically done by the system.
You cannot call an AsyncTask inside another AsyncTask or Thread. The call of the method execute must be done in the UI Thread.
The method onPostExecute is executed in the UI Thread (here you can call another AsyncTask!).
The input parameters of the task can be an Object array, this way you can put whatever objects and types you want.
I'm too late to the party but thought this might help someone.
Keep it simple!
An AsyncTask is background task which runs in the background thread. It takes an Input, performs Progress and gives Output.
ie AsyncTask<Input,Progress,Output>.
In my opinion the main source of confusion comes when we try to memorize the parameters in the AsyncTask.
The key is Don't memorize.
If you can visualize what your task really needs to do then writing the AsyncTask with the correct signature would be a piece of cake.
Just figure out what your Input, Progress and Output are and you will be good to go.
For example:
Heart of the AsyncTask!
doInBackgound() method is the most important method in an AsyncTask because
Only this method runs in the background thread and publish data to UI thread.
Its signature changes with the AsyncTask parameters.
So lets see the relationship
doInBackground() and onPostExecute(),onProgressUpdate() are also related
Show me the code
So how will I write the code for DownloadTask?
DownloadTask extends AsyncTask<String,Integer,String>{
#Override
public void onPreExecute()
{}
#Override
public String doInbackGround(String... params)
{
// Download code
int downloadPerc = // calculate that
publish(downloadPerc);
return "Download Success";
}
#Override
public void onPostExecute(String result)
{
super.onPostExecute(result);
}
#Override
public void onProgressUpdate(Integer... params)
{
// show in spinner, access UI elements
}
}
How will you run this Task
new DownLoadTask().execute("Paradise.mp3");
Refer to following links:
http://developer.android.com/reference/android/os/AsyncTask.html
http://labs.makemachine.net/2010/05/android-asynctask-example/
You cannot pass more than three arguments, if you want to pass only 1 argument then use void for the other two arguments.
1. private class DownloadFilesTask extends AsyncTask<URL, Integer, Long>
2. protected class InitTask extends AsyncTask<Context, Integer, Integer>
An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.
in Short, There are 3 parameters in AsyncTask
parameters for Input use in DoInBackground(String... params)
parameters for show status of progress use in OnProgressUpdate(String... status)
parameters for result use in OnPostExcute(String... result)
Note : - [Type of parameters can vary depending on your requirement]

Need help with AsyncTasks - Android Application

Hey, I have an application which logs onto a few sites using defaulthttpclient and I've found I'm going to need to use the AsyncTask as the requests hold up the UI thread. In my code, I create an instance of a state class i.e. State state = new O2State(); with different states for different sites.
I then call state.logon(String username, String password); which returns a string containing details of the result so:
String result = state.logon(username, password);
I've been trying to implement asynctasks to run this code in another thread and return the string back to the UI thread on completion. The idea is I will display a progress dialog, run the thread, and on complete, will display a dialog with the result.
I've been looking at this example:
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask {
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}
Where I'm stuck is:
I don't think I'll need any arguments, but doinbackground seems to require a list of parameters. I'm also unfamiliar with this time of method argument declaration.
Secondly:
I'm not sure how to return the resulting string when the thread is finished executing. Should I just create a "DoThisWhenTheThreadIsFinished(String result)" and call this from onPostExecute?
Anyway, I hope this isn't too confusing to read and I'd really appreciate any help you can offer.
Thanks
Where you don't need parameters just specify the type (e.g. String) and ignore it, or you could use the Void class (note the capital V).
What you suggest for how to return control back to the UI thread to reflect the update is a good approach. i.e. in onPostExecute() call a method on the activity to update the UI.
As a general rule if any operations will take more than a couple of hundred milliseconds, use a separate thread. You may also want to use a rotating progress indicator to show the app is doing something.
(when people answer your questions, always rate the ones you like, and pick one as the "best" answer. you get points doing this, and it helps others later).

Categories

Resources