Parse JSON data into a ListView - android

I know that there are several similar questions already answered, but because the fact that I'm very new to Android development, I couldn't figure out how to solve this on my own. The question is pretty self-explanatory. I'm fetching data from the database over HTTP request and want to adapt that data into a listview. I'm using Volley for my HTTP requests and underneath is my onResponse -method.
Everything else works perfectly, I just haven't found a way to adapt that data into a listview.
#Override
public void onResponse(String response) {
Log.d(TAG, response.toString());
// If we are getting success from server
try {
JSONObject jObject = new JSONObject(response);
int count = jObject.getInt("count");
if(count == 0) {
noEventsTextView.setText(jObject.getString("msg").toString());
noEventsTextView.setGravity(Gravity.CENTER);
noEventsImageView.setVisibility(View.VISIBLE);
} else {
JSONArray childArray = jObject.getJSONArray("lectures");
for(int i = 0; i < childArray.length(); i++) {
JSONObject finalObject = childArray.getJSONObject(i);
// TODO Adapt data to listView
}
}
} catch(JSONException e) {
e.printStackTrace();
}
}
}
And here's an example of JSON I get back from the server:
{
count: 2,
msg: "",
lectures: [
{
id: "1",
starting_at: "2015-11-30 13:00:00",
ending_at: "2015-11-30 15:00:00",
user_id: "1",
course: "Course #1",
user_name: "John Doe"
},
{
id: "2",
starting_at: "2015-11-30 13:00:00",
ending_at: "2015-11-30 15:00:00",
user_id: "1",
course: "Course #2",
user_name: "John Doe"
}
]
}

Create a class of each key value pairs of Json and the map your json to that class using Jackson and the add generic list of that class to your List Adapter .
Like
Custom Class{
String id;
String starting_at;
String ending_at;
String user_id;
String course ;
String username;
}
Map your response through Jackson to ArrayList
and then
ListAdapter(ArrayList)
https://w2davids.wordpress.com/android-json-parsing-made-easy-using-jackson/
and you are ready to go.......you can use gson also but jackson is a bit faster so you can go for anyone according to ur need......
hope it helps.

create array Variables for each key value pairs of Json.
and pass all those variable to a listview.
new Listadapter(this,id[],starting_at[],ending_at[],user_id[],course[],username[]);
or There is a concept called Gson.
which will allow you to write data to Serializable class without using array.
And after assigning data to these class you can pass the Serializable class to adapter and used it inside adapter getView method.
There is a simple tutorial on this which I wrote to assign data to serializable class, think it will give you an idea.
hope it helps.

You can have a POJO consisting of all the keys a lecture has.
DataPOJO.java
public class DataPOJO {
private int id;
private String starting_at;
private String ending_at;
private String user_id;
private String course;
private String user_name;
}
Inside your onResponse:
#Override
public void onResponse(String response) {
Log.d(TAG, response.toString());
// If we are getting success from server
try {
JSONObject jObject = new JSONObject(response);
int count = jObject.getInt("count");
if(count == 0) {
noEventsTextView.setText(jObject.getString("msg").toString());
noEventsTextView.setGravity(Gravity.CENTER);
noEventsImageView.setVisibility(View.VISIBLE);
} else {
JSONArray childArray = jObject.getJSONArray("lectures");
ArrayList<DataPOJO> datas = new ArrayList<DataPOJO>();
for(int i = 0; i < childArray.length(); i++) {
JSONObject finalObject = childArray.getJSONObject(i);
DataPOJO data = new DataPOJO;
data.id = finalObject.getInt("id");
data.starting_at = finalObject.getString("starting_at");
//so on
//add data to arraylist......
datas.add(data);
}
//set adapter of your listview here, you have to have an instance of your list view
listView.setAdapter(new MyAdapter(datas, context));
}
} catch(JSONException e) {
e.printStackTrace();
}
}
}
MyAdapter.java
public class MyAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<DataPOJO> listItem;
public MyAdapter(Context mContext, ArrayList<DataPOJO> listItem) {
this.mContext = mContext;
this.listItem = listItem;
}
#Override
public int getCount() {
return listItem.size();
}
#Override
public Object getItem(int position) {
return listItem.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null)
convertView = LayoutInflater.from(mContext).inflate(R.layout.list_items, null);
((TextView) convertView.findViewById(R.id.name)).setText(listItem.get(position).user_name);
return convertView;
}
}
list_items.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#000"
android:textSize="18sp"/>
</RelativeLayout>

Related

How to Show only first 5 elements of Array List in RecyclerView?

Hello, I am trying to Load only first 5 elements which I am fetching from an API . Currently, it is fetching all Items.
This is my current code which displays all items :
This is the Adapter code (i am not posting unnecessary methods)
Context mCtx;
List<VolleyModel> volleyModelList;
public VolleyAdapter(Context mCtx, List<VolleyModel> volleyModelList) {
this.mCtx = mCtx;
this.volleyModelList = volleyModelList;
}
#Override
public int getItemCount() {
return volleyModelList.size();
}
This is the Activity code :
List<VolleyModel> volleyModelList;
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET, URL, null, response -> {
for (int i = 0; i < response.length(); i++) {
try {
JSONObject jsonObject = response.getJSONObject(i);
String id = jsonObject.getString("id");
authorName = insideAuthorArray.getString("name");
volleyModelList.add(new VolleyModel(id, authorName));
volleyAdapter.notifyDataSetChanged();
progressBarLoadMore.setVisibility(View.GONE);
} catch (JSONException e) {
e.printStackTrace();
Log.e("ERROR HomeFragment", e.getMessage());
}
volleyAdapter = new VolleyAdapter(getActivity(), volleyModelList);
recyclerView.setAdapter(volleyAdapter);
The above code properly displays every result which is returned by the server. What should I do so get only the first 5 items ?
Just modify this method inside your adapter code:
#Override
public int getItemCount() {
int size = volleyModelList.size();
// Return at most 5 items from the ArrayList
return (size > 5 ? 5 : size);
}
try it like this , it will only show 5 items
#Override
public int getItemCount() {
//return volleyModelList.size();
return 5;
}

Recyclerview json data binding has failed

I am trying to bind JSON data on to the recyclerView , but data seems not to bind to the RecyclerView.
Surprisingly when i Toast the data i see it's available. What could be the problem?
private void parseJson(String result){
try {
if (result!=null) {
String resultTostring = "" + result;
JSONObject obj = new JSONObject(resultTostring).getJSONObject("ScheduleResource");
JSONArray arr = obj.getJSONArray("Schedule");
itemList = new ArrayList<>();
for (int i = 0; i < arr.length(); i++)
{
String DepartureAirport = arr.getJSONObject(i).getJSONObject("Flight").getJSONObject("Departure").getString("AirportCode");
String ArrivalAirport = arr.getJSONObject(i).getJSONObject("Flight").getJSONObject("Arrival").getString("AirportCode");
String Duration = arr.getJSONObject(i).getJSONObject("TotalJourney").getString("Duration");
String DepartureTime = arr.getJSONObject(i).getJSONObject("Flight").getJSONObject("Departure").getJSONObject("ScheduledTimeLocal").getString("DateTime");
String ArrivalTime = arr.getJSONObject(i).getJSONObject("Flight").getJSONObject("Arrival").getJSONObject("ScheduledTimeLocal").getString("DateTime");
String Stops = arr.getJSONObject(i).getJSONObject("Flight").getJSONObject("Details").getJSONObject("Stops").getString("StopQuantity");
FlightModel model = new FlightModel();
model.setDepartureAirport(DepartureAirport);
model.setArrivalAirport(ArrivalAirport);
model.setDuration(Duration);
model.setDeparturTimee(DepartureTime);
model.setArrivalTime(ArrivalTime);
model.setStops(Stops);
model.Stops= Stops;
itemList.add(model);
Toast.makeText(FlightListActivity.this, "DEPT : " + DepartureAirport + " Arrival " + ArrivalAirport+
" Duration : " + Duration + " Dept time : "+ DepartureTime+" Arr Time "+ ArrivalTime
+" Stops "+ Stops, Toast.LENGTH_LONG).show();
}
// Setup and Handover data to recyclerview
final FlightAdapter adapter = new FlightAdapter(FlightListActivity.this, itemList);
flights_rv.setAdapter(adapter);
flights_rv.setLayoutManager(new LinearLayoutManager(FlightListActivity.this));
}
else{
Toast.makeText(FlightListActivity.this,Config.POOR_NETWORK_CONNECTION, Toast.LENGTH_LONG).show();
}
}
catch (JSONException r){
System.out.println("ERROR PROB : "+ r);
// Toast.makeText(ListOfFlights.this,"ERROR PROB : "+ r,Toast.LENGTH_LONG).show();
}
}
In my Adapter i have attached the Layout which will have the appearance of the data in the List , and also my POJO class is set which has both getters and setters, but when i try to attach the adapter on to the RecyclerView the data doesn't bind why ?
EDIT
My Adapter Class
public class FlightAdapter extends RecyclerView.Adapter<FlightHolder> {
private List<FlightModel> itemList= Collections.emptyList();
private Context context;
public FlightAdapter(Context context,List<FlightModel> itemList) {
this.context = context;
this.itemList = itemList;
}
#Override
public FlightHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.new_details, parent, false);
FlightHolder rcv = new FlightHolder(layoutView, context);
return rcv;
}
#Override
public void onBindViewHolder(FlightHolder holder, int position) {
final FlightModel sr = itemList.get(position);
final String DepartureAirport = sr.getDepartureAirport();
final String ArrivalAirport = sr.getArrivalAirport();
final String Duration = sr.getDuration();
final String DepartureTime = sr.getDeparturTimee();
final String ArrivalTime = sr.getArrivalTime();
final String Stops = sr.getStops();
final String DirectFlight = sr.getDirectFlights();
holder.from_txt.setText(DepartureAirport);
holder.to_txt.setText(ArrivalAirport);
holder.duration_txt.setText(Duration);
holder.depature_txt.setText(DepartureTime);
holder.arrival_txt.setText(ArrivalTime);
holder.stops_txt.setText(Stops);
holder.dept_txt.setText(DepartureAirport);
holder.arr_txt.setText(ArrivalAirport);
holder.root.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Intent i = new Intent(FlightAdapter.this.context, DetailsLocalLeader.class);
// context.startActivity(i);
}
});
}
#Override
public int getItemCount() {
;
return itemList.size();
}
}
For more information , below is the link to the project :
https://github.com/huxaiphaer/FlightsApp/blob/master/app/src/main/java/adapter/FlightAdapter.java
First of all, get someone to review your code structure. Read and understand Java Standard Naming Conventions. Use a design pattern for your app, probably MVP. Use Gson library to parse JSON data for you.
To answer your question, I would say that your JSON structure is flawed. Your code outputs this error
ERROR PROB : org.json.JSONException: Value "SOME_LONG_JSON" at Flight of type org.json.JSONArray cannot be converted to JSONObject
It means that you are trying to parse a JSONArray as a JSONObject. In the Schedule array, there's 9th entry which is supposed to be a JSONObject(as seen in previous 8 entries). But, it is a JSONArray.
So, first 8 entries are like:
{
"Departure": {},
"Arrival": {},
"MarketingCarrier": {},
"Equipment": {},
"Details": {}
}
and, the 9th entry is like :
[
{
"Departure": {},
"Arrival": {},
"MarketingCarrier": {},
"Equipment": {},
"Details": {}
},
{
"Departure": {},
"Arrival": {},
"MarketingCarrier": {},
"Equipment": {},
"Details": {}
}
]
That's why you get this parsing exception in try-catch block. So, you can do this to check if your object is JSONArray or JSONObject like this in parseJson(String result):
Object departureObject = arr.getJSONObject(i).getJSONObject("Flight").get("Departure");
if (departureObject instanceof JSONObject) {
String departureAirport = ((JSONObject) departureObject).getString("Airport");
}
else if (departureObject instanceof JSONArray) {
JSONArray departures = (JSONArray) departureObject;
// use for-loop here to get data from array
}
But, seriously, use POJO with Gson and simplify parsing process. Also, if you have control over how API works, try to keep an object of one type only. If it is supposed to be a list, it better be a list even if there are no items or if there's one or more.
Try these things, it might solve this problem, but I doubt it. You will face more problems with parsing I think. Ping me after you've done this.
Also, if you try to parse all of JSON received by Server, you will see that it is not even complete. Look at the end of your JSON data.
Try something like this for your adapter:
public class FlightAdapter extends RecyclerView.Adapter<FlightAdapter.MyViewHolder> {
private List<FlightModel> mItemList;
private Context context;
public class MyViewHolder extends RecyclerView.ViewHolder {
//TODO: Add all your views and the types hear!
Public TextView mTvName;
public MyViewHolder(View v){
super(v);
//TODO: add here for each view in your row
mTvName = (TextView)v.findViewById(R.id.tvName);
}
}
public FlightAdapter(Context context,List<FlightModel> itemList) {
this.context = context;
this.mItemList = itemList;
}
#Override
public FlightHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.new_details, parent, false);
return new MyViewHolder(layoutView);
}
#Override
public void onBindViewHolder(FlightHolder holder, int position) {
FlightModel model = mItemList.get(position);
//TODO: Add for each view and data point!!
String name = model.getName();
holder.mTvName.setText(name);
holder.layoutView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Intent i = new Intent(FlightAdapter.this.context, DetailsLocalLeader.class);
// context.startActivity(i);
}
});
}
#Override
public int getItemCount() {
return mItemList.size();
}
}
Disclaimer!
I typed this in a text editor, so there might be a few syntax errors or misspellings. Please let me know if you have any issues.

