Reputation: 37
So AsyncTask and I don't get along properly. I'm trying to understand better how its used.
So I keep running into this issue where I load a JSON API into an ArrayList (called ratesList) through GSON AsyncTask. The call is being made successfully. I then try to copy the ratesList content into another ArrayList called globalRates. Both lists are defined globally.
To insure that both lists are populated, I log print the size of the lists from the onPostExecute and both return 158.
But as soon as I try to get an element from the globalRates list on the onCreate method, my program crashes. I tried a try/catch block to see if I can get a little more info and the error responds with NullPointerException. I will show my log below.
Here is MainActivity class:
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();
}
}
}
}
And here is the "BitRateFetcher" log:
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
What I would eventually be doing is grabbing a specific element from the list and passing it to a fragment via bundle (if that's the right way to do it).
Any ideas as to why this is happening and how I can fix it? I even tried calling an element from ratesList but it also crashed.
Thanks for the help!
EDIT: To see if it helps out more, this is a little more info as to what I'm trying to do. When a user clicks on a ListView within a Navigation Drawer, its position number will be returned. More information is in the comments within the code. Here is the code:
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;
}
}
It may not be proper but do I really need to call the API through AsyncTask? Can I just implement a new thread and do the same thing?
Upvotes: 3
Views: 183
Reputation: 22527
You should move the following in the 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());
}
Why?
Because AsyncTask is running in the background (in other words in another thread). And when you called the code above, it was still processing hence globalRates list is still null.
First make sure that onPostExecute() is called before using globalRates.
When you call
BitRateFetcher br = new BitRateFetcher();
br.execute();
the program is not going to wait until the AsyncTask is finished before jumping to the next line.
Hope it is clear now.
Upvotes: 1