I have an object, MyObject, that populates itself with some random numbers. It doesn’t take very long and is seemingly instant. However, these values are used on the UI and on occasion it isn’t completely ready when the UI is building.
I’ve created an AsyncTask that is used to instantiate the object and it’s at the end of this post.
However doInBackground(...) doesn’t instantiate the object completely before onPostExecute(...) is called when it is in this fashion.
protected MyObject doInBackground(Void... unused) {
// this may take a few moments and cause a null reference
// so make a task
MyObject obj = new MyObject();
return obj;
}
I’ve also tried to use a flag to signify completion, but it doesn’t appear to guarantee either.
MyObject obj = new MyObject();
while (obj.isComplete() == false) {
// do nothing. Wait for completion
}
return obj;
Inside of MyObject is simple
public MyObject() {
createValues(); // entire object created with this
this.mComplete = true;
}
It fails less, but still does. createValues() uses an ArrayList for part of its calculations if that is contributing to the race condition.
Below is an example MyFragment that uses the task in methodCall().
Question How do I simply wait until MyObject is completely instantiated to end?
Stacktrace
java.lang.NullPointerException
at MyFragment.setupFragment(MyFragment.java:95)
at MyFragment.onTaskComplete(MyFragment.java:143)
at MyTask.onPostExecute(MyTask.java:37)
at MyTask.onPostExecute(MyTask.java:1)
at android.os.AsyncTask.finish(AsyncTask.java:631)
Fragment
public class MyFragment extends Fragment implements MyTask.OnTaskComplete {
private MyObject mMyObject;
// ...
public void methodCall() {
// generate puzzle and set it up in the background
MyTask task = new MyTask(this);
task.execute();
}
function void setupFragment() {
// null pointer exception here
// mMyObject is not initiated yet and only some times
// values is an array of integers
int example = this.mMyObject.values[0];
}
@Override
public void onTaskComplete(MyObject obj) {
// returned from MyTask
this.mMyObject = obj;
this.setupFragment();
}
}
AsyncTask
public class MyObjectTask extends AsyncTask<Void, Void, MyObject> {
public static interface OnTaskComplete {
public abstract void onTaskComplete(MyObject obj);
}
static final String TAG = "MyObjectTask";
private OnTaskComplete mListener;
public MyObjectTask(OnTaskComplete listener) {
this.mListener = listener;
}
@Override
protected MyObject doInBackground(Void... unused) {
// this may take a few moments and cause a null reference
// so make a task
return new MyObject();
}
@Override
protected void onPostExecute(MyObject obj) {
this.mListener.onTaskComplete(obj);
}
}
What you are doing should be completely fine if you are not creating any new threads inside your object when creating it.
You have added a callback which you need to fist set before executing the task and then it will be triggered when the AsyncTask exits (doInBackground finishes and your post execute is called).
So from what i am seeing in your code there is no way the constructor doesn’t finish and your object is returned in the callback.
So check if possibly something throws an Exception in your object in the method createValues.
Do you have a stacktrace of the exception that happens?