Getting Nested JsonObjects & Arrays Using Retrofit Library - android

I got tired using this library, this is my first time using it and made a lot of success ways, but i'm a bit confused in getting the following Json :
{
"Guides":
{
"English": {"ArabicSony":"Test1","ArabicNexus":"Test2","ArabicSamsung":"Test3","ArabicHTC":"Test4"}
,"Arabic": {"EnglishSony":"Test1","EnglishNexus":"Test2","EnglishSamsung":"Test3","EnglishHTC":"Test4"}
}
}
Googled and saw a lot of guides and answered, and made my List like this :
public class PostItem {
List<PostItemArabic> Arabic;
List<PostItemEnglish> English;
}
class PostItemArabic{
private String ArabicSony;
private String ArabicNexus;
private String ArabicSamsung;
private String ArabicHTC;
public String getArabicSony() {
return ArabicSony;
}
public void setArabicSony(String arabicSony) {
ArabicSony = arabicSony;
}
public String getArabicNexus() {
return ArabicNexus;
}
public void setArabicNexus(String arabicNexus) {
ArabicNexus = arabicNexus;
}
public String getArabicSamsung() {
return ArabicSamsung;
}
public void setArabicSamsung(String arabicSamsung) {
ArabicSamsung = arabicSamsung;
}
public String getArabicHTC() {
return ArabicHTC;
}
public void setArabicHTC(String arabicHTC) {
ArabicHTC = arabicHTC;
}
}
class PostItemEnglish{
private String EnglishSony;
private String EnglishNexus;
private String EnglishSamsung;
private String EnglishHTC;
public String getEnglishSony() {
return EnglishSony;
}
public void setEnglishSony(String englishSony) {
EnglishSony = englishSony;
}
public String getEnglishNexus() {
return EnglishNexus;
}
public void setEnglishNexus(String englishNexus) {
EnglishNexus = englishNexus;
}
public String getEnglishSamsung() {
return EnglishSamsung;
}
public void setEnglishSamsung(String englishSamsung) {
EnglishSamsung = englishSamsung;
}
public String getEnglishHTC() {
return EnglishHTC;
}
public void setEnglishHTC(String englishHTC) {
EnglishHTC = englishHTC;
}
}
My Model :
private class Model {
private List<PostItem> Guides;
public List<PostItem> getGuides() {
return Guides;
}
public void setGuides(List<PostItem> roms_center) {
this.Guides = roms_center;
}
}
And printing the result like this :
List<PostItem> Guides = response.body().getGuides();
for(int i = 0 ; i < Guides.size() ; i ++ ) {
for (int b = 0; b < Guides.get(i).English.size() ; b++){
Log.LogInfo("English Result Is: " + Guides.get(i).English.get(i).getEnglishHTC());
Log.LogInfo("English Result Is: " + Guides.get(i).English.get(i).getEnglishNexus());
Log.LogInfo("English Result Is: " + Guides.get(i).English.get(i).getEnglishSamsung());
Log.LogInfo("English Result Is: " + Guides.get(i).English.get(i).getEnglishSony());
}
for (int b = 0; b < Guides.get(i).Arabic.size() ; b++){
Log.LogInfo("Arabic Result Is: " + Guides.get(i).Arabic.get(i).getArabicHTC());
Log.LogInfo("Arabic Result Is: " + Guides.get(i).Arabic.get(i).getArabicNexus());
Log.LogInfo("Arabic Result Is: " + Guides.get(i).Arabic.get(i).getArabicSamsung());
Log.LogInfo("Arabic Result Is: " + Guides.get(i).Arabic.get(i).getArabicSony());
}
}
My work isn't correct, and getting a lot of errors,
Here's the last error i got :
`Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 3 column 18 path $.Guides
What's the way to make it correct ? `

Based on your models when you try to get the guides list your telling retrofit to populate an array. Retrofit is then getting the data and finding that it is a single object and not array. So you need to update your model to reflect the data returned. For example:
class PostItem {
List<Language> mLanguages;
}
class Language{
String mLanguageTitle; //for example english
List<String> mData; //for this is your list of data
}
Then in your activity instead of getting guides you would get just a post item for example:
response.body().getPostItem();
Hope it helps !