Error putting data from JSON response into Adapter (ListView)

I learned how to use ListView recently so I am not much proficient in it. I am facing a problem while adding the data from JSON response into the ListView. When I add hard-coded Strings into the ListView, it works fine. But gives nothing when putting data from JSON response.
Here is my activity (SupportedAds.java)
public class SupportedAds extends AppCompatActivity {
String[] Title;
String[] Content;
ListView list;
Offers offer;
ArrayList<Offers> offers = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_supported_ads);
list = findViewById(R.id.list);
/* Getting Supported Ads from the api*/
RequestQueue queue = Volley.newRequestQueue(SupportedAds.this);
final String URL_SUPPORTED_ADS = "http://lb-89089438.us-east-2.elb.amazonaws.com/api/offers";
StringRequest postRequest = new StringRequest(Request.Method.POST, URL_SUPPORTED_ADS,
new Response.Listener<String>()
{
#Override
public void onResponse(String response) {
JSONArray jsonResponse;
String offerContent;
String offerTitle;
// response
Log.wtf("POST api/offers", response);
try {
jsonResponse = new JSONArray(response);
Title = new String[jsonResponse.length()];
Content = new String[jsonResponse.length()];
for(int i=0; i < jsonResponse.length(); i++)
{
JSONObject jsonobject = jsonResponse.getJSONObject(i);
offerContent = jsonobject.getString("offercontent");
offerTitle = jsonobject.getString("offertitle");
offer = new Offers();
offer.setTitle(offerTitle);
offer.setContent(offerContent);
Log.e("Title", offerTitle); // shows correct values. No problem in JSON parsing or POST request
Log.e("Content", offerContent); // shows correct values. No problem in JSON parsing or POST request
offers.add(offer);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error) {
// error
Log.d("POST api/offers", error.toString());
}
}
) {
#Override
protected Map<String, String> getParams()
{
return new HashMap<>();
}
};
queue.add(postRequest);
/* Getting Supported Ads from the api*/
/* If i use these hard coded values, it works fine */
/*offer = new Offers();
offer.setTitle("Ad1");
offer.setContent("Advertisement #01 Description");
offers.add(offer);
offer = new Offers();
offer.setTitle("Ad2");
offer.setContent("Advertisement #02 Description");
offers.add(offer);
offer = new Offers();
offer.setTitle("Ad3");
offer.setContent("Advertisement #03 Description");
offers.add(offer);*/
list.setAdapter(new MyAdapter(getApplicationContext(), offers));
}
private class MyAdapter extends BaseAdapter {
private Context context;
private ArrayList<Offers> offers;
public MyAdapter(Context context, ArrayList<Offers> offers) {
this.context = context;
this.offers = offers;
}
#Override
public int getCount() {
return offers.size();
}
#Override
public Object getItem(int position) {
return offers.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TwoLineListItem twoLineListItem;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
twoLineListItem = (TwoLineListItem) inflater.inflate(
android.R.layout.simple_list_item_2, null);
} else {
twoLineListItem = (TwoLineListItem) convertView;
}
TextView text1 = twoLineListItem.getText1();
TextView text2 = twoLineListItem.getText2();
text1.setText(offers.get(position).getTitle());
text2.setText(offers.get(position).getContent());
return twoLineListItem;
}
}
}
When I try to use data from JSON response (no data being displayed - sorry for the background color)
When I use hard-coded Strings (works fine in this case - sorry for the background color)
Layout file (activity_supported_ads.xml)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:background="#color/lightgreen"
tools:context="com.fyp.mrisecondscreen.activity.SupportedAds">
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/list">
</ListView>
</RelativeLayout>
Response from POST Request (I am sure that I have no problems in JSON response parsing as i use Log.e to display the extracted values and they're correct)
[
{
"offercontent": "Sample Description",
"offertitle": "Ad 1",
},
{
"offercontent": "42 inch TV",
"offertitle": "TV ",
},
{
"offercontent": "Coke Ad Offer description here",
"offertitle": "Coke",
},
{
"offercontent": "Cola Ad Offer description here",
"offertitle": "Cola Offer",
},
{
"offercontent": "Nestle Ad Offer description here",
"offertitle": "Nestle Cerelac Offer",
},
{
"offercontent": "New Year sale",
"offertitle": "Chocolate",
}
]
Please help me, I am unable to solve it after spending many hours..
Your code list.setAdapter(new MyAdapter(getApplicationContext(), offers)); executes before the request completes and hence there is no data to show. This line should execute after the parsing is done inside the onResponse method.

get string from arraylist and settext inside fragment android

I want to get string from arraylist inside oncreateview fragment but i cant figure itout since no position index has been pass. get(position) return error.
String price = arrayList.get(position).getPrice();
i need to get string price and settext for price.this is my main concern.
this values should return from arraylist.
this is response JSON array from volley using mysingleton.
Single Product Response: [{"price":"75","date":"2017-07-13 03:25:31","pk_i_id":"4"}]
this main activty fragment
public class MainActivityFragment extends Fragment {
private TextView product,price,date,title;
private String product_id;
ArrayList<ProductItem> arrayList = new ArrayList<>();
Context context;
public MainActivityFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_main_activity, container, false);
product = (TextView) view.findViewById(R.id.tv1);
title = (TextView) view.findViewById(R.id.tvTitle);
price = (TextView) view.findViewById(R.id.tvPrice);
date = (TextView) view.findViewById(R.id.tvDate);
if (getArguments() != null) {
Log.i(TAG, "getArgument is not null");
product_id = getArguments().getString("product_id");
ProductBackgroundTask productBackgroundTask = new ProductBackgroundTask(this.getActivity(), product_id);
arrayList = productBackgroundTask.getList();
String price = arrayList.get(position).getPrice();
// Log.d(TAG, "price: " + price);
product.setText(product_id);
// price.setText(price);
}else {
Log.i(TAG, "getArgument is null");
}
return view;
}
}
this is task to get arraylist using volley
public class ProductBackgroundTask {
private Context context;
ArrayList<ProductItem> arrayList = new ArrayList<>();
String json_url = "phpfile.php";
private String product_id;
public ProductBackgroundTask(Context context, String product_id) {
this.context = context;
this.product_id = product_id;
}
public ArrayList<ProductItem> getList(){
StringRequest stringRequest = new StringRequest(Request.Method.POST, json_url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d(TAG, "Single Product Response: " + response);
try {
JSONArray jsonarr = new JSONArray(response);
for (int i = 0; i < jsonarr.length(); i++) {
JSONObject jsonobj = jsonarr.getJSONObject(i);
ProductItem productItem = new ProductItem(jsonobj.getString("price"), jsonobj.getString("date"), jsonobj.getInt("pk_i_id"));
arrayList.add(productItem);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> params = new HashMap<>();
params.put("product_id", product_id);
return params;
}
};
MySingleton.getInstance(context).addToRequestQueue(stringRequest);
return arrayList;
}
}
and this is class of array list
public class ProductItem {
private String Price,Date;
private int ProductId;
public ProductItem(String Price, String Date, int ProductId){
this.setPrice(Price);
this.setDate(Date);
this.setProductId(ProductId);
}
public int getProductId() {
return ProductId;
}
public void setProductId(int productId) {
ProductId = productId;
}
public String getPrice() {
return Price;
}
public void setPrice(String price) {
Price = price;
}
public String getDate() {
return Date;
}
public void setDate(String date) {
Date = date;
}
Clearly in your oncreate you haven’t initialized the product item and you cannot parse the complete list.You can try two to solve this
1.Pass specific item number instead of position i.e
say if you want to show 4th item then position=3
2.Or write a loop like this to parse entire arrayList like this
for(ProductItem productItem:arrayList){
String price = productItem.getPrice();
// Log.d(TAG, "price: " + price);
product.setText(product_id);
price.setText(price);
}
Mistake you're doing is that in the MainActivityFragment your trying to assign the value to the arrayList even before the data is added to the arrayList in the ProductBackgroundTask-getList. That's the reason you are getting the list null all the time. Try to use interfaces.
1.Make your MainActivityFragment implement the interface.
2.Set the value to the interface method once you get the data from the server.
3.Get the data in the MainActivityFragment inside interface method and do all the operation you're doing inside the onCreateView method.
Now your arraylist will have the data whatever you received from the server.
Below is the link for the example on interfaces if you haven't used them before. He is doing exactly as your requirement.
https://www.justinmccandless.com/post/setting-up-a-callback-function-in-android/
Allow me. The arrayList that you return from getList isn't populated at the time you call String price = arrayList.get(position).getPrice();. The server call using volley takes some time to process and that's when the onResponse gets called. This happens AFTER you've returned the arrayList which is in fact empty.
The sequence of events is as follows.
• Call to arrayList = productBackgroundTask.getList(); which returns an empty ArrayList.
• String price = arrayList.get(position).getPrice();
Now after a while..
• onResponse inside getList() gets called.
Do you now see why it's empty?
Simple Solution: • Define a simple interface ProductListener alongside ProductBackgroundTask. (With only a single abstract method onProducts).
• Instantiate it inside the Fragment's onCreateView using an anonymous class and pass it to the constructor of ProductListener to save it for later use. Do whatever you want to do with the products inside the onProducts method. (Since that will be called with the actual data)
• Call its onProducts method with the data that's parsed and fetched inside the onResponse method.
ProductBackgroundTask code:
public class ProductBackgroundTask {
private Context context;
// I removed the instance ArrayList since that can be made
// local.
// Here, we add a reference to our callback interface as we can use it later.
private ProductListener listener;
String json_url = "http://192.168.43.55/android/v1/productList.php";
private String product_id;
// Instantiate this class using an additional listener argument
// which would be a concrete implementation of our interface.
public ProductBackgroundTask(Context context, String product_id, ProductListener listener) {
this.context = context;
this.product_id = product_id;
this.listener = listener;
}
// getList should not return anything,
// so I keep the return as void.
public void getList() {
StringRequest stringRequest = new StringRequest(Request.Method.POST, json_url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
ArrayList<ProductItem> arrayList = new ArrayList<>();
Log.d(TAG, "Single Product Response: " + response);
try {
JSONArray jsonarr = new JSONArray(response);
for (int i = 0; i < jsonarr.length(); i++) {
JSONObject jsonobj = jsonarr.getJSONObject(i);
ProductItem productItem = new ProductItem(jsonobj.getString("price"), jsonobj.getString("date"), jsonobj.getInt("pk_i_id"));
arrayList.add(productItem);
}
// Notice this line here, this is what
// calls the callback with the products.
listener.onProducts(arrayList);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> params = new HashMap<>();
params.put("product_id", product_id);
return params;
}
};
MySingleton.getInstance(context).addToRequestQueue(stringRequest);
}
}
// Callback interface, we would need a concrete implementation
// of this and pass that to the constructor of ProductBackgroundTask.
interface ProductListener {
void onProducts(ArrayList<ProductItem> products);
}
The code inside onCreateView:
ProductBackgroundTask productBackgroundTask = new ProductBackgroundTask(this.getActivity(), product_id, new ProductListener() {
// This method will be called with the needed products.
// Give an anonymous class implementation of our interface
// right here since we won't be using it anymore.
public void onProducts(ArrayList<ProductItem> products) {
// Get the price you want.
String str = arrayList.get(0).getPrice();
// Use str wherever necessary. Use the UI thread here if you need
// to change any visible elements on the screen.
}
});
// Simply call this method to get the ball rolling.
productBackgroundTask.getList();
This is a concrete implementation of the this answer and you won't be changing much code.

How to retrieve multidimensional array using json and volley

I want to retreive data from json URL and i am face to a problem. I have this from the url :
{
-infos: (2)[
-{
value: "anderson",
-pictures: (2)[
-{
picone: "text_pic",
url: http://www.example.com
},
-{
picone: "text_pic2",
url: http://www.example.com
}
]
},
-{
value: "bryan",
-pictures: (2)[
-{
picone: "text_pic3",
url: http://www.example.com
},
-{
picone: "text_pic4",
url: http://www.example.com
}
]
},....
I have also my listview row :
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:id="#+id/url"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<com.android.volley.toolbox.NetworkImageView
android:id="#+id/pic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"/>
And here the volley code i used te retrieve data:
....
private List<News_Item> nNews = new ArrayList<>();
......
CustomRequest lnews = new CustomRequest(Request.Method.POST, URL, param, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray vals= response.getJSONArray("infos");
for (int i = 0; i < vals.length(); i++) {
JSONObject dats= vals.getJSONObject(i);
News_Item item = new News_Item ();
item.setmTitle(dats.getString("value"));
JSONArray overinfo = dats.getJSONArray("pictures");
for (int j = 0; j < overinfo.length(); j++) {
JSONObject links = overinfo .getJSONObject(j);
item.setmImage(links.getString("picone"));
item.setmUrl(links.getString("url"));
}
nNews.add(item);
}
} catch (JSONException ex) {
ex.printStackTrace();
}
....
This code return only one rows (the last row) for pictures array. something like this
row 1 => anderson / text_pic2 / http://www.example.com
row 2 = bryan / text_pic4 / http://www.example.com
So please help
UPDATE
This News_Item.class
class News_Item {
String mTitle;
public News_Item (){
}
List<Picture> pictureList;
public News_Item (String mTitle, <Picture> pictureList){
this.mTitle= mTitle;
this.pictureList= pictureList;
}
public String getmTitle() {
return mTitle;
}
public void setmTitle(String mTitle) {
this.mTitle = mTitle;
}
class Picture {
String url;
String picone;
public Picture (String url, String picone) {
this.url= url;
this.picone= picone;
}
public String getUrl() {
return Url;
}
public void setUrl(String url) {
this.url = url;
}
public String getPicone() {
return picone;
}
public void setPicone(String picone) {
this.picone = picone;
}
}
}
How get pictures datas.
Like in News_Item you did
News_Item item = new News_Item ();
item.setmTitle(dats.getString("value"));
And at last added to list: nNews.add(item);
you need to add picture items too,
So inside this loop, you are adding in for loop with same object i.e. item so its overwriting those variables
for (int j = 0; j < overinfo.length(); j++) {
JSONObject links = overinfo.getJSONObject(j);
item.setmImage(links.getString("picone"));
item.setmUrl(links.getString("url"));
-- Here add in collection of links
}
UPDATE: Here this will guide what you will need to do (I wrote directly on stackoverflow editor so might have error)
News_Item item = new News_Item();
item.setmTitle(dats.getString("value"));
List <Picture> pictures = new ArrayList<>();
for (int j = 0; j < overinfo.length(); j++) {
JSONObject links = overinfo.getJSONObject(j);
Picture picture = new Picture(links.getString("picone"), links.getString("url"));
pictures.add(picture);
}
item.setmPictureList(pictures); // Create this or use constructor itself
nNews.add(item);
Try to change News_Item to have a list of Picture class.
Your code has a problem. You are overwriting new image in every looping.
JSONArray overinfo = dats.getJSONArray("pictures");
for (int j = 0; j < overinfo.length(); j++) {
JSONObject links = overinfo .getJSONObject(j);
item.setmImage(links.getString("picone"));
item.setmUrl(links.getString("url"));
}
By creating new Picture class, you can add Picture object for picone and url value from pictures data.
class News_Item {
List<Picture> pictureList;
...
class Picture {
String url;
String picone;
...
}
}
Google has developed Gson, a library which lets you convert a JSON Strings to a Objects in just one line:
Gson on GitHub
Given that these are your classes:
public class InfoResponse {
List<Info> infos;
public InfoResponse(List<Info> infos) {
this.infos = infos;
}
}
public class Info {
String value;
List<Picture> pictures;
public Info(String value, List<Picture> pictures) {
this.value = value;
this.pictures = pictures;
}
}
public class Picture {
String picone;
String url;
public Picture(String picone, String url) {
this.picone = picone;
this.url = url;
}
}
you just have to call
InfoResponse response = new Gson().fromJson(jsonString, InfoResponse.class);
This will do everything for you.

Categories

Resources