I tried to change the textview more than once in my activity and then again in my AsyncTask. Is this possible it gave me a error on the line where i changed it the second time.
You can change it as often as you want.
But keep in mind that an AsyncTask is a seperate thread. If you want to change UI-components, you have to do this in the UI-thread.
This means: If you want to change a UI-control inside the AsyncTask class, you have to do it either inside onPreExecute(), onProgressUpdate() or onPostExecute(). These run in the UI thread and can manipulate Views and layouts. You can't do it inside doInBackground().
Edit: If you want to know more, read the official documentation:
Processes and Threads
TextView in Android is mutable - it can be written more than once using setText();
Here's the docs.
http://developer.android.com/reference/android/widget/TextView.html#setText(java.lang.CharSequence, android.widget.TextView.BufferType)
A more likely problem is that the variable for the TextView is null in the handler function of the AsyncTask. Check that the textView variable is available to the scope of your asynctask.
Related
An answer to another question raised a different question for me.
When displaying a ListView you update the Data Set then call the adapter's notifyDataSetChanged(). This calls requestLayout() and the Google documentation says "This will schedule a layout pass of the view tree"
So apparently we don't really know when that will take place. But during the layout pass many of the custom overrides in the adapter such as getView() and getCount() will be accessing the data set. So if the layout pass is run at an unknown time how do you know when it's safe to alter the data set?
I have a complex data set with multiple arrays that I need to keep synchronized with each other so I make my changes and call notifyDataSetChanged(). After that I may need to make more changes (say, because new data has come in over the network) so how do I make sure a layout pass from the previous notifyDataSetChanged() isn't going to run in the middle of making the new changes?
Also, what does Google mean by "schedule" a layout pass? When I log stuff in getView() the TID shown in the Logcat screen is the same as the main UI thread. so after calling notifyDataSetChanged() if I check for new data and start updating my arrays how does Android manage to run the layout pass in that same thread?
So if the layout pass is run at an unknown time how do you know when
it's safe to alter the data set?
It's very simple: by only updating the data set in the UI thread, you're guaranteed to avoid any problems. Since the layout also occurs in the UI thread, both operations will, by necessity, execute serially. This can be achieved via AsyncTask, Handler, or any other method of thread communication.
Also, what does Google mean by "schedule" a layout pass?
A message is posted for the UI thread's Looper. It will be processed whenever said thread is idle.
I am having a main class A, from which i create an object to class B extending Asynctask. Have set content view in A. Now in doInBackground of B, i want to update the textView of A, but its giving
Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Exception. I tried declaring the setcontentview in B as well, but no use, can anyone please tell how to edit the textview of A in B??
override onProgressUpdate and call publishProgress in doInBackground
You need to call setText() from the UI thread, so either from onPreExecute(), onPostExecute() or in onProgressUpdate()
You could also use a runOnUiThread() handler in doInBackground(), but that kind of defeats the purpose of using an AsyncTask.
If the text update has to do with progress information, then you could use publishProgress()/onProgressUpdate() for that.
If it's not a progress update in a wider sense then I'm with Raghav -- you should consider another approach then.
We should not perform any ui changes in the doinBackgroud. You should and can perform in post execute. and also you can set notification in preexecute or onProgressUpdate.
Hope this will help you.
doInBackground is work thread. You have handle View in UI thread. please do it in onPreExecute(), onPostExecute() or onProgressUpdate. All these are working in UI Thread.
Of course you can pass Integer to onProgressUpdate. please notice the second paramters: AysncTask<Void, Integer, VOid>, the second parameter means the onProgressUpdate parameter type
In an Android activity I'm executing an AsyncTask in onCreate method.
Should I declare the handler function of UI buttons inside onPostExecute of AsyncTask or in OnCreate method? Can I create another AsyncTask inside this button onClick handler? Thanks
A little bit of code would be helpful to better answer you. But the call to the constructor or the execute() method can be done in onCreate() but the actual class should be created either in a separate file or as an inner class of your Activity, depending on what you need it for. What you are explaining would probably work but I wouldn't put onClick events in your AsyncTask. If nothing else, for the readability. Also, this may make it more error prone, in my opinion. You might need local variables outside of the AsyncTask for the onClick() so this would reduce scope issues. Calling an AsyncTask from inside an onClick() would generally be fine to do. I hope this makes sense but if you need more clarification feel free to ask
I have some worker thread that gets an address using the geocoder, and when its done, i want to show the result on the application thread's TextView, using setText() from the worker thread leads to an exception, so what is the best practice to do that?
Android UI Views must not be touched from external threads, Any code that calls Methods on Views must run in UI thread only. You Should use AsyncTask . It provides useful callback methods to update UI from task running in a separate thread.
It's hard to say without seeing your code or knowing what exception:
but check if:
your textView object is linked with the one in your layout (findViewById(R.id.textView1))
is it visible in you layout?(sometimes when dimensions of elements dont't add up, views get pushed off screen)
Is it really a String you're trying to set? (not an int or so?)
Try this inside your thread where you want to set text:
// you should finalize your text before using it in another thread,
// else the IDE would show an error
final String text = yourTextToBeSet;
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(text);
}
});
The exception you get when you call setText() on non-UI thread is because you can't call anything related to UI when you are on a non-UI thread. You can, as above, easily call runOnUiThread(Runnable) to divert code execution on UI thread.
Keep in mind that this solution is not good enough if your code is not as simple as that, which in such situations, using AsyncTask is recommended.
Question arising from my first attempt at using an Async object.
I have a main activity in which some TextViews have been created programmatically and added to a LinearLayout. Also a button, when this is clicked, an AsyncTask object is instantiated and results are obtained in the doInBackGround method. How should the result strings be transferred to the TextViews?
a) by calling the SetText methods of these TextViews from the onPostExecute method,
b) using intents and an onActivityResult method in the main activity
c) some other way (a clue would be nice!)
Thanks!
I would go for the AsyncTask option. I'm guessing that as you already have one in place, the obtaining results part that happens when you click the button takes time, so it's good design to have that in the doInBackground method of the AsyncTask.
Then you can call each TextView's setText(...) method in the onPostExecute method in your AsyncTask. Or, it's more suitable, you can update each view as you get the result by using the publishProgress(...) and onProgressUpdate(...) methods (see the AsyncTask documentation) during the background calculations, instead of having to wait until the end.
Just bear in mind that you can only call setText(...) from the onPreExecute, onProgressUpdate and onPostExecute methods, as (at least it seems this way from your explanation) the views have been created on the UI thread, so they can only be modified from that same thread, which those methods run on.
When using an AsyncTask, you can use the doInBackground method for processing, and the onPostExecute to update any UI changes. So, if you need to use an AsyncTask, I'd go for option A.
Make the TextViews private and define them in doInBackground, then you can just call the setText method in onPostExecute or as the last thing in doInBackground, but i would recommend onPostExecute.