2014-04-21 2 views
3

Так что AsyncTask и я не ладят правильно. Я пытаюсь лучше понять, как он используется.Глобальные проблемы с ArrayList и AsyncTask

Так что я продолжаю сталкиваться с этой проблемой, когда загружаю JSON API в ArrayList (называемый rateList) через GSON AsyncTask. Вызов выполняется успешно. Затем я пытаюсь скопировать содержимое rateList в другой ArrayList, называемый globalRates. Оба списка определяются глобально.

Чтобы убедиться, что оба список будет заполнен, я вхожу печать размера списков из onPostExecute и возвращают 158.

Но как только я пытаюсь получить элемент из списка globalRates по методе OnCreate , моя программа выйдет из строя. Я попробовал блок try/catch, чтобы узнать, могу ли я получить немного больше информации, и ошибка отвечает NullPointerException. Я покажу свой журнал ниже.

Вот MainActivity класс:

public class PostsActivity extends Activity { 

// JSON info will be stored here through GSON 
public static List<GlobalRates> ratesList = new ArrayList<GlobalRates>(); 

// Trying to copy contents of ratesList into this ArrayList 
// Then trying to call an index from here on the onCreate method 
public static List<GlobalRates> globalRates; 

TextView view; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_posts); 

    view = (TextView) findViewById(R.id.textView1); 

    BitRateFetcher br = new BitRateFetcher(); 
    br.execute(); 

    // Error comes here. Error keeps saying 'NullPointerException' 
    try { 
     String name = globalRates.get(0).getName(); 
    } catch (NullPointerException ex) { 
     Log.e("BitRateFetcher", "Error: " + ex.fillInStackTrace()); 
     Log.e("BitRateFetcher", "Error: " + ex.getLocalizedMessage()); 
    } 

    // view.setText(name); 
} 

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    // Inflate the menu; this adds items to the action bar if it is present. 
    getMenuInflater().inflate(R.menu.posts, menu); 
    return true; 
} 

private void failedLoadingPosts() { 
    runOnUiThread(new Runnable() { 
     @Override 
     public void run() { 
      Toast.makeText(PostsActivity.this, 
        "Failed to load Posts. Have a look at LogCat.", 
        Toast.LENGTH_SHORT).show(); 
     } 
    }); 
} 

private class BitRateFetcher extends AsyncTask<Void, Void, String> { 
    private static final String TAG = "BitRateFetcher"; 
    public String BIT_PAY_SERVER = "https://bitpay.com/api/rates"; 

    private ProgressDialog dialog; 

    @Override 
    protected void onPreExecute() { 
     // Things to be done before execution of long running operation. For 
     // example showing ProgessDialog 
     super.onPreExecute(); 
     dialog = new ProgressDialog(PostsActivity.this); 
     dialog.setMessage("Please Wait... Downloading Information"); 
     dialog.show(); 
    } 

    @Override 
    protected String doInBackground(Void... params) { 
     try { 
      // Create an HTTP client 
      HttpClient client = new DefaultHttpClient(); 
      HttpGet getBitRates = new HttpGet(BIT_PAY_SERVER); 

      // Perform the request and check the status code 
      HttpResponse bitRatesResponse = client.execute(getBitRates); 

      StatusLine bitRatesStatus = bitRatesResponse.getStatusLine(); 

      if (bitRatesStatus.getStatusCode() == 200) { 
       HttpEntity entity = bitRatesResponse.getEntity(); 
       InputStream content = entity.getContent(); 

       try { 
        // Read the server response and attempt to parse it as 
        // JSON 
        Reader reader = new InputStreamReader(content); 
        Gson gson = new Gson(); 

        ratesList = Arrays.asList(gson.fromJson(reader, 
          GlobalRates[].class)); 

        content.close(); 
        entity.consumeContent(); 
       } catch (Exception ex) { 
        Log.e(TAG, "Failed to parse JSON due to: " + ex); 
        failedLoadingPosts(); 
       } 
      } else { 
       Log.e(TAG, "Server responded with status code: " 
         + bitRatesStatus.getStatusCode()); 
       failedLoadingPosts(); 
      } 
     } catch (Exception ex) { 
      Log.e(TAG, "Failed to send HTTP POST request due to: " + ex); 
      failedLoadingPosts(); 
     } 
     return null; 
    } 

    @Override 
    protected void onPostExecute(String result) { 
     // execution of result of Long time consuming operation 
     globalRates = new ArrayList<GlobalRates>(ratesList); 

     // This shows both lists are populated. 
     Log.i(TAG, "Bit Rates Connected"); 
     Log.i(TAG, "Rates List Size: " + ratesList.size()); 
     Log.i(TAG, "Global Rates Size: " + globalRates.size()); 

     if (dialog.isShowing()) { 
      dialog.dismiss(); 
     } 
    } 
} 

}

А вот "BitRateFetcher" Журнал:

04-20 22:13:55.626: E/BitRateFetcher(21097): Error: java.lang.NullPointerException 
04-20 22:13:55.626: E/BitRateFetcher(21097): Error: null 
04-20 22:13:56.206: I/BitRateFetcher(21097): Bit Rates Connected 
04-20 22:13:56.206: I/BitRateFetcher(21097): Rates List Size: 158 
04-20 22:13:56.206: I/BitRateFetcher(21097): Global Rates Size: 158 

То, что я в конечном итоге будет делать захватывает конкретный элемент из и передать его фрагменту через пучок (если это правильный способ сделать это).

Любые идеи относительно того, почему это происходит и как я могу это исправить? Я даже попытался вызвать элемент из списка тарифов, но он также разбился.

Спасибо за помощь!

EDIT: Чтобы узнать, помогает ли это больше, это немного больше информации о том, что я пытаюсь сделать. Когда пользователь нажимает на ListView в навигационном ящике, его номер позиции будет возвращен. Дополнительная информация содержится в комментариях в коде. Вот код:

private void displayView(int position) { 
    // update the main content by replacing fragments 
    Bundle bundle; 
    Fragment fragment = null; 
    String name; 

    switch (position) { 
    case 0: 

     // I want to get the name of a specific element depending on 
     // the position the user clicked. When i run the below line, it 
     // crashes and return the NullPointerException. globalRates is 
     // defined globally up top, similar to the code I pasted above. 
     name = globalRates.get(position).getName(); // <------ Crashes 

     // I will then pass the variable "name" into the bundle so 
     // that I can call it from the fragment. 
     bundle = new Bundle(); 
     bundle.putString("message", "Test " + position); 

     fragment = new CoinFragment(); 
     fragment.setArguments(bundle); 
     break; 
    case 1: 
     bundle = new Bundle(); 
     bundle.putString("message", "Litecoin Info"); 

     fragment = new CoinFragment(); 
     fragment.setArguments(bundle); 
     break; 
    case 2: 
     bundle = new Bundle(); 
     bundle.putString("message", "Peercoin Info"); 

     fragment = new CoinFragment(); 
     fragment.setArguments(bundle); 
     break; 
    case 3: 
     bundle = new Bundle(); 
     bundle.putString("message", "Dogecoin Info"); 

     fragment = new CoinFragment(); 
     fragment.setArguments(bundle); 
     break; 
    case 4: 
     bundle = new Bundle(); 
     bundle.putString("message", "Nxt Info"); 

     fragment = new CoinFragment(); 
     fragment.setArguments(bundle); 
     break; 
    case 5: 
     bundle = new Bundle(); 
     bundle.putString("message", "Namecoin Info"); 

     fragment = new CoinFragment(); 
     fragment.setArguments(bundle); 
     break; 

    default: 
     break; 
    } 

}

Оно не может быть надлежащим, но мне действительно нужно вызвать API через AsyncTask? Могу ли я просто реализовать новый поток и сделать то же самое?

+0

Вместо того, чтобы получать имя в первой позиции, попробуйте распечатать содержимое «Список» в цикле или распечатать его размер.Я знаю, что вы уже пробовали его в 'onPostExecute()', но ваша реализация кажется прекрасной. –

ответ

1

Вы должны переместить следующее в onPostExecute();

// Error comes here. Error keeps saying 'NullPointerException' 
try { 
    String name = globalRates.get(0).getName(); 
} catch (NullPointerException ex) { 
    Log.e("BitRateFetcher", "Error: " + ex.fillInStackTrace()); 
    Log.e("BitRateFetcher", "Error: " + ex.getLocalizedMessage()); 
} 

Почему?

Поскольку AsyncTask работает в фоновом режиме (другими словами, в другом потоке). И когда вы вызвали код выше, он все еще обрабатывался, поэтому список globalRates по-прежнему равен нулю.
Сначала убедитесь, что onPostExecute() вызывается перед использованием globalRates.
Когда вы звоните

BitRateFetcher br = new BitRateFetcher(); 
br.execute(); 

программа не будет ждать, пока AsyncTask не будет закончена перед переходом на следующую строку.
Надеюсь, теперь это ясно.

+0

Немного. Есть ли способ завершить обработку перед вызовом globalRates? В onCreate я выполнил инструкцию if/else if, чтобы проверить статус AsyncTask, и она всегда появляется. Я попробовал цикл while, чтобы распечатать статус, чтобы увидеть, изменится ли он, но он разбил мой телефон и перезапустил LOL! Вот что я хочу сделать. У меня будет оператор switch, который прослушивает щелчок списка. В зависимости от позиции он вызывается globalRates.get (position) .DataThatIWant. Я не уверен, что смогу сделать это в PostExecute. Вы видите, откуда я или нуждаюсь в дополнительной информации? @Lazy Ninja – AlwaysLearning

+0

Есть способы попытаться подождать в onCreate(), но это плохая практика. Предположим, что вы вызываете globalRates.get (position), когда запускается событие clickview, вместо того, чтобы делать это в onCreate. –

+0

Я отредактировал свое оригинальное сообщение. Если то, что вы упомянули, соответствует тому, что я добавил, то оно также падает. Я честно из идей здесь:/Спасибо за помощь, я действительно ценю это. @Lazy Ninja – AlwaysLearning

Смежные вопросы