2016-05-23 6 views
0

Ich versuche, ein Array von einer asynchronen Aufgabenklasse zu einer anderen Fragmentklasse zu bekommen, aber ich bekomme eine Nullzeiger Ausnahme. Ich habe hier viele Antworten gesehen, aber keine, die ich gesehen habe, hat diese Frage beantwortet.Android übergeben Wert von Array von Async-Aufgabe zu einer anderen Klasse

Ich habe versucht, den Wert aus der Async-Klasse Aufgabe und ich versuchte, das Array statisch zu machen, aber ich hatte keinen Erfolg.

Dies sind die Klassen (ich habe hervorgehoben, wo ich versuche, den Wert von zu bekommen und bringen sie zu):

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

Ich bin nicht sicher, was ich falsch hier, warum das ein Null-Zeiger ist tue Wann sollte es ein globales (statisches) Array sein? Gibt es einen besseren Weg, dies zu tun?

Danke für Ihre Hilfe

Antwort

1

Ok, so dass Sie das Prinzip der AsyncTask zu verstehen haben, einfach ausgedrückt, läuft es einige Dinge in einem anderen Thread, nicht blockiert den aktuellen Thread, und nicht blockiert das bedeutet, dass es automatisch in die nächste Zeile gehen nach dem Aufruf execute unabhängig von der Dauer der Aufgaben in der asynk-Task und nicht warten auf die Aufgaben abgeschlossen werden.

In Ihrem Fall:

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 

Die Art und Weise Sie tun sollten, ist es mit Observer Muster (Rückrufe). Sie legen einen Beobachter für Ihre AsyncTask fest, um herauszufinden, wann das erledigt ist. Wenn es fertig ist, benachrichtigt es das Objekt, das die Aufgabe beobachtet.

So könnte ein Beispiel so etwas wie dieses:

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(); 

// new best practice ist neue GetSongsInCategory (this) .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); 
    } 
} 

}

Jetzt Verwirrung zu vermeiden, werden die Parameter in theTaskIsDone & onPostExecute nur Beispiele sind, und Sie können, was diese für Ihre Beispiel funktioniert. Dies ist wirklich eine generische Art zu gehen, Sie könnten auch von onPostExecute eine Methode aus der enthaltenden Klasse Ihrer asynchronen Task aufrufen, aber dieser Ansatz funktioniert, wenn Sie innere asynchrone Task oder eine asynchrone Task in einer separaten Java-Datei haben.

2

Set Daten-Adapter in OnPostExecute() -Methode von AsynTask. Sie erhalten eine Ausnahme, weil Sie keine Daten als Adapter erhalten. AsynTask führt die Operation im Hintergrund aus und es kann der Fall sein, dass Sie die Werte verwenden, bevor AsyncTask beendet ist. Setzen Sie den Adapter in onPostExecute.

doInBackground(){ 
} 
onPostExecute(){ 

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

AsyncTask ist asynchron so das Array null.You ist, den Adapter aktualisieren, wenn die durch den Zugriff auf AsyncTask im OnPostExecute() Methode durchgeführt.

Dies ist der Code Ich habe die Logik geändert, jetzt wird es funktionieren.

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

     } 

    }