I have an application that parses JSON data and displays it into a recycler view. Each item in the recycler view is an object of the Reps class and is contained within a card layout. The code works fine when I only attempt to parse the string variables.
The moment I attempt to parse the Image URL into the ImageView, the recycler view doesnt display and the activity is blank. I am using Picasso to load the images into the onBinfViewHolder method in my adapter class. Here is the relevant code
Reps:
public class Reps {
private String officeName;
private String officialName;
private String party;
private String photoUrl;
//continue to develop this with other values such as phone, photo, address etc.
public Reps(String officeName, String officialName, String party, String photoUrl) {
this.officeName = officeName;
this.officialName = officialName;
this.party = party;
this.photoUrl = photoUrl;
}
public Reps(String officeName, String officialName, String party) {
this.officeName = officeName;
this.officialName = officialName;
this.party = party;
}
public Reps(String officeName) {
this.officeName = officeName;
}
public Reps(String name, String party) {
this.officialName = name;
this.party = party;
}
public String getOfficeName() {
return officeName;
}
public void setOfficeName(String officeName) {
this.officeName = officeName;
}
public String getOfficialName() {
return officialName;
}
public void setOfficialName(String officialName) {
this.officialName = officialName;
}
public String getParty() {
return party;
}
public void setParty(String party) {
this.party = party;
}
public String getPhotoUrl() {
return photoUrl;
}
public void setPhotoUrl(String photoUrl) {
this.photoUrl = photoUrl;
}
}
RepRvAdapter:
public class RepRvAdapter extends
RecyclerView.Adapter<RepRvAdapter.MyViewHolder> {
private Context context;
private List<Reps> repsList;
RequestOptions option;
public RepRvAdapter() {
}
public RepRvAdapter(List<Reps> repList, Context applicationContext) {
this.repsList = repList;
this.context = applicationContext;
}
@NonNull
@Override
public RepRvAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view;
LayoutInflater mInflater = LayoutInflater.from(context);
view = mInflater.inflate(R.layout.card, viewGroup, false); //Inflate view to card.xml
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RepRvAdapter.MyViewHolder myViewHolder, int i) {
myViewHolder.officeName.setText(repsList.get(i).getOfficeName()); //Display these three elements in the card view
myViewHolder.officialName.setText(repsList.get(i).getOfficialName());
myViewHolder.party.setText(repsList.get(i).getParty());
//load image into card view
Picasso.get()
.load(repsList.get(i).getPhotoUrl())
.centerCrop()
.transform(new CircleTransform(50, 0))
.fit()
.into(myViewHolder.photoUrl);
}
@Override
public int getItemCount() {
return repsList.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
//Variables
TextView officeName, officialName, party; //Only the Referendum title and type will be in the recycler view
ImageView photoUrl;
public MyViewHolder(View itemView){
super(itemView);
officeName = itemView.findViewById(R.id.office_name);
officialName = itemView.findViewById(R.id.official_name);
party = itemView.findViewById(R.id.party);
photoUrl = itemView.findViewById(R.id.photo_url);
}
}
}
Method that parses JSON data:
//fetch json data from Civic API
private void getData(){
final ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Loading...");
progressDialog.show();
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
progressDialog.dismiss();
try{
JSONObject jsonObject = new JSONObject(response);
//first loop through offices array. Retrieve officeName value
JSONArray officesArray = jsonObject.getJSONArray("offices"); //One array for offices
JSONArray officialsArray = jsonObject.getJSONArray("officials"); //one array for officials
for (int i = 0; i < officesArray.length(); i++){
JSONObject jsonOffices = officesArray.getJSONObject(i);
JSONObject jsonOfficials = officialsArray.getJSONObject(i);
Reps reps = new Reps (jsonOfficials.getString("name"),
jsonOfficials.getString("party"),
//jsonOfficials.getString("photoUrl")
jsonOffices.getString("name"));
repList.add(reps);
}
adapter = new RepRvAdapter(repList, getApplicationContext());
myrv.setAdapter(adapter);
}catch (JSONException e){
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("Volley", error.toString());
progressDialog.dismiss();
}
});
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(stringRequest);
}
Right now, I have the line of code that parses the image URL commented out. Once the line is uncommented, the activity no longer displays. How can I get the Image url to be parsed and displayed in the ImageView? I think it might be an issue with the JSON data. In the JSON array, not all photoUrl fields are set. The API may not return image data for every representative in the array, whereas the party, name and office fields always have values. Can this be what stops the recycler view from displaying? Here is a relevant chunk of JSON data:
"officials": [
{
"name": "Donald J. Trump",
"address": [
{
"line1": "The White House",
"line2": "1600 Pennsylvania Avenue NW",
"city": "Washington",
"state": "DC",
"zip": "20500"
}
],
"party": "Republican",
"phones": [
"(202) 456-1111"
],
"photoUrl":"https://www.whitehouse.gov/sites/whitehouse.gov/files/images/45/PE%20Color.jpg",
"channels": [
{
"type": "GooglePlus",
"id": "+whitehouse"
},
{
"type": "Facebook",
"id": "whitehouse"
},
{
"type": "Twitter",
"id": "potus"
},
{
"type": "YouTube",
"id": "whitehouse"
}
]
},
{
"name": "Mike Pence",
"address": [
{
"line1": "The White House",
"line2": "1600 Pennsylvania Avenue NW",
"city": "Washington",
"state": "DC",
"zip": "20500"
}
],
"party": "Republican",
"phones": [
"(202) 456-1111"
],
"photoUrl":"https://www.whitehouse.gov/sites/whitehouse.gov/files/images/45/VPE%20Color.jpg",
"channels": [
{
"type": "GooglePlus",
"id": "+whitehouse"
},
{
"type": "Facebook",
"id": "whitehouse"
},
{
"type": "Twitter",
"id": "VP"
}
]
},
{
"name": "Dianne Feinstein",
"address": [
{
"line1": "331 Hart Senate Office Building",
"city": "Washington",
"state": "DC",
"zip": "20510"
}
],
"party": "Democratic",
"phones": [
"(202) 224-3841"
],
"photoUrl": "http://bioguide.congress.gov/bioguide/photo/F/F000062.jpg",
"channels": [
{
"type": "Facebook",
"id": "SenatorFeinstein"
},
{
"type": "Twitter",
"id": "SenFeinstein"
},
{
"type": "YouTube",
"id": "SenatorFeinstein"
}
]
},
{
"name": "Kamala D. Harris",
"address": [
{
"line1": "112 Hart Senate Office Building",
"city": "Washington",
"state": "DC",
"zip": "20510"
}
],
"party": "Democratic",
"phones": [
"(202) 224-3553"
],
"channels": [
{
"type": "Twitter",
"id": "KamalaHarris"
},
{
"type": "YouTube",
"id": "UC0XBsJpPhOLg0k4x9ZwrWzw"
}
]
As you can see, All representative have a name, party and office, but not all representatives have an image URL. The logcat returns this in regards to it.
I am willing to try different libraries. Let me know if you need to see any more code. Thanks for the help!
I added the following conditional to my jsonParse method to account for objects with no photoUrl field.
try{
JSONObject jsonObject = new JSONObject(response);
//first loop through offices array. Retrieve officeName value
JSONArray officesArray = jsonObject.getJSONArray("offices"); //One array for offices
JSONArray officialsArray = jsonObject.getJSONArray("officials"); //one array for officials
for (int i = 0; i < officesArray.length(); i++){
JSONObject jsonOffices = officesArray.getJSONObject(i);
JSONObject jsonOfficials = officialsArray.getJSONObject(i);
if(jsonOfficials.has("photoUrl")){
Reps reps = new Reps (jsonOfficials.getString("name"),
jsonOfficials.getString("party"),
jsonOfficials.getString("photoUrl"),
jsonOffices.getString("name"));
repList.add(reps);
}else{
Reps reps = new Reps(jsonOfficials.getString("name"),
jsonOfficials.getString("party"),
jsonOffices.getString("name"));
repList.add(reps);
}
}
adapter = new RepRvAdapter(repList, getApplicationContext());
myrv.setAdapter(adapter);
With this code, the recycler view displays, but the image URL string is displayed in the officeName textview instead of an image in the ImageView.
Since the last official doesnt have an image available, their data is displayed correctly.
2
Answers
There is a mistake in the JSON Response. Try this
Problem#1: A JSON Exception Occurred When you try to parse “photoUrl”, cause there is no field exist named “photoUrl” in last officials object.
Solution#1: Just put the code inside a condition like:
Problem#2: please check your “Reps” class 1st constructor. Here, u get the “photoUrl” feild as 4th parameter, but when u create an object of “Reps” class, u pass “photoUrl” feild as 3rd parameter.
Solution#2: