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).
Related
I have problem when implementing AsyncTask. I have to rotate my phone in order to get a recent information. Below is my class:
GamerObject gamer;
….
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ip = "134.188.204.155";
// Set the name of the gamer
gamername = (TextView) findViewById(R.id.gamer_name);
// Set the gamerstatus:
gamerstatus = (TextView) findViewById(R.id.tvgamer_status_msg);
// set the job status
jobstatus = (TextView) findViewById(R.id.tvJob_status_msg);
new Operation().execute();
}
private class Operation extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
gamer= new GamerObject(ip);
gamer.UpdateAllData();
}
#Override
protected void onPostExecute(Void result) {
updateUI();
}
}
private void updateUI() {
gamer.updateAllData();
// Set the name of the gamer
TextView gamername = (TextView) findViewById(R.id.gamer_name );
gamername.setText(gamer.gamername);
gamername = gamer.gamername ;
// Set the gamer status:
…
// set the job status
…
}
Before I was using a Intent for Refresh the Interface, but now I want to try using AsyncTask so that it can compatible with Android version 4. Anybody knows how to get the information updated without rotating the phone ?
EDIT:
If I'm not wrong, Why my UI didn't refresh if there is new value, it is because new Operation().execute(); only use once in onCreate. AsyncTask will be executed if onCreate has been called, which means every time I rotate my phone, it will go to onCreate . Anybody knows how to keep the AsyncTask executed?
AsyncTask will only be executed once, so whenever system calls onCreate on your activity dueto some lifecycle event, asyncTask will be executed.
One, simple but naive approach, would be to create a new Thread and use Handler to update your UI. Some more information can be found eg. here and of course in Android doc.
Better approach, but more complicated would be to use Loader and LoaderCallback along with ContentProvider as #metter mentioned. This will require implementing you own ContentProvider and force you to add more "abstraction layers" to your app but will allow to separate network base code and ui code.
So this is as always tough decision to make either use "simple" but ugle solution with threads or "harder" but elegant solution with ContentProvier
I want to get the inofrmation updated automatically without have to rotating the phone.
Doing that requires some more work. Unfortunately, we can't see what your Async task actually does. If it is reading data from a database and you wan't your UI to be informed about any changes to the database, then your content resolver could call it's notifyChange and your Activity would listen to these changes and then call the async task again. For that, you would use a Content Observer. However, if your task is downloading data from the web, then there are two methods to get informed if the data online changed. One is called polling and means that you periodically connect and check the server. You should never do that on a mobile device due to limitations in battery, performance and data traffic. The other is called pushing and requires you to set up some infrastructure.
I hope that helps you.
I am using this following code for getting all songs stored in the sdcard.
https://stackoverflow.com/a/12227047/2714061
Well why does this code take so long to return this list of songs.
I have included this code in a function which is called from the oncreate method in my player's playlist.
This is what happens.
1: When the application runs is executed for the first time on my android ph, the playlist has nothing to show, and hence is seen empty.
2: Well after for instance-> 30sec when I again call for the playlist it returns instantly all the songs.
Hence, giving the feel as though this thing takes time to execute?
Why does this happen?
How about using an asynchronous task, reading a file or downloading something, takes time that requires the user to wait, you must think of using an Asynchronous task for this purpose,
1: From the developer reference we have :
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers. http://developer.android.com/reference/android/os/AsyncTask.html
An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.
2: So you may include an Async task class as:
class DoBackgroundTask extends AsyncTask<URL, Void, ArrayList> {
/*
URL is the file directory or URL to be fetched, remember we can pass an array of URLs,
Void is simple void for the progress parameter, you may change it to Integer or Double if you also want to do something on progress,
Arraylist is the type of object returned by doInBackground() method.
*/
#Override
protected ArrayList doInBackground(URL... url) {
//Do your background work here
//i.e. fetch your file list here
return fileList; // return your fileList as an ArrayList
}
protected void onPostExecute(ArrayList result) {
//Do updates on GUI here
//i.e. fetch your file list from result and show on GUI
}
#Override
protected void onProgressUpdate(Integer... values) {
// Do something on progress update
}
}
//Meanwhile, you may show a progressbar while the files load, or are fetched.
This AsyncTask can be called from you onCreate method by calling its execute method and passing the arguments to it:
new DoBackgroundTask().execute(URL);
3: And at last, there is also a very nice tutorial about AsyncTasks here, http://www.vogella.com/articles/AndroidBackgroundProcessing/article.html
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.
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.
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)