First of all, you can use the retrofit Gson library.
You can handle this in two ways:
Option 1: reformat your languages in your json to be an array like Doug says.
{
"Guides":
[
{"Lang":"English","ArabicSony":"Test1","ArabicNexus":"Test2","ArabicSamsung":"Test3","ArabicHTC":"Test4"}
, {"Lang":"Arabic","EnglishSony":"Test1","EnglishNexus":"Test2","EnglishSamsung":"Test3","EnglishHTC":"Test4"}
]
}
Then you will need to redesign your class to reflect this structure.
Like Doug sayd:
class PostItem {
List<Language> mLanguages;
}
Option 2: Create a custom json desirializer in your class. this will take the Json and break it down into whatever structure you want it to be.
public class PostItem implements JsonDeserializer
#Override
public MyDesirializer deserialize(JsonElement json, Type type,
JsonDeserializationContext context) throws JsonParseException {
JsonObject jarabic = (JsonObject) json.get("Arabic");
//whatever manipulations you want to do (fill with your own code)
PostItem item = new PostItem();
item.arabic = jarabic;
...
...
return item;
}

Related

Sorting ArrayList of JSONObjects by a double doesn't work

I'm currently creating an Android app for school but still want to give my best.
I'm pretty new to Android development and coding in general. The app is supposed to be a stock market game. (Btw, I'm German, so there might be some German variables)
So I want to sort my RecyclerView containing shares. It works alphabetically but not by worth.
I can guarantee that the name "worth" of the double in the JSONObject is correct. What am I doing wrong?
public class CompanyAdapter extends RecyclerView.Adapter<CompanyAdapter.viewHolder> implements Filterable {
private CustomFilter filter;
private ArrayList<JSONObject> jObjList;
private final String keyName;
private final String keyWorth;
private final String keyChange;
public final static int SORT_ALPHABETICALLY = 0;
public final static int SORT_ALPHABETICALLY_REVERSE = 1;
public final static int SORT_BY_WORTH = 2;
public final static int SORT_BY_WORTH_REVERSE = 3;
public CompanyAdapter(Context context, ArrayList<JSONObject> jObjList) {
this.jObjList = jObjList;
Context c = context;
keyName = c.getResources().getString(R.string.nameCompany);
keyWorth = c.getResources().getString(R.string.worthCompany);
keyChange = c.getResources().getString(R.string.changeCompany);
sort(SORT_ALPHABETICALLY);
}
//left out some unnecessary code
public void sort (int sorting) {
if (jObjList.size()>1) {
switch (sorting) {
case SORT_ALPHABETICALLY:
sortAlphabetically();
break;
case SORT_ALPHABETICALLY_REVERSE:
sortAlphabeticallyReverse();
break;
case SORT_BY_WORTH:
sortByWorth();
break;
case SORT_BY_WORTH_REVERSE:
sortByWorthReverse();
break;
}
}
}
private void sortAlphabetically () {
Collections.sort(jObjList, new Comparator<JSONObject>() {
#Override
public int compare(JSONObject j1, JSONObject j2) {
try {
return j1.getString(keyName).compareToIgnoreCase(j2.getString(keyName));
} catch (JSONException e) {
return 0;
}
}
});
}
private void sortAlphabeticallyReverse () {
sortAlphabetically();
Collections.reverse(jObjList);
}
private void sortByWorth () {
Collections.sort(jObjList, new Comparator<JSONObject>() {
#Override
public int compare(JSONObject j1, JSONObject j2) {
try {
return Double.compare(j1.getDouble(keyWorth), j2.getDouble(keyWorth));
} catch (JSONException e) {
Log.e("JSONException", e.getMessage());
return 0;
}
}
});
}
private void sortByWorthReverse () {
sortByWorth();
Collections.reverse(jObjList);
}
}
try to replace
return Double.compare(j1.getDouble(keyWorth), j2.getDouble(keyWorth));
with
System.out.print("VALUE1: "+j1.getDouble(keyWorth));
System.out.print("VALUE2: "+j2.getDouble(keyWorth));
return (int)(j1.getDouble(keyWorth)-j2.getDouble(keyWorth));
as well to make sure and debug the value print it.
and after sortByWorth();
add notifyDataSetChanged();
Have you checked the values of the objects you are comparing within the console?
Since you are reading in the values as a string, perhaps they will not be giving the result you expect.
Furthermore, what operation is the compare function performing?
Replace:
return Double.compare(j1.getDouble(keyWorth), j2.getDouble(keyWorth));
In sortByWorth method, to:
return j1.getDouble(keyWorth).compareTo(j2.getDouble(keyWorth))
Try it..
I forgot the notifyDataSetChanged(). Sorry, that's a stupid error.

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.

