2013-02-17 2 views
1

У меня есть объект, MyObject, который заполняет собой некоторые случайные числа. Это не займет много времени и, похоже, мгновенно. Однако эти значения используются в пользовательском интерфейсе, и иногда он не полностью готов при создании пользовательского интерфейса.AsyncTask не ждет, пока объект будет создан до завершения

Я создал AsyncTask, который используется для создания объекта, и он находится в конце этого сообщения.

Однако doInBackground(...) не создает объект полностью, прежде чем onPostExecute(...) вызывается, когда он таким образом.

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; 
} 

Я также попытался использовать флаг, чтобы обозначить завершение, но он также не гарантирует.

MyObject obj = new MyObject(); 
while (obj.isComplete() == false) { 
    // do nothing. Wait for completion 
} 

return obj; 

Внутри MyObject просто

public MyObject() { 
    createValues(); // entire object created with this 
    this.mComplete = true; 
} 

В нем не меньше, но до сих пор. createValues() использует ArrayList для частичных расчетов, если это способствует условию гонки.

Ниже приведен пример MyFragment, который использует задачу в methodCall().

Вопрос Как просто подождать, пока MyObject полностью не создан?

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) 

Фрагмент

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); 
    } 
} 
+0

'mListener' может быть' null' – Geros

+0

Хорошая точка. Я обязательно поймаю это – Kirk

ответ

1

Что вы делаете должны быть полностью прекрасным, если вы не создаете никаких новых потоков внутри своего объекта при его создании.

Вы добавили обратный вызов, который вам нужно задать перед выполнением задачи, а затем он будет запущен, когда выйдет AsyncTask (вызывается завершение doInBackground и вызывается ваш пост).

Так что из того, что я вижу в вашем коде, конструктор не заканчивается, и ваш объект возвращается в обратном вызове.

Так что проверьте, возможно ли что-то выбрасывает исключение в вашем объекте в методе createValues.

У вас есть stacktrace исключения, которое происходит?

+0

Спасибо за ответ. Я добавил свое использование задачи в сообщение, и оно получило нулевой указатель в методе 'setupFragment()'. Я добавил связанную стек. – Kirk

+0

Мне просто пришло в голову, что я использую 'ArrayList' внутри' MyObject', если это вызывает проблемы в потоках. Сейчас я изучаю это. – Kirk

+0

Ваш объект не объявлен как массив, но вы по-прежнему обращаетесь к нему как таковой. Я думаю, что проблема заключается в том, как вы настраиваете вещи в моем объекте. все остальное выглядит хорошо. если вы используете список массивов, вам нужно получить значение как list.get (position). то, как у вас сейчас, это как обычный массив, а не arraylist, так как вы указываете – DArkO

1

Вы можете создать объект по методу onPreExecute из AsyncTask. Итак, когда doInBackground был вызван, объект будет уже создан. В этом случае вы можете просто вызвать метод для создания значений.

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; 
    private MyObject myObject; 

    public MyObjectTask(OnTaskComplete listener) { 
     this.mListener = listener; 
    } 

    @Override 
    protected void onPreExecute() { 
     myObject = new MyObject(); 
    } 

    @Override 
    protected MyObject doInBackground(Void... unused) { 
     // this may take a few moments and cause a null reference 
     // so make a task 
     myObject.createValues(); 
     return myObject; 
    } 

    @Override 
    protected void onPostExecute(MyObject obj) { 
     this.mListener.onTaskComplete(obj); 
    } 
} 
Смежные вопросы