I have a php page (urldisplay) returning this array of question objects:
[{
"suggestid": "1",
"question": "What does Aotearoa mean?",
"answer1": "Maui and the Whale",
"answer2": "2 Islands",
"answer3": "Land of the Long White Cloud",
"answer4": "Isle of Greenstone",
"correctanswer": "Land of the Long White Cloud",
"userID": "1"
}, {
"suggestid": "2",
"question": "What does Haere Ra mean?",
"answer1": "Hello",
"answer2": "Goodbye",
"answer3": "Thanks",
"answer4": "Sorry",
"correctanswer": "Goodbye",
"userID": "1"
}, {
"suggestid": "3",
"question": "Where is Zealand?",
"answer1": "France",
"answer2": "Germany",
"answer3": "Denamrk",
"answer4": "Finland",
"correctanswer": "Denmark",
"userID": "1"
}, {
"suggestid": "4",
"question": "What does Aotearoa mean?",
"answer1": "Maui and the Whale",
"answer2": "2 Islands",
"answer3": "Land of the Long White Cloud",
"answer4": "Isle of Greenstone",
"correctanswer": "Land of the Long White Cloud",
"userID": "2"
}, {
"suggestid": "5",
"question": "What does Aotearoa mean?",
"answer1": "Maui and the Whale",
"answer2": "2 Islands",
"answer3": "Land of the Long White Cloud",
"answer4": "Isle of Greenstone",
"correctanswer": "Land of the Long White Cloud",
"userID": "3"
}]
I am trying to read the objects via this class (in my DAO class) which saves the results to an array list of questions
ArrayList<Question> quest;
public ArrayList<Question> ListSugg()
{
ListSuggestions sugg = (ListSuggestions)new ListSuggestions().execute();
return quest;
}
public class ListSuggestions extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
try {
URL url = new URL(urldisplay);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
JSONArray jsonArray = new JSONArray(con);
quest = new ArrayList<Question>();
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String question = jsonObject.getString("question");
String answer1 = jsonObject.getString("answer1");
String answer2 = jsonObject.getString("answer2");
String answer3 = jsonObject.getString("answer3");
String answer4 = jsonObject.getString("answer4");
String correctanswer = jsonObject.getString("correctanswer");
Question ques = new Question(0, question, answer1, answer2, answer3, answer4, correctanswer);
quest.add(ques);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e1) {
e1.printStackTrace();
}
return null;
}
}
quest stays empty though. I then want to add the question objects to a ListView.
public class ListActivity extends AppCompatActivity {
ListView listv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
listv = (ListView)findViewById(R.id.ListDisplay);
DAO dao = new DAO();
ArrayList list = dao.ListSugg();
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_1,
list );
listv.setAdapter(arrayAdapter);
}
I've tried a bunch of other SO posts but I seem to be chasing my tail. Can anyone spot my mistakes/is there a better way for me to do this?
Cheers,
The issue is that AsyncTask executes code Asunchrounsly, meaning that when you call ListSugg()
, it will run the background task on another thread and return you the quest object before the background quest is finished, meaning you'll have a still empty list. read here for more info
What you can do, is that you override the onPostExecute
method, and set the adapter there, like so:
public class ListSuggestions extends AsyncTask<Void, Void, Void> {
@Override
protected Boolean doInBackground(String... params) {
// do something
return true;
}
@Override
protected void onPostExecute(String result) {
// The results of the above method
// Processing the results here
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_1,
list);
listv.setAdapter(arrayAdapter);
}
}
But for this to work, you need to include your AsyncTask inside the MainActivity.
This should solve your issue, hope it helps.
However, there are much better and simpler solutions like using an HTTP networking library like okhttp or Retrofit, and using a JSON parser like Gson, you can check them out if you'd like.
You are returning ques
as soon as you fire the background task. The background task will take some time to finish and till then your ques
list will remain null so you will not see data.
Update the list in the postExecute
method of AsyncTask.
try this
quest = new ArrayList<Question>();
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
Question ques = new Question(); //inti Question
//Enter Values to Question Object
ques.setQuestion( jsonObject.getString("question"));
ques.setAnswer1( jsonObject.getString("answer1"));
ques.setAnswer2( jsonObject.getString("answer2"));
ques.setAnswer3( jsonObject.getString("answer3"));
ques.setAnswer4( jsonObject.getString("answer4"));
ques.setCorrectAnswer( jsonObject.getString("correctanswer"));
// Add Question Object to ArrayList
quest.add(ques);
}
It is empty because you are returning null from the doInBackground(). The ideal way is to pass the result to onPostExecute() and set the adapter there.Like this :-
public class ListSuggestions extends AsyncTask<Void, Void, ArrayList<Question>> {
@Override
protected ArrayList<Question> doInBackground(Void... params) {
try {
URL url = new URL(urldisplay);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
//JSONArray jsonArray = new JSONArray(con);
quest = new ArrayList<Question>();
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String question = jsonObject.getString("question");
String answer1 = jsonObject.getString("answer1");
String answer2 = jsonObject.getString("answer2");
String answer3 = jsonObject.getString("answer3");
String answer4 = jsonObject.getString("answer4");
String correctanswer = jsonObject.getString("correctanswer");
Question ques = new Question(0, question, answer1, answer2, answer3, answer4, correctanswer);
quest.add(ques);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e1) {
e1.printStackTrace();
}
return quest;
}
@Override
protected void onPostExecute(ArrayList<Question> questions) {
super.onPostExecute(questions);
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_1,
list );
listv.setAdapter(arrayAdapter);
}
}