I have an AsyncTask with a textview loaded in the class so it looks something like this:
private class MyClass extends AsyncTask<TextView, Void, Void>{
}
TextView tv;
Loaded this way
"new MyClass(tv).execute();"
The reason for this is because of I have a textview loaded inside a viewflipper and I have a long load method inside the task to implement a process dialog.
My error is found on "protected Void doInBackground(TextView... params) {" this is where params is a TextView[] but not a single TextView.
Does anyone have a solution of to this problem?
Your TextView is the first element in params:
TextView tv = params[0];
NOTE:
If you plan to modify that TextView in doInbackground() don't do it because you'll throw an exception(you can't modify a view from another thread, instead use the onPostExecute method).
You can't change the method signature of the AsyncTask.doInBackground() method.
It is defined to take a varargs parameter, so you will have to pass a TextView[] parameter to your AsyncTask.
Try
Arrays.asList(tv);
If you want to pass a single TextView you will need to define a Construcotr in MyClass and then store the TextView as a field in MyClass. Beware doing this though, you should not hold references to View's or Contexts in your tasks. This will stop the Android OS from garbage collecting the activity that owns the TextView and could leat to a memory leak. If you must keep a reference to a view or context in your AsyncTask, use something like this:
private class MyClass extends AsyncTask<TextView, Void, Void>{
private WeakReference<TextView> tvRef;
public MyClass(TextView tv) {
this.tvRef = new WeakReference<TextView>(tv);
}
}
Just read params[0] as your parameter. You can pass a single value, a sequence or an array wherever you see ... in the parameter list. (A single value is actually a sequence containing just one element.)
Related
This question already has answers here:
AsyncTask Android example
(21 answers)
Closed 9 years ago.
I have a splash screen with a TextView to displays what the app is doing such as "Updating Library"... "Updating Shipping"... etc. I'm using AsyncTask to updated my database via an API.
I'm passing the update text to the AsyncTask. I need to change the text in TextView statusMessage. I'm attempting to do this:
public class JSONParser extends AsyncTask<String, String, JSONObject> {
static InputStream is = null;
static JSONObject json = null;
static String outPut = "";
TextView statusMessage;
#Override
protected void onPreExecute() {
statusMessage = (TextView) findViewById(R.id.statusMessage);
}
...
My plan is to change the text in the doInBackground method but findViewById isn't accessible in AsyncTask. I think I need to use setContentView to allow findViewById to work but I'm not sure how.
My java file is SplashScreen.java and my xml is activity_splash_screen.xml
----- EDIT -----
For more info I have three pieces talking to each other:
SplashScreen.java -> calls to method in baseActivity.java -> method sends data to JSONParser.java -> sends parsed JSON from the API to baseActivity.java to update database
Per suggestions below I've declared
statusMessage = (TextView) findViewById(R.id.statusMessage);
In baseActivity.java's onCreate since it's the file calling the AsyncTask.
In JSONParser.java I've done this, now:
public class JSONParser extends AsyncTask<String, String, JSONObject> {
static InputStream is = null;
static JSONObject json = null;
static String outPut = "";
TextView statusMessage;
#Override
protected JSONObject doInBackground(String... params) {
// TODO Auto-generated method stub
...
}
protected void onProgressUpdate() {
statusMessage.setText("testing");
}
protected void onPostExecute(JSONObject result) {
}
}
I'm just using "testing" there for testing purposes.
My plan is to change the text in the doInBackground
Bad plan! You can't update the UI from a background Thread. You will need to do this in either onPostExecute() or onProgressUpdate().
but findViewById isn't accessible in AsyncTask.
If this is an inner class of your Activity then initialize the View in the Activity then update it in your task as described above.
If it is its own file then you will want to use an interface and have a callback to the Acitivty in onPostExecute(), onPreExecute(), or onProgressUpdate(). You can see an example of that in this SO answer.
I think I need to use setContentView to allow findViewById
Definitely! But as stated above, do this before the task such as in onCreate() of your Activity.
Edit
onProgressUpdate() takes a param but your onProgressUpdate() doesn't so it isn't the same method. That's why it complained when you had #Override which is the point of the annotation. It complains and you know you are suppose to be overriding a method so you know something is wrong with it.
Change it to
protected void onProgressUpdate(Void...values) {
statusMessage.setText("testing");
}
onProgressUpdate() link
http://developer.android.com/reference/android/os/AsyncTask.html#onProgressUpdate(Progress...)
You should use onProgressUpdate, that method has acces to the ui thread.
public class yourAsync extends AsyncTask<> {
#Override
protected void onProgressUpdate() {
textView.setText();
}
}
put something like this in your activity
Handler statusUpdateHandeler = new Handler()........
In your thread, call the handler (send it a message)
MainActivity.statusUpdateHandler.sendEmptyMessage(1);
In you actual handler code, set the status message.
I think I need to use setContentView to allow findViewById to work but I'm not sure how.
Yes. You need to use setContentView(R.layout.activity_splash_screen) in onCreate.
You can initialize your view in onCreate make asynctask an inner class of activity and update ui in onPreExecute.
TextView statusMessage;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
statusMessage = (TextView) findViewById(R.id.statusMessage);
}
Also you can use a progressdialog and display the message. I think using progressdialog would be a better choice than textview. You can publish progress in doInbackground and update progress dialog in onProgressUpdate()
http://developer.android.com/reference/android/os/AsyncTask.html
textview and button in my listview by using adapter class. When i click on that button i have to call AsyncTask passing parameters i.e String of that perticular position in adapter class getview method .Here am created my Asynctask is another class i.e an activity class. Please provide some examples.
Thanks in advance.
Your AsycnTask takes an Array of some sort - Strings for instance, so when you instantiate the AsyncTask, you just pass it an Array like so:
String[] arr = new String[] {"A string to pass..."};
MyAsyncTask task = new MyAsyncTask();
task.execute(arr);
Full example on how to use it:
http://www.android-ever.com/2012/10/android-asynctask-example.html
Create public class in different file or within your activity. If you are creating within Activity then define like this way
public class static MyAsync extends AsyncTask<String, Void, String>{
}
and then used anywhere like this
YourActivity.MyAsync myAsync = new YourActivity.MyAsync();
for passing the value to the your Async class use this way
myAsync.execute(yourstring);
access in doInBackground like this way
public String doInBackground(String... param){
String s = param[0]; // here you can access you string like this way
}
Ok so now I have Class A that contains some spinners that values will be populated by Class B that extends AsnycTask which grabs the spinner values from a web service. In class B i manage to retrieve the values, showing in a Toast. The problem now is how do I pass those spinner values back to Class A?
I've tried
Can OnPostExcecute method in AsyncTask RETURN values?
by passing Class A to Class B and store the value in a public variable of Class A like below
#Override
protected void onPostExecute(String result)
{
classA.classAvariable = result;
}
However whenever I try to read the classAvariable i always get a NullPointer Exception.
Seems like the variable was never assigned with the result.
For readability purpose I needed to seperate Class B instead of using as an inline class.
Any ideas my fellow Java programmers?
Problem here is that when you execute your AsynchTask, its doInBackground() methode run in separate thread and the thread that have started this AsynchTask move forward, Thereby changes occur on your variable by AsynchTask does not reflect on parent thread (who stated this AsynchTask) immediately.
Example --
class MyAsynchTask
{
doInbackground()
{
a = 2;
}
}
int a = 5;
new MyAsynchTask().execute();
// here a still be 5
Create a interface like OnCompletRequest() then pass this to your ClassB constructor and simply call the method inside this interface such as complete(yourList list) in the method of onPostExecute(String result)
You can retrieve the return value of protected Boolean doInBackground() by calling the get() method of AsyncTask class :
E.g. you have AsyncTask class as dbClass like
dbClass bg = new dbClass(this);
String Order_id = bg.execute(constr,data).get();
Here I am passing constr as URL and data as string of inputs to make my class dynamic.
But be careful of the responsiveness of the UI, because get() waits for the computation to complete and will block the UI thread.
I've used the AsyncTask example from vogella website, I've created a class file with it.
I'm calling it from Activity A to update the postalcode's TextView, it's working.
I'm wondering how can I call the same AsyncTask from Activity B to update another postal code TextView.
So one AsyncTask, 2 calls from different Activities to update different TextViews.
I've to do something onPostExecute(), right?
Some example code, is much appreciated.
Thanks in advance
You can (I guess) pass the TextView to the AsyncTask when you instantiate it.
All without the IDE open so apologies if the syntax is off...
public class ExampleTask extends AsyncTask<Void, Void, Void> {
private TextView targetTextView;
public ExampleTask(TextView target) {
targetTextView = target;
}
#Override
protected String doInBackground(Void... orSomething) {
//do work and get a value I guess
}
#Override
protected void onPostExecute(String result) {
targetTextView.setText(result);
}
}
Then you'd call this:
ExampleTask task = new ExampleTask(theTextViewToUpdate);
task.execute();
You'd want to be careful about the scope of the task objects you instantiate as that reference to a TextView could end up leaking memory from your activities.
Here I am not good, but you can try
It is possible to reuse AsyncTask for different Activities.
For this you must take different parameter from different Activities.
In AsyncTask Class initiate a constructor with a case parameter (which is described in other activities) which will decide ,it is called by Activity A or B or C.
Now use switch case statement and move ahead.
I want to implement a generic, thread save class which takes the RessourceId of an ImageView and the Url (http) where the desired image file is stored. It'll download the image and fills the src of the ImageView in the UiThread.
I thought AsyncTask would be the best thing for me. However I noticed that I only can pass one type of parameters to the doInBackground() Method. Like an Array of Urls. Is that true? What would u suggest me?
You can pass params as objects
new MyTask().execute(url, str, context);
public class MyTask extends AsyncTask<Object, Void, Void> {
#Override
protected Void doInBackground(Object... params) {
Url url = (Url) params[0];
String str = (String) params[1];
Context ctx = (Context) params[2];
return null;
}
}
You can add setter methods to your AsyncTask implementation, or even define your own constructor to pass additional parameters.
Optionally, if your AsyncTask implementation is an inner class of an activity you can access all the instance variables of your activity. I prefer the above option myself, as it clearly indicates which data the task requires.