cannot find symbol type token in android studio?

private void loadFromAndToPlaceValues() {
String str = loadJSONFromAsset();
this.places = (List)new Gson().fromJson(str, newTypeToken<List<BusEntity>>().getType());
if (this.places != null && this.places.size() > 0) {
this.places_array = new String[this.places.size()];
for (int i = 0; i < this.places_array.length; i++) {
this.places_array[i] = ((BusEntity) this.places.get(i)).getValue();
}
}
}
You've missed {} braces. Change it like following.
this.places = (List)new Gson().fromJson(str, new TypeToken<List<BusEntity>>(){}.getType());
On a different note, question should be more constructive and descriptive. Posting plain code likely won't yield good answer most of the time.
It may help you :
Option 1 - implement java.lang.reflect.ParameterizedType yourself and pass it to Gson.
private static class ListParameterizedType implements ParameterizedType {
private Type type;
private ListParameterizedType(Type type) {
this.type = type;
}
#Override
public Type[] getActualTypeArguments() {
return new Type[] {type};
}
#Override
public Type getRawType() {
return ArrayList.class;
}
#Override
public Type getOwnerType() {
return null;
}
// implement equals method too! (as per javadoc)
}
Then simply:
Type type = new ListParameterizedType(clazz);
List<T> list = gson.fromJson(json, type);
This will work too, at least with Gson 2.2.4.
Type type = com.google.gson.internal.$Gson$Types.newParameterizedTypeWithOwner(null, ArrayList.class, clazz);

Display the ArrayList values into TextVitew

