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.
Related
I also faced with the NetworkOnMainThreadException in my application but I don't see how to resolve it.
I have a class with a getter method. Like:
public ArrayList<News> get(int i){
// get the list of news from a HTML on the net. The news are split up into web pages on the site
// and i is the page number
return NewsParser(i);
}
Since Android throws the exception I come up with an idea of a downloader class which downloads the HTML content in a separate thread
pubic ArrayList<News> get(int i){
Downloader dl = new Downloader(i);
String HTMLcontent = dl.getContent(); <-- AsyncTask starts in getContent()
return NewsParser(HTMLcontent); <-- What happens here in the main thread???
}
Any ideas/best practices for this problem?
Just looking at your code and your question, it seems like you don't have a very solid understanding of how AsyncTask (or threads in general) works.
I would recommend reading this article.
Basically, your AsyncTask should query the web URL and download the data. Once the data is complete, your AsyncTask should send the HTMLContent to a handler object. The handler will be running on your main thread, so you can display the information to the user at that point.
You shouldn't be calling
dl.getContent();
to retrieve the content. AsyncTask runs on a separate thread, so you can't just call methods like this from your main thread. You need to create the Downloader object (like you did) and then call
dl.execute();
to start the AsyncTask.
run the get method inside a thread,
new Thread(new Runnable() {
#Override
public void run() {
// call get method here
}
}).start();
Since Honeycomb (Android 3.0) you can't use Networking Operations in the MainThread to avoid freezes on the Phone. This is important in order to make your app responsive.
More info:
NetworkOnMainThreadException
Responsiveness
One of the first things I learned when beginning android development (and beginners development in general) is that the UI should not (and in many cases can not) be updated by any other thread besides the main UI thread.
I have an AsyncTask that is moving a bunch of files in its doInBackground(). I have a progressbar that represents that to the user.
For the heck of it (mostly due to laziness) I decided to try the progressBar.setProgress([updated progress]) right in the doInBackground() method/thread, and to my surprise, it works fine.
However, that seems to go against the convention I've learned. I know AsyncTask has a onProgressUpdate() or whatever, but it's confusing me a bit, and I'm not sure if it's worth switching, since the current implementation seems to be working fine.
Should I not be updating the progressbar in this background thread?
ProgressBar is able to do this without crashing because setProgress() calls refreshProgress() (a Thread-safe method), when it is time to actually refresh the View.
private synchronized void refreshProgress(int id, int progress, boolean fromUser) {
if (mUiThreadId == Thread.currentThread().getId()) {
doRefreshProgress(id, progress, fromUser, true);
} else {
if (mRefreshProgressRunnable == null) {
mRefreshProgressRunnable = new RefreshProgressRunnable();
}
final RefreshData rd = RefreshData.obtain(id, progress, fromUser);
mRefreshData.add(rd);
if (mAttached && !mRefreshIsPosted) {
post(mRefreshProgressRunnable);
mRefreshIsPosted = true;
}
}
}
It posts a Runnable to the UI Thread if the method call was made a non-UI Thread, avoiding CalledFromWrongThreadExceptions.
However, always use the UI thread for UI related calls; the Android developers can change the implementation anytime and Views are usually not Thread-safe.
You should not modify the ProgressBar and/or call any of its methods directly from inside doInBackground(), as the Android UI toolkit is not thread safe.
Instead, call publishProgress() from inside doInBackground() and you will receive a subsequent callback on the UI thread in onProgressUpdate() where you can modify the ProgressBar however you like.
I have an AsyncTask which which takes an ArrayList of music files to play. In the doInBackground method, I loop through the ArrayList and play the songs one-by-one. I'd like to put a status message on a TextView of the UI or something to indicate which song is playing, but getting the error Only the original thread that created a view hierarchy can touch its views. If I only update the UI widgets from onPreExecute() and onPostExecute() the list has already been played. Is there a way to use onProgressUpdate or other AsyncTask method to do this?
This is certainly possible. Here's a basic example if you had Strings you wanted to display for song name, album name, and artist name (I haven't fully implemented the AsyncTask, just the parts relevant to onProgressUpdate):
private class myAsyncTask extends AsyncTask<Void, String, Void>
{
protected Void doInBackground(Void... voids)
{
//Get some list of songs, named songs
for(Song song in songs)//This is the loop where you're playing your songs
{
publishProgress(song.name, song.album, song.artist);
//Play the song and wait for it to finish
}
return null;
}
protected void onProgressUpdate(String... songData)
{
//Assuming three text views exist to display your data
nameTextView.setText(songData[0]);
albumTextView.setText(songData[1]);
artistTextView.setText(songData[2]);
}
}
The important things to note are the the second class in the angle brackets is the type of parameters for onProgressUpdate, and that publishProgress gets called in doInBackground to trigger onProgressUpdate. Most examples that you'll find for onProgressUpdate involve increasing the fill on a ProgressBar, but the method runs on the UI thread and can interact with any Views that can be accessed by your AsyncTask. If you're still having some trouble, post your current AsyncTask so that it'll be easier to help integrate this example class into what you already have. Here are the docs for AsyncTask for more information.Hope this helps!
You should be able to use onProgressUpdate() to perform the update from the UI thread. Or, you could do it like this (which is typical when not using AsyncTask).
Post an event on the UI thread that updates your UI like this:
view.post( new Runnable() {
#Override
public void run() {
// Update your UI
}
});
It will be running on the UI thread so it can access and update the view.
Yes there is.
When you decalre your AsyncTask, you decalre the types that go into each part of the task:
public class MyTask extends AsyncTask<URL,Integer,Long> {
.
.
.
}
The types in order, for this example:
URL gets passed to doInBackground via execute
Integer gets to onProgressUpdate (via publishProgress)
Long gets to onPostExecute, also the return value of doInBackground
In your doInBackground(), you can call publishProgress(), which will in turn call onProgessUpdate() on the main thread (assuming you created your AsyncTask on the main thread).
There is a complete example in the reference docs under Usage (link).
I'm looking for a design pattern or approach for the following scenario. I wish to kick off two separate background threads for data retrieval from different sources. I then want one method (on the UI thread) to be called once both background threads have completed their work. As the data from the two sources must be combined to be useful, I must wait until both have finished retrieving before manipulating the data. How can I achieve this on the Android platform?
Edit: My first version has been bothering me, and I didn't like the necessary added boolean with it, so here's another version. Call it with this from onPostExecute of each added task.
ArrayList<AsyncTask> tasks;
public void doStuffWhenDone(AsyncTask finishedTask)
{
tasks.remove(finishedTask);
if(tasks.size() > 0)
return;
... do stuff
}
I'll keep the older one up also, since they both work, but I think the above is much cleaner. Now to go tidy up one of my earlier projects.
ArrayList<AsyncTask> tasks;
boolean hasBeenDone = false;
public void doStuffWhenDone()
{
for(int i=0;i<tasks.size();i++)
if(hasBeenDone || (tasks.get(i).getStatus() != AsyncTask.Status.FINISHED))
return;
hasBeenDone = true;
... do stuff
}
It's easily extendable to however many tasks you have, and there's no need for a thread to handle the threads. Just call the method at the end of each task. If it's not the last one done, nothing happens.
Edit: Good point, but I don't think it needs to be atomic. Since both AsyncTasks' onPostExecute methods run on the UI thread, they'll be called one after the other.
Use a CountDownLatch, like this:
CountDownLatch barrier = new CountDownLatch(2); // init with count=2
startWorkerThread1(barrier);
startWorkerThread2(barrier);
barrier.await(); // it will wait here until the count is zero
doStuffWithTheResult();
when a worker thread finishes, call barrier.countDown() from it.
You can use AsyncTask and an int to know if both jobs are finished...
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).