This is a simple program to gain the JSON data from the internet. answerWithAsyncTask() is an interface that ensures that all the downloaded data will only be added to questionArrayList when the download is complete.
Error: java.lang.IndexOutOfBoundsException: Index: 1, Size: 0
private List<Question> questionList;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Few findViewbyId's here. Ignoring them
questionList = new QuestionBank().getQuestions(new answerWithAsyncTask() {
#Override
public void asyncMe(ArrayList<Question> questionArrayList) {
questionTextview.setText(questionArrayList.get(currentQuestionIndex).getQuestionId());
}
});
updateQuestion(); //This is the newly added line
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.prev_button:
updateQuestion();
break;
}
}
private void updateQuestion() {
String question = questionList.get(1).getQuestionId();
questionTextview.setText(question);
}
UPDATE This is my getQuestions method.
String url ="https://raw.githubusercontent.com/curiousily/simple-quiz/master/script/statements-data.json";
private ArrayList<Question> questionArrayList= new ArrayList<>();
public List<Question> getQuestions (final answerWithAsyncTask callback){
JsonArrayRequest jsonArrayRequest =new JsonArrayRequest(Request.Method.GET, url, (String) null,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
for(int i=0;i<response.length();i++){
Question question = new Question();
try {
question.setQuestionId(response.getJSONArray(i).getString(0));
question.setTorF(response.getJSONArray(i).getBoolean(1));
questionArrayList.add(question);
} catch (JSONException e) {
e.printStackTrace();
}
}
if(null != callback) callback.asyncMe(questionArrayList);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
AppController.getInstance().addToRequestQueue(jsonArrayRequest);
return questionArrayList;
}
and this my interface answerWithAsyncTask
public interface answerWithAsyncTask {
void asyncMe(ArrayList<Question> arrayList);
}
You are getting this error because
private List<Question> questionList;
is empty. In your first code, you are not getting any error because you are not calling updateQuestion() which will try to fetch data from an empty list. The error is in 2nd code because it's trying to access that empty list. Your
return questionArrayList;
is not returning data to questionList. Here, you are trying to do interface callback, to implement it properly, please look at this answer and change your code accordingly,
Java Interface Callback
Related
i am new to Android,here is class Question bank returns list of json obj received from an api
ArrayAsyncResponse in interface containing only one method process complete ,i readed that http request is asynchronous but unable to relate
Question is model class
case 1) when there is no ArrayAsyncResponse interface exist and i return the list to main activity and print it it shows empty list but when i make call to callback.processComplete() and then return list followed by printing ,it shows data
case2 )if i pass null in this function callback.processComplete() then again returned list is empty
so what basically Interface is helping us
public class QuestionBank {
ArrayList questionArrayList = new ArrayList<>();
private String url = "https://raw.githubusercontent.com/curiousily/simple-quiz/master/script/statements-data.json";
public List<Question> getQuestions(final AnswerListAsyncResponse callBack) {
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(
Request.Method.GET,
url,
(JSONArray) null,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
for (int i = 0; i < response.length(); i++) {
try {
Question question = new Question();
question.setAnswer(response.getJSONArray(i).get(0).toString());
question.setAnswerTrue(response.getJSONArray(i).getBoolean(1));
//Add question objects to list
questionArrayList.add(question);
//Log.d("Hello", "onResponse: " + question.getAnswer());
// Log.d("JSON", "onResponse: " + response.getJSONArray(i).get(0));
//Log.d("JSON2", "onResponse: " + response.getJSONArray(i).getBoolean(1));
} catch (JSONException e) {
e.printStackTrace();
}
}
if (null != callBack) callBack.processFinished(questionArrayList);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
AppController.getInstance().addToRequestQueue(jsonArrayRequest);
return questionArrayList;
}
public class MainActivity extends AppCompatActivity {
private QuestionBank questionBank;
List<Question> questionList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
questionBank=new QuestionBank();
questionList=questionBank.getQuestions(new AnswerListAsyncResponse() {
#Override
public void processFinished(ArrayList<Question> questionsArrayList) {//this function triggers when response is received from api
Log.d("inside", "processFinished: "+questionsArrayList);
}
});
Log.d("sync response", "questionLIst: "+questionList);
}
}
Sorry I can't write this in comment, but I think I can help you.
I don't understand well your question. but I think you need to get a Listener of the async in your class activity.
You can do that with EventBus, like this : https://github.com/greenrobot/EventBus
I'm trying to initialize a global ArrayList from within a listener (to deal with JSONArray objects from the Volley library in different places of the code). However, when I try to access it in the Oncreate method it seems to be uninitialized.
I tried the same with different static and non-static variables i.g. int[], String, etc. but the problem seems to persist.
NOTE:
The Question class is used for app development purposes:
public class Question {
private String question;
private boolean answer;
public Question(String question, boolean answer){
this.question = question;
this.answer = answer;
}
public String getQuestion() {
return question;
}
public boolean isAnswer() {
return answer;
}
}
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private String url = "https://raw.githubusercontent.com/curiousily/simple-quiz/master/script/statements-data.json";
private static ArrayList<Question> questionArrayList = new ArrayList<>();
int [] intArr = new int[10];
String str = "Hello";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// calling the method where the variables are re-initialized
getQuestions();
// printing results after re-initialization
System.out.println("Mainactivity======================");
System.out.println("intArray: "+ intArr[0]);
System.out.println("STR: "+ str);
System.out.println(questionArrayList.get(0).getQuestion());
}
public void getQuestions(){
JsonArrayRequest arrayRequest = new JsonArrayRequest(Request.Method.GET, url, null,
new Response.Listener<JSONArray>() {
// Response Listener
#Override
public void onResponse(JSONArray response) {
// Test variables:
MainActivity.this.intArr[0] = 110;
str = "HI";
for(int i=0; i< response.length(); i++){
try {
// initializing ArrayList<Question>
questionArrayList.add(new Question(response.getJSONArray(i).getString(0), response.getJSONArray(i).getBoolean(1) ));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
RequestQueue queue = Volley.newRequestQueue(this);
queue.add(arrayRequest);
}
}
output:
I/System.out: Mainactivity======================
I/System.out: intArray: 0
STR: Hello
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: myapp.com.triviaapp, PID: 29167
java.lang.RuntimeException: Unable to start activity ComponentInfo{myapp.com.triviaapp/myapp.com.triviaapp.MainActivity}: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
The String is getting modified by the listener, however the listener is getting executing at some later point in time, after onCreate has finished. If you add a second log within the listener you will see that it gets called afterwards. This is because the listener doesn't get executed until it gets a response from the network, which will always take longer than it will take for onCreate to finish executing
System.out.println(questionArrayList.get(0).getQuestion()); <- here you getting crash, because array list is empty.
You can put printing information after getting result:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// calling the method where the variables are re-initialized
getQuestions();
}
#Override
public void onResponse(JSONArray response) {
// Test variables:
MainActivity.this.intArr[0] = 110;
str = "HI";
for(int i=0; i< response.length(); i++){
try {
// initializing ArrayList<Question>
questionArrayList.add(new Question(response.getJSONArray(i).getString(0), response.getJSONArray(i).getBoolean(1) ));
} catch (JSONException e) {
e.printStackTrace();
}
}
System.out.println("Mainactivity======================");
System.out.println("intArray: "+ intArr[0]);
System.out.println("STR: "+ str);
if (!questionArrayList.isEmpty()) { // and check if we have at least one element
System.out.println(questionArrayList.get(0).getQuestion());
}
}
I store data with sqlite database from remote server with AsyncTask..
I have used Retrofit to fetch data, and now I want to store that data into sqlite... I already have DatabaseHelper.class , Model Class and NavigationDrawer in that i am performing AsynckTask in MainActivity.
private class getDataToSqlite extends AsyncTask<Post, Void, Void>{
#Override
protected Void doInBackground(Post... params) {
apiInterface.getContacts().enqueue(new Callback<List<Post>>() {
#Override
public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
if (response.isSuccessful()){
contacts = response.body();
for (int i=0; i < contacts.size(); i++){
Post post = contacts.get(i);
SaveToDatabase task = new SaveToDatabase();
task.execute(post);
adapter.addPost(post);
}
}else {
}
}
#Override
public void onFailure(Call<List<Post>> call, Throwable t) {
Toast.makeText(getApplicationContext(), "Error" + t.toString(), Toast.LENGTH_SHORT).show();
}
});
return null ;
}
}
private class SaveToDatabase extends AsyncTask<Post, Void , Void> {
#Override
protected Void doInBackground(Post... params) {
Post post = params[0];
try {
myDb.addData(post);
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
return null;
}
}
That class present in MainActivity
and i call the class in onCreate
new getDataToSqlite();
where i doing wrong please tell me
You can do something like this that I have already Done :
public boolean SyncCityMasterToDevice() {
try {
DatabaseHandler db = new DatabaseHandler(mContext);
db.dbDelete(TableCityMaster.TABLE);
List<CityMaster> cityMasterList = ServerRepo.getCities();
db.dbAddCity(cityMasterList);
Log.d(TAG, "SyncCityMasterToDevice: ");
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
ServerRepo.getCities(); is a Retrofit Call.
I have called SyncCityMasterToDevice() method in an Async task
`DatabaseHandler` is the Database Helper Class.
Inside my Fragment onCreateView method I have call a method named getData() which has implemented to get some data as json response from server using android volley library.
getData() method :
public void getData(MyCustomListener<CompleteCartProItem> customListener) {
if (MyApplication.getAndroidSession().getAttribute("cart") != null) {
Log.i("cart_null", "NOT null");
RequestQueue requestQueue = VolleySingleton.getsInstance().getRequestQueue();
CartDetails cartDetails = (CartDetails) MyApplication.getAndroidSession().getAttribute("cart");
ArrayList<CartItem> jsonSendArray = cartDetails.getShoppingList();
final String jsonString = new Gson().toJson(jsonSendArray,
new TypeToken<ArrayList<CartItem>>() {
}.getType());
Log.i("json_object", jsonString);
String url = "http://10.0.2.2:8080/ECommerceApp/getAllProductsAction";
JsonArrayRequest arrayRequest = new JsonArrayRequest(Request.Method.GET, url,
response -> {
List<CompleteCartProItem> completeCart = new Gson().fromJson(response.toString(),
new TypeToken<List<CompleteCartProItem>>() {
}.getType());
Log.i("response", completeCart.get(0).getP_name());// successfully prints out the 0th product name.
customListener.onResponse(completeCart);
}, error -> Log.i("Volley_error", error.getMessage())) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("Content-Type", "application/json");
params.put("cartList", jsonString);
return params;
}
};
arrayRequest.setRetryPolicy(new RetryPolicy() {
#Override
public int getCurrentTimeout() {
return 5000;
}
#Override
public int getCurrentRetryCount() {
return 5000;
}
#Override
public void retry(VolleyError error) throws VolleyError {
}
});
requestQueue.add(arrayRequest);
} else {
Log.i("cart_null", "null");
}
}
Inside onCreateView :
...
getData(new MyCustomListener<CompleteCartProItem>() {
#Override
public void onResponse(List<CompleteCartProItem> response) {
completeCartProItems.addAll(response);
Log.i("executed", "Inside_onResponse");
Log.i("check", completeCartProItems.get(0).getP_name());
}
#Override
public void onError(String error_response) {
}
});
cart_item_scrollerAdapter = new CartItem_ScrollerAdapter(getActivity(), completeCartProItems);//completeCartProItems is an ArrayList of CompleteCartProItem (private List<CompleteCartProItem> completeCartProItems = new ArrayList<>();)
...
As you can see I m calling getData() before initializing the Adapter. But CartItem_ScrollerAdapter(...) constructor is calling before the getData() method here.
Constructor of CartItem_ScrollerAdapter(...) :
public CartItem_ScrollerAdapter(Context context, List<CompleteCartProItem> completeCartProItems) {
this.inflater = LayoutInflater.from(context);
this.context = context;
this.completeCartProItems = completeCartProItems;
Log.i("executed","Adapter");
}
As you can see Log.i("executed", "Inside_onResponse"); inside the getData() method is displays in the log cat after displaying the Log.i("executed","Adapter"); which is inside CartItem_ScrollerAdapter(...) . I havent initialize it anywhere before this. So that cause my completeCartProItems ArrayList passing to the constructor of CartItem_ScrollerAdapter(...) always empty.Any suggestions to get rid of this issue would be appreciable. Thank you.
Initialize the adapter before calling getData(). And when data is received, add it into ArrayList and call adapter's notifyDataSetChanged();
// completeCartProItems should be initialized before passing it into adapter.
cart_item_scrollerAdapter = new CartItem_ScrollerAdapter(getActivity(), completeCartProItems);
// Set your adatper here...
cart_horizontal_scroller.setAdapter(cart_item_scrollerAdapter);
getData(new MyCustomListener<CompleteCartProItem>() {
#Override
public void onResponse(List<CompleteCartProItem> response) {
completeCartProItems.addAll(response);
cart_item_scrollerAdapter.notifyDataSetChanged();
Log.i("executed", "Inside_onResponse");
Log.i("check", completeCartProItems.get(0).getP_name());
}
#Override
public void onError(String error_response) {
}
});
Let's say I have this Dashboard.java:
public class DashboardActivity extends ActionBarActivity {
private TextView login_response;
private static String TAG = DashboardActivity.class.getSimpleName();
final static String API_URL_ACCOUNT = "http://www.example.com/apiv2/account";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dashboard);
login_response = (TextView) findViewById(R.id.login_response);
Intent intent = getIntent();
if(intent.hasExtra("TOKEN"))
{
String token = intent.getStringExtra("TOKEN");
getShopName(token);
}
else
{
}
And this is the getShopName method:
private void getShopName(String token) {
JsonObjectRequest req = new JsonObjectRequest(API_URL_ACCOUNT + "?token=" + token, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
VolleyLog.v("Response:%n %s", response.toString(4));
JSONArray account = response.getJSONArray("account");
//Log.d(TAG, "Account: "+account.toString());
JSONObject shop = account.getJSONObject(0);
String name_shop = shop.getString("name_shop");
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.e("Error: ", error.getMessage());
}
});
// add the request object to the queue to be executed
VolleyController.getInstance().addToRequestQueue(req);
}
My goal is to have
if(intent.hasExtra("TOKEN"))
{
String token = intent.getStringExtra("TOKEN");
String shop_name = getShopName(token);
}
The "shop_name" in variable, to reuse in other part.
So, I know that void doesn't return nothing, but, I tried to edit like this answer, without success:
How can I return value from function onResponse of Volley?
Thank you
The issue is not returning a value from a JsonObjectRequest, but rather that you're trying to do an asynchronous operation in a synchronous way.
Here is a great explanation: Asynchronous vs synchronous execution, what does it really mean?
And to your specific question: I advise using an AsyncTask for your network operation.