I am trying to parse JSON using Volley.
I am using a vector to store parsed data and calling adapter.notifyDataSetChanged() inside onCreate() after filling vector. But no changes are there.
If I am calling adapter.notifyDataSetChanged() inside try-catch block of getData() then it is working fine. Why?
public class MainActivity extends AppCompatActivity{
Vector<Data> ve;
private Adapter adapter;
RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView=(RecyclerView)findViewById(R.id.main_recycler_view);
ve=new Vector<Data>();
adapter=new Adapter(ve);
RecyclerView.LayoutManager lm=new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(lm);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(adapter);
getData(ve);
adapter.notifyDataSetChanged(); //not working
}
public void getData(final Vector<Data> ve)
{
String url = "https://api.androidhive.info/contacts/";
StringRequest request = new StringRequest(url, new Response.Listener<String>() {
#Override
public void onResponse(String jsonString) {
try
{
JSONObject object = new JSONObject(jsonString);
JSONArray arr = object.getJSONArray("contacts");
int len=arr.length();
JSONObject obj;
for (int i = 0; i < len; i++)
{
obj = arr.getJSONObject(i);
ve.add(new Data(obj.getString("name"), obj.getString("email"));
}
//adapter.notifyDataSetChanged();working
}
catch (JSONException e)
{
Toast.makeText(getApplicationContext(),"JSON Parsing Exception",Toast.LENGTH_LONG);
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(getApplicationContext(), "Some error occurred!!", Toast.LENGTH_SHORT).show();
}
});
RequestQueue rQueue = Volley.newRequestQueue(this);
rQueue.add(request);
}
}
you cannot do that reason nothing volley used network requests which are designed to be asynchronous in nature , so the network request is put in queue and code continues to execute the notifyadapter changed method . The response to the network call occurs afterwards and add data, you should call that method after data is received by calling it inside volley on response method
Related
I want to see my array list in my logcat but when I run my app in logcat it shows that size of my array list is zero and there is no elements in it
this is my activity
public class Tmp2 extends AppCompatActivity {
public RequestQueue queue;
static ArrayList<Question> array_list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tmp2);
array_list = new ArrayList<>();
queue= AppController.getInstance(this).getRequestQueue();
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET,
"https://raw.githubusercontent.com/curiousily/simple-quiz/master/script/statements-data.json",
(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((Boolean) response.getJSONArray(i).get(1));
array_list.add(question);
} catch (JSONException e) {
e.printStackTrace();
}
}Log.d("wakwash","array "+array_list.size());
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
Log.d("json","array "+array_list.size());
queue.add(jsonArrayRequest);
Log.d("json","array "+array_list);
}
}
Logcat:
2020-10-25 00:32:43.548 18576-18576/com.example.practice D/json: array 0
2020-10-25 00:32:43.548 18576-18576/com.example.practice D/json: array []
its showing that size of my array is zero and there is no element it but when i use this log in onResonse it gives sizeand elements both. How can I access my array list out of the response
This is because you are logging your array size at wrong place even before you're getting the response, you are making a call which is asynchronous but the log that you've written is executed in synchronous manner that will always be empty.
Log your data when your response is received i.e in onResponse callback.
public class Tmp2 extends AppCompatActivity {
public RequestQueue queue;
static ArrayList<Question> array_list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tmp2);
array_list = new ArrayList<>();
queue= AppController.getInstance(this).getRequestQueue();
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET,
"https://raw.githubusercontent.com/curiousily/simple-quiz/master/script/statements-data.json",
(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((Boolean) response.getJSONArray(i).get(1));
array_list.add(question);
} catch (JSONException e) {
e.printStackTrace();
}
}Log.d("wakwash","array "+array_list.size());
// Log it over here
Log.d("json","array "+array_list.size());
Log.d("json","array "+array_list);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
//Log removed from here
queue.add(jsonArrayRequest);
}
}
You have to do your work after the response is received rather than doing it outside of the response scope, You can also make a callback for your response.
I have two functions fetchData() and setDataUI(), in fetchData() i'm sending a request and saving the response. In setDataUI() function i'm setting adapter to bind the data's.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_gallery);
recyclerView = (RecyclerView) findViewById(R.id.image_recycler_view);
data_list = new ArrayList<>();
fetchData2(1);
}
fetchData2() to fetch data from server.
public void fetchData2(final int next){
String url = Constants.URL+"image/gallery?page="+next;
Log.d(TAG,"Data2 Url-->"+url);
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
Log.d(TAG, "Response-->" + response);
JSONObject jsonObject = new JSONObject(response);
JSONArray jsonArray = jsonObject.getJSONArray("media");
Log.d(TAG, "Media Array-->" + jsonArray);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject1 = jsonArray.getJSONObject(i);
ImageGallery imageGallery = new ImageGallery(
jsonObject1.getString("file"),
jsonObject1.getString("description"),
jsonObject.getInt("next"));
data_list.add(imageGallery);
Log.d(TAG, "Data List in AsyncTask-->" + data_list);
setDataUI();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(ActivityImageGallery.this, "Server Error!!!!", Toast.LENGTH_SHORT).show();
}
});
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
requestQueue.add(stringRequest);
}
then in setDataUI()
private void setDataToUI() {
gridLayoutManager = new GridLayoutManager(this,1);
recyclerView.setLayoutManager(gridLayoutManager);
Log.d(TAG,"Data_List-->"+data_list);
adapter = new AdapterImageGallery(this, data_list);
recyclerView.setAdapter(adapter);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (gridLayoutManager.findLastCompletelyVisibleItemPosition() == data_list.size()-1){
fetchData2(data_list.get(data_list.size()-1).getNext());
}
}
});
}
Expected Result:
function setDataUI() must only start when fetchData2() finishes execution completely. So, data_list in setDataUI() will have the values that are initialized in fetchData2().
Actual Result :
currently setDataUI() starts execution before fetchData2() completes its execution, resulting in data_list to be empty in setDataUI().
I do get the correct response from the server but after the setDataUI() is executed.
What you need to do is just change like below in your response method,
#Override
public void onResponse(String response) {
try {
if(response.isSuccessful){
Log.d(TAG, "Response-->" + response);
JSONObject jsonObject = new JSONObject(response);
JSONArray jsonArray = jsonObject.getJSONArray("media");
Log.d(TAG, "Media Array-->" + jsonArray);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject1 = jsonArray.getJSONObject(i);
ImageGallery imageGallery = new ImageGallery(
jsonObject1.getString("file"),
jsonObject1.getString("description"),
jsonObject.getInt("next"));
data_list.add(imageGallery);
Log.d(TAG, "Data List in AsyncTask-->" + data_list);
}
setDataToUI();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
-Put setDataToUI(); method call after completion of your for loop in onresponse.
-Also, your second method gets executed before your first method because, your first method is asynchronous (i.e., working on another thread. It's not executing in the Main Thread or UI thread).
Volleys' requests are aynchronous. So, you should call your setDataToUI from callback:
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// all your code
runOnUiThread(new Runnable() {
#Override
public void run() {
setDataToUI();
}
}
}
This is because in your fetchData() Async Task is running in background which you cannot predict how much time it will take. So rather than calling setDataToUI() after fetchData2() function you can just call it inside the response of the fetchData2() function. You can edit this in fetchData2 Function
data_list.add(imageGallery);
Log.d(TAG, "Data List in AsyncTask-->" + data_list);
setDataToUI()
this issue has been bugging me all day. I have stepped through the program with the debugger and it never goes into the Response.Listener. It doesn't go into onErrorResponse either so the API isn't throwing an error.
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_history_rewards);
prf = new PrefManager(this);
getSupportActionBar().setIcon(R.drawable.ic_back_icon);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(R.string.earning_history);
listView = (ListView) findViewById(R.id.list);
TextView emptyText = (TextView) findViewById(R.id.empty);
emptyText.setText(getString(R.string.no_rewards_yet));
adapter = new UserHistoryAdapter(EarningHistoryActivity.this, historyList);
listView.setAdapter(adapter);
listView.setEmptyView(emptyText);
listView.setDivider(null);
pDialog = new ProgressDialog(this);
pDialog.setMessage(getString(R.string.loading));
pDialog.show();
// changing action bar color
// getActionBar().setBackgroundDrawable(new ColorDrawable(Color.parseColor("#1b1b1b")));
JsonArrayRequest historyReq = new JsonArrayRequest(Config.Base_Url+"api/earning_history.php?username="+App.getInstance().getUsername(), new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
hidePDialog();
// Parsing json
for (int i = 0; i < response.length(); i++) {
try {
JSONObject obj = response.getJSONObject(i);
UserHistory history = new UserHistory();
history.setTitle(obj.getString("type"));
history.setRating(obj.getString("date"));
history.setThumbnailUrl(Config.Base_Url+"images/reward.png");
history.setYear(obj.getString("points"));
//history.setGenre(obj.getString("time"));
historyList.add(history);
} catch (JSONException e) {
e.printStackTrace();
}
}
// notifying list adapter about data changes
// so that it renders the list view with updated data
adapter.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
hidePDialog();
}
});
// Adding request to request queue
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(historyReq);
}
Any help would be greatly appreciated.
Edit: I added more code from the entire onCreate method to give some more information to help.
You have created historyReq object of class JsonArrayRequest;
Now there should be some method call inside JsonArrayRequest class which make utilize the Response.ErrorListener() object that you injected inside the historyReq. The injected objected inside historyReq should make use of on onErrorResponse method.
For more info you can see behavior of Anonymous class.
Im using volley to download the JSON data from a server, setting the Adapter within the function that reads and parses the data. However, the adapter is not being recognized. The problem is, I have successfully implemented the adapter in another activity with the same method without errors. The following is my code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
if (extras!=null) {
user_id = getIntent().getStringExtra("user_id");
} else {
Intent logIn = new Intent(JoinedActivity.this, LoginActivity.class);
startActivity(logIn);
}
setContentView(R.layout.activity_joined);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView1);
recyclerView.addItemDecoration(new SimpleDividerItemDecoration(this));
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
GetJoinedEvents();
}
public void GetJoinedEvents(){
String tag_string_req = "req_getJoinedEvents";
StringRequest stringRequest = new StringRequest(Request.Method.GET, Config.URL_USER_lIST_EVENTS+user_id, new Response.Listener<String>(){
#Override
public void onResponse(String response) {
// progressDialog.dismiss();
Log.i("responseTest",response);
try {
JSONObject jsonObject = new JSONObject(response);
JSONArray result = jsonObject.getJSONArray(Config.TAG_JSON_ARRAY);
int length = result.length();
HashMap<String, String> events;
for (int i = 0; i < length; i++) {
JSONObject jo = result.getJSONObject(i);
String event_id = jo.getString(Config.TAG_EVENT_ID);
String name = jo.getString(Config.TAG_EVENT_NAME);
String date = jo.getString(Config.TAG_EVENT_START_DT);
String weekday = jo.getString(Config.TAG_EVENT_WEEKDAY);
String event_type = jo.getString(Config.TAG_EVENT_TYPE);
events = new HashMap<>();
events.put(Config.TAG_EVENT_ID, event_id);
events.put(Config.TAG_EVENT_NAME, name);
events.put(Config.TAG_EVENT_START_DT, date);
events.put(Config.TAG_EVENT_WEEKDAY, weekday);
events.put(Config.TAG_EVENT_TYPE, event_type);
eventList.add(events);
}
listAdapter = new RecyclerViewAdapter(JoinedActivity.this,eventList, user_id);
recyclerView.setAdapter(listAdapter);
}
catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("Error", "Bad internet connection");
}
}) {};
AppController.getInstance().addToRequestQueue(stringRequest, tag_string_req);
Log.i("URL", stringRequest.toString());
}
}
A better approach to this is just to initialize the Recycler view and adapter on the onCreate. Then later on when you have the data you could create a swapItems method just for the purpose of changing the data within the recyclerview through the adapter, but in a way that both the RecyclerView and its adapter is instantiated as the activity starts.
on your swapItems you could do something like below:
public void swapItems(List<Events> eventList) {
if (eventList != null) {
this.items = eventList;
notifyDataSetChanged();// should call this to let the recyclerview know that our data set has changed
}
}
Then you could just call it via the activity by
listAdapter.swapItems(eventList);// this is done the moment you already got your list of events
I've been trying to get into android/java programming and I've been having issues understanding how to properly get the value of this json and parse it into the options to select in a spinner.
My json is like:
["Result1","Result2","Result3"]
My current code is like:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RequestQueue queue = Volley.newRequestQueue(this);
String url = "https://example.com/jsonfile.json";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,new Response.Listener<String>() {
#Override
public void onResponse(String response) {
//Do something with response
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
System.out.println(error.toString());
}
});
queue.add(stringRequest);
}
What would be the easiest way to get these values (Result1, Result2, Result3, etc.) into the spinner.entries?
Thanks in advance
Try this:
myString.replace("\"]","");
myString.replace("[\"","");
List<String> myList = new ArrayList<String>(Arrays.asList(s.split("\",\"")));
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(varRoot, android.R.layout.simple_spinner_item, myList);
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // The drop down vieww
mySpinner.setAdapter(spinnerArrayAdapter);
As per my knowledge you are sending json data in the wrong way.
If you want to send an array you have to place a jsonArray object in response with name to access that jsonArray.
Example
"cars":[ "Ford", "BMW", "Fiat" ]
Here, we are sending 3 car name in JsonArray of name "cars".
For accessing those entries:-
for (i in myObj.cars) {
carsArray += myObj.cars[i];
}
You need to make an assync call to get json data. Please refer the following tutorial
Android assync task example
and for parsing json data use Android json parsing example
#Override
public void onResponse(String response) {
//Do something with response
JSONArray jsonArray = new JSONArray(response);
for (int i = 0; i < array.length(); i++) {
array.put(jsonArray.getString(i));
}
}
add this on your activity's OnCreate() metod
ArrayAdapter<CharSequence> adapter =
ArrayAdapter.createFromResource(this, array,
android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
and put it
ArrayList<String> array = new ArrayList<String>();
Hello Try this if it may help
public class MainActivity extends AppCompatActivity {
Button btnCall;
final List<String> reviewList = new ArrayList<>();
List<String>resultList=new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnCall=(Button)findViewById(R.id.btnCall);
final String jArrStr="[\"Result1\",\"Result2\",\"Result3\"]";
btnCall.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
JSONArray jArry=new JSONArray(jArrStr);
for (int i = 0; i < jArry.length(); i++) {
String strArr=jArry.getString(0);
resultList.add(jArry.getString(i));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
}