2016-05-23 1 views
0

Я пытаюсь получить массив из одного класса задачи async в другой класс фрагмента, но получаю исключение с нулевым указателем. Я видел много ответов здесь, но никто, что я видел, фактически не ответил на этот вопрос.Android, передающий значение массива из задачи async в другой класс

Я попытался вернуть значение из задачи класса async, и я попытался сделать массив статическим, но я не имел успеха.

Эти классы (я выделил, где я пытаюсь получить значение из и довести его до):

public class DemoPreviewSongFragment extends DemoFragmentBase { 
     // The DynamoDB object mapper for accessing DynamoDB. 
     private final DynamoDBMapper mapper; 
     public DemoPreviewSongFragment() { 
      mapper = AWSMobileClient.defaultMobileClient().getDynamoDBMapper(); 
     } 

     SongPreviewCardsDataAdapter mCardAdapter; 
     com.wenchao.cardstack.CardStack mCardStack; 

     @Override 
     public View onCreateView(final LayoutInflater inflater, final ViewGroup container, 
           final Bundle savedInstanceState) { 
      View view = inflater.inflate(R.layout.fragment_preview_song, container, false); 
      mCardStack = (CardStack)view.findViewById(R.id.cardstackcontainer); 
      mCardStack.setContentResource(R.layout.song_preview_card_layout); 
      mCardStack.setStackMargin(20); 

      new getSongsInCategory().execute(); 

/////////// WHEN TRYING TO REFERENCE THE STATIC ARRAY RESULT HERE I GET A NULL /////////// POINTER. I NEED THE ARRAY HERE SO I CAN PUT IT IN THE ADAPTER. 

      mCardAdapter = new SongPreviewCardsDataAdapter(getActivity().getApplicationContext(),0); 
      mCardAdapter.add("test1"); 

      mCardStack.setAdapter(mCardAdapter); 

      return view; 
     } 



//////////////////// THIS IS THE ARRAY I AM TRYING TO PASS ///////////////////// 
     public static PaginatedQueryList<SongDatabaseMappingAdapter> result; 

     public class getSongsInCategory extends AsyncTask { 

