Inner class can access but not update values - AsyncTask
How can I ensure that the values remain updated?
They will be updated since they are member variables. However, since AsyncTask
is asynchrounous, they might not be updated yet when you check them. You can use an interface
to create a callback when these values are updated. This SO answer covers how to do this
Does that mean that any values updated in the new thread will be lost once that thread returns?
No they shouldn't be "lost". They probably just haven't been changed in the AsyncTask
when you check them.
Since this isn't your actual code I can't see when you are trying to access them but you can use the interface
method or call the functions that need these values in onPostExecute()
. You also can do a null
check before trying to access them. It just depends on the functionality and flow that you need as to which is the best way. Hope that helps.
Edit
In the answer I linked to, you tell the Activity
that you will use that interface
and override its method(s) with implements AsyncResponse
in your Activity
declaration after creating the separate interface class
public class MainActivity implements AsyncResponse{
then, in your Activity
still, you override the method you declared in that class (void processFinish(String output);
)
@Override
void processFinish(String output){ // using same params as onPostExecute()
//this you will received result fired from async class of onPostExecute(result) method.
}
then this is called in onPostExecute()
when the listener sees that it is done with delegate.processFinish(result);
delegate
is an instance of AsyncResponse
(your interface class)
public class AasyncTask extends AsyncTask{
public AsyncResponse delegate=null;
@Override
protected void onPostExecute(String result) {
delegate.processFinish(result);
}
Interface
example taken from linked answer above and adjusted/commented for clarity. So be sure to upvote that answer if it helps anyone.
Asynctask inner class not updating UI textview
You have not called ASyncTask, execute it like this after initializing TextView:
txtview = (TextView) findViewById(R.id.mainview);
SimpleTask objSimpleTask=new SimpleTask();
objSimpleTask.execute();
Hope is what you want.
doInBackground not updating variable
The problem is that your AsyncTask
is executed asynchronously, while you try to retrieve the value immediately. You need to implement this a little bit differently. Either leverage the API of AsyncTask, sine it posts callbacks for your on the UI thread. You can update your TextView
directly in your AsyncTask
class MyAwesomeAsyncTask extends AsyncTask<Void, Void, String> {
@Override
protected void onPreExecute() {
myTextView.setText("progress started");
}
@Override
protected String doInBackground(final Void... voids) {
String s = amazingCallToBackend();
return s;
}
@Override
protected void onPostExecute(final String s) {
myTextView.setText(s);
}
}
Or if you just want the value, you can pass a Callback to your async task that will deliver the value to you, something like that
interface Callback {
void onValueReceived(String value);
void onFailure();
}
class MyAwesomeAsyncTask extends AsyncTask<Void, Void, String> {
private Callback callback;
MyAwesomeAsyncTask(final Callback callback) {
this.callback = callback;
}
@Override
protected String doInBackground(final Void... voids) {
String s = amazingCallToBackend();
return s;
}
@Override
protected void onPostExecute(final String s) {
callback.onValueReceived(s);
}
}
Here's how you create it
Callback callback = new Callback() {
@Override
public void onValueReceived(final String value) {
}
@Override
public void onFailure() {
}
};
new MyAwesomeAsyncTask(callback).execute();
However, be careful because if for some reason your activity/fragment is gone/finished before your AsyncTask is done, this can cause memory leaks.
A quick Google search will tell you all you want about AsyncTask leaking memory :)
What's the correct way to implement AsyncTask? static or non static nested class?
In general I would recommend the static implementation (though both are acceptable).
The Google approach will require less code but your asynctask will be tightly coupled with your actitivy (which means not easily reusable). But sometimes this approach is more readable.
With the CommonsGuy approach, it will require more effort (and more code) to decouple activity and asynctask, but in the end you will have a more modular, more reusable code.
Access private variable from inner class (AsyncTask)
The entire point of an async task is that it is asynchronous. If you execute a task, you will not get the results back on your next line of code. In order to evaluate the result, you should be using the onPostExecute
callback method.
@Override
protected void onPostExecute(String s) {
if(sentResult==true){
Toast toast = Toast.makeText(this.context, "Message Sent", Toast.LENGTH_LONG);
toast.show();
}else{
Toast toast = Toast.makeText(this.context, "ERROR: Message not Sent", Toast.LENGTH_LONG);
toast.show();
}
}
Also, if you were to change your method signatures, you wouldn't even need an external variable.
private class SenderAsync extends AsyncTask<String,String,Boolean> {
@Override
protected void onPostExecute(Boolean sent) {
if(sent == true){
Toast toast = Toast.makeText(this.context, "Message Sent", Toast.LENGTH_LONG);
toast.show();
}else{
Toast toast = Toast.makeText(this.context, "ERROR: Message not Sent", Toast.LENGTH_LONG);
toast.show();
}
}
@Override
protected Boolean doInBackground(String... params) {
try {
...
if (resp.getStatusLine().getStatusCode() == 200) {
return true;
}
}
catch (IOException e) {
}
return false;
}
updating UI thread while in asynctask
This line here
TextView tv = (TextView) findViewById(R.id.thingsThatNeedToBeUpdated);
is obviously declared either
- Outside of a method -which would result in
tv
beingnull
or - In a method that isn't part of the
AsyncTask
- which would mean the
task doesn't have access to it
You should define it as a member variable (outside of a method)
TextView tv;
then initialize it inside of a method
tv = (TextView) findViewById(R.id.thingsThatNeedToBeUpdated);
This will give your task access to it as well as the rest of your class.
If your AsyncTask
is a separate file than your Activity
then you will want to see this answer on using an interface
and create a callback to update the TextView
in your Activity
.
AsyncTask as Inner class and static field issue
I have understand where is the problem.
You have to run the search method on the UI thread.
So change this code block:
@Override
protected Void doInBackground(String... strings) {
try {
search(strings[0], string[1]);
return null;
} catch(Exception e) {
}
}
with this
@Override
protected Void doInBackground(final String... strings) {
try {
runOnUiThread(new Runnable() {
public void run() {
search(strings[0], string[1]);
return null;
}
});
} catch(Exception e) {
e.printStackTrace();
}
}
And all should works correctly.
Android AsyncTask as NOT an Inner class : Weird NullPointerException
As Pedro stated in his comment you don't want to try and instantiate an Activity
the way you are.
All you need to do is to pass the value from the first to second Activity
. Then you can pass that value to the constructor of your AsyncTask
.
So, in your onClick()
of the first Activity
you pass it as an Extra
.
public void StartSecondActivity(View v) {
Intent intent = new Intent(this, SecondActivity.class);
EditText et = (EditText) findViewById(R.id.mainActivity_editText1);
String temp = et.getText().toString();
intent.putExtra("temp", temp);
startActivity(intent);
}
then retrieve it and pass it to the task
public class SecondActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// get the String
Intent i = getIntent();
String temp = i.getStringExtra("temp");
setContentView(R.layout.activity_second);
// and pass it here
new MyTask(temp).execute();
}
}
now get it in your task
MyTask(String value) {
searchString= value;
}
Android: How to update an UI from AsyncTask if AsyncTask is in a separate class?
AsyncTask is always separate class from Activity
, but I suspect you mean it is in different file than your activity class file, so you cannot benefit from being activity's inner class. Simply pass Activity context as argument to your Async Task (i.e. to its constructor)
class MyAsyncTask extends AsyncTask<URL, Integer, Long> {
WeakReference<Activity> mWeakActivity;
public MyAsyncTask(Activity activity) {
mWeakActivity = new WeakReference<Activity>(activity);
}
...
and use when you need it (remember to NOT use in during doInBackground()
) i.e. so when you would normally call
int id = findViewById(...)
in AsyncTask you call i.e.
Activity activity = mWeakActivity.get();
if (activity != null) {
int id = activity.findViewById(...);
}
Note that our Activity
can be gone while doInBackground()
is in progress (so the reference returned can become null
), but by using WeakReference
we do not prevent GC from collecting it (and leaking memory) and as Activity is gone, it's usually pointless to even try to update it state (still, depending on your logic you may want to do something like changing internal state or update DB, but touching UI must be skipped).
Related Topics
How to Use Java 8 For Android Development
One Time Login in App - Firebaseauth
Android 5.0 - Add Header/Footer to a Recyclerview
How to Compare Strings in Java
When to Use Linkedlist Over Arraylist in Java
Why Is Java Vector (And Stack) Class Considered Obsolete or Deprecated
How to Generate a Random Alpha-Numeric String
"Comparison Method Violates Its General Contract!"
What Is a Classpath and How to Set It
Collision Detection With Complex Shapes
Android, Getting Resource Id from String
Showing Firebase Data in Listview
How to Ping External Ip from Java Android
Is Java "Pass-By-Reference" or "Pass-By-Value"
How to Efficiently Iterate Over Each Entry in a Java Map