Am working on one android project. i stored the getting response in the ArrayList while parsing from the JsonArray. now i want just display the values to required text views.
Here am doing.
public void updateRedemptionRequestDetails(){
//Dismiss dialog
dlgProgress.dismiss();
// Get the status
String status=redemptionRequestDetailsResponse.getStatus();
if(status.equals("success")){
List<RedemptionRequestDetailsResource> redemptionRequestDetailsResource = redemptionRequestDetailsResponse.getData();
if(!redemptionRequestDetailsResource.isEmpty() && redemptionRequestDetailsResource.size()==0 ){
redemptionRequestDetailsResources.addAll(redemptionRequestDetailsResource);
populateRedemptionDetails(redemptionRequestDetailsResources);
}
}else if ( status.equals("failed")) {
//Show toast based on error code
generalMethods.showToastMessage(context,redemptionRequestDetailsResponse.getErrorcode());
}
}
Can anyone please shed some lights on this.how can i get the values in specified string and display them.
Here my model class
public class RedemptionRequestDetailsResource {
private String rdmId;
private String rdmUniqueBatchTrackingId;
private String rdmLoyaltyId;
private String rdmStatus;
private String rdmCashPaymentStatus;
private String rdmProductCode;
public String getRdmId() {
return rdmId;
}
public void setRdmId(String rdmId) {
this.rdmId = rdmId;
}
public String getRdmUniqueBatchTrackingId() {
return rdmUniqueBatchTrackingId;
}
public void setRdmUniqueBatchTrackingId(String rdmUniqueBatchTrackingId) {
this.rdmUniqueBatchTrackingId = rdmUniqueBatchTrackingId;
}
public String getRdmLoyaltyId() {
return rdmLoyaltyId;
}
public void setRdmLoyaltyId(String rdmLoyaltyId) {
this.rdmLoyaltyId = rdmLoyaltyId;
}
public String getRdmStatus() {
return rdmStatus;
}
public void setRdmStatus(String rdmStatus) {
this.rdmStatus = rdmStatus;
}
public String getRdmCashPaymentStatus() {
return rdmCashPaymentStatus;
}
public void setRdmCashPaymentStatus(String rdmCashPaymentStatus) {
this.rdmCashPaymentStatus = rdmCashPaymentStatus;
}
public String getRdmProductCode() {
return rdmProductCode;
}
public void setRdmProductCode(String rdmProductCode) {
this.rdmProductCode = rdmProductCode;
}
}
here my populateRedemptionDetails method
public void populateRedemptionDetails(List<RedemptionRequestDetailsResource> requestDetailsResource) {
List<RedemptionRequestDetailsResource> redemptionRequestDetailsResource = requestDetailsResource;
TextView txtLoyaltyId = (TextView)rootView.findViewById(R.id.txtLoyaltyId);
txtLoyaltyId.setText(redemptionRequestDetailsResource.getRdmLoylatyId());
}
i tried like this but it throwing error.
The if condition is wrong, it will never enter:
if (!redemptionRequestDetailsResource.isEmpty() && redemptionRequestDetailsResource.size()==0) {
}
it should be:
if (!redemptionRequestDetailsResource.isEmpty()) {}
also, small tip, when using equals, you should put the constant on the left side of the call, like this:
"success".equals(status)
this is to prevent NullPointerExceptions

How to properly parse JSON Array in Android

Im trying to find an easy way to parse JSON data that are in an array. Ive been able to do this before with pure JSON Objects and OkHttp.
What I plan to do is make a simple recycler view that each row will contain the data from the JSON Array.
Note: there will be keys in each array that may or may not have a "viewers" parameter. If it does not exist I plan to make a default value of 0.
JSON example:
{
status_code: 200,
status_text: "OK",
errors: [ ],
data: {
items: [
{
stream: "channel1",
status: 1,
channel: 527,
provider: "akamai"
},
{
stream: "channel2",
status: 2,
channel: 565,
provider: "akamai",
viewers: 3
},
I have a class that stores the data (not sure if needed in the case of a JSON Array) called CurrentStreams.java
package com.example.concurrent;
public class CurrentStreams {
private String mStream;
private int mStatus;
private int mChannel;
private String mProvider;
private int mViewers;
public String getStream() {
return mStream;
}
public void setStream(String stream) {
mStream = stream;
}
public int getStatus() {
return mStatus;
}
public void setStatus(int status) {
mStatus = status;
}
public int getChannel() {
return mChannel;
}
public void setChannel(int channel) {
mChannel = channel;
}
public String getProvider() {
return mProvider;
}
public void setProvider(String provider) {
mProvider = provider;
}
public int getViewers() {
return mViewers;
}
public void setViewers(int viewers) {
mViewers = viewers;
}
}
In my MainActivity I initiate a new OkHttpClient and create the request and pass a method called getCurrentDetails(jsonData) which contains the following
private CurrentStreams getCurrentDetails(String jsonData) throws JSONException {
//New JSON Array
JSONArray jsonArray = new JSONArray(jsonData);
for (int i = 0; i < jsonArray.length(); i++){
JSONObject items = jsonArray.getJSONObject(i);
String streamName = items.getString("stream_name");
int status = items.getInt("status");
int channelId = items.getInt("channel_id");
String cdn = items.getString("cdn");
int viewers = items.getInt("viewers");
}
}
I assume im kinda lost at how to properly handle the JSON Array and save the data to then later populate the view with rows of data. Any help is greatly appreciated in advanced.
I would suggest to use gson.
You maybe want to take a look at this answer or this Tutorial

Categories

Resources