      @Override 
      protected Object doInBackground(Object[] params) { 

       SongDatabaseMappingAdapter songs = new SongDatabaseMappingAdapter(); 
       songs.setCategory("Rap"); 

       String userRatingQueryString = "5"; 

       Condition rangeKeyCondition = new Condition() 
         .withComparisonOperator(ComparisonOperator.EQ) 
         .withAttributeValueList(new AttributeValue().withN(userRatingQueryString)); 

       DynamoDBQueryExpression queryExpression = new DynamoDBQueryExpression() 
         .withHashKeyValues(songs) 
         .withIndexName("Category-UserRating-index") 
         .withRangeKeyCondition("UserRating", rangeKeyCondition) 
         .withConsistentRead(false); 

       result = mapper.query(SongDatabaseMappingAdapter.class, queryExpression); 
       return result; 
      } 
    } 

Я не уверен, что я здесь делаю неправильно, почему это пустой указатель когда он должен быть глобальным (статическим) массивом? Есть ли лучший способ сделать это?

Спасибо за вашу помощь

ответ

1

Ok, так что вы должны понять принцип AsyncTask, попросту говоря, она выполняет некоторые вещи в другом потоке, не блокирует текущий поток, а не блокирует, что означает, что он автоматически перейдет к следующей строке после того, как вы вызовете execute в зависимости от продолжительности задач в задаче asynk и не дожидаетесь завершения задач.

В вашем случае:

new getSongsInCategory().execute(); // here you call the task to generate the result 
result.doSomething() // this line will be called before your task is completed, so the result won't be initialized => NPE 

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

Так пример может быть что-то вроде этого:

public class DemoPreviewSongFragment extends DemoFragmentBase implements AwesomeObserver { 
public interface AwesomeObserver { 
    void theTaskIsDone(Object theTaskResult); 
} 

public View onCreateView(final LayoutInflater inflater, final ViewGroup container, 
          final Bundle savedInstanceState) { 
... 
new GetSongsInCategory(this).execute(); 

// Новая передовая практика новый GetSongsInCategory (это) .executeOnExecutor (THREAD_POOL_EXECUTOR); }

@Override 
theTaskIsDone(Object theTaskResult) { 
    theTaskResult.doSomething(); 
    //In your case 
     mCardAdapter = new SongPreviewCardsDataAdapter(getActivity().getApplicationContext(),0); 
     mCardAdapter.add("test1"); 

     mCardStack.setAdapter(mCardAdapter); 
} 

public class GetSongsInCategory extends AsyncTask { 
    private AwesomeObserver observer; 
    public GetSongsInCategory(AwesomeObserver someone) { 
     observer = someone; 
    } 
// doInBackground ....and do things 

public void onPostExecute(Object object) { 
    // at this point you know the task is done 
    if(observer != null) 
    observer.theTaskIsDone(object); 
    } 
} 

}

Теперь, чтобы избежать путаницы, параметры в theTaskIsDone & onPostExecute только примеры, и вы можете использовать все, что он работает на вашем примере. Это действительно общий путь, вы также можете вызвать метод из класса-класса вашей асинхронной задачи, но этот подход будет работать, если у вас есть внутренняя задача async или задача async в отдельном java-файле.

2

Набор данных для адаптера в onPostexecute() метод AsynTask. Вы получаете исключение, потому что вы не получаете никаких данных, это адаптер. AsynTask выполняет операцию в фоновом режиме, и может случиться, что вы используете значения до завершения AsyncTask. Поэтому установите адаптер в onPostExecute.

doInBackground(){ 
} 
onPostExecute(){ 

// use result array here and set it on adapter 
} 
1

AsyncTask является асинхронным поэтому массив null.You может обновить адаптер, когда AsyncTask завершено путем доступа в методе OnPostExecute().

Это код, который я изменил, теперь он будет работать.

public class DemoPreviewSongFragment extends DemoFragmentBase { 
    // The DynamoDB object mapper for accessing DynamoDB. 
    private final DynamoDBMapper mapper; 
    public DemoPreviewSongFragment() { 
     mapper = AWSMobileClient.defaultMobileClient().getDynamoDBMapper(); 
    } 

    SongPreviewCardsDataAdapter mCardAdapter; 
    com.wenchao.cardstack.CardStack mCardStack; 

    @Override 
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container, 
          final Bundle savedInstanceState) { 
     View view = inflater.inflate(R.layout.fragment_preview_song, container, false); 
     mCardStack = (CardStack)view.findViewById(R.id.cardstackcontainer); 
     mCardStack.setContentResource(R.layout.song_preview_card_layout); 
     mCardStack.setStackMargin(20); 

     new getSongsInCategory().execute(); 

     return view; 
    } 

    public class getSongsInCategory extends AsyncTask { 

     @Override 
     protected Object doInBackground(Object[] params) { 

      SongDatabaseMappingAdapter songs = new SongDatabaseMappingAdapter(); 
      songs.setCategory("Rap"); 

      String userRatingQueryString = "5"; 

      Condition rangeKeyCondition = new Condition() 
        .withComparisonOperator(ComparisonOperator.EQ) 
        .withAttributeValueList(new AttributeValue().withN(userRatingQueryString)); 

      DynamoDBQueryExpression queryExpression = new DynamoDBQueryExpression() 
        .withHashKeyValues(songs) 
        .withIndexName("Category-UserRating-index") 
        .withRangeKeyCondition("UserRating", rangeKeyCondition) 
        .withConsistentRead(false); 

     return mapper.query(SongDatabaseMappingAdapter.class, queryExpression); 

     } 

     @Override 
     public void onPostExecute(Object obj){ 

     //Here array will not be null. 

     PaginatedQueryList<SongDatabaseMappingAdapter> result=(PaginatedQueryList<SongDatabaseMappingAdapter>)obj; 
     mCardAdapter = new SongPreviewCardsDataAdapter(getActivity().getApplicationContext(),result[0]); 
     mCardAdapter.add("test1"); 

     mCardStack.setAdapter(mCardAdapter); 

     } 

    }