If you have been following along you can keep working on what we made in the last post otherwise, you can grab the code for everything we have done till now here to follow along.
In the last post we fetched some data from Github API. We now want to parse it so that we can use it to do something meaningful. If you are unsure about what JSON is this might help.
Let’s take a look at a query to figure out what our JSON looks like and what to fetch. There are a lot of things that we could use, let's just try to display names of repos in the TextView. Displaying data in a list using a RecyclerView is a better approach than squashing everything in a single TextView, but that’s for another post.
Parsing is pretty straight forward, JSON arrays are inside square brackets []
and object in curly brackets {}
. I think method names are pretty self explanatory. Here is how I am getting the names of repos from the JSON:
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
try {
// Get the main JSON object from the String
JSONObject json = new JSONObject(s);
// Get all the repos
JSONArray repos = json.getJSONArray("items");
// loop every repo and add the name to the TextView
for(int i = 0; i < repos.length(); i++){
JSONObject repo = repos.getJSONObject(i);
mSearchResultTextView.append(repo.getString("name") + "\n\n");
}
}catch (JSONException e){
e.printStackTrace();
}
// We don't need this now since we are adding the names above
// mSearchResultTextView.setText(s);
mSearchResultTextView.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.INVISIBLE);
}
We get the main JSON object from the string using JSONObject json = new JSONObject(s);
and then we can use functions like getJSONObject
, getJSONArray
, getString
, and so forth, on the JSON arrays and objects based on what we want to fetch.
In the JSON we get here we have the main JSON object which has an array named items
and each item in the array contains repos which are JSONObjects and each of these JSONObjects contains a string which contains the name of the repo.
Now instead of displaying everything now we are displaying the repository names. This is what it looks like:
This is already looking better, but we might want to use more than just the name of the repository in the future. Creating a custom class to hold the data seems like a good idea here. We might end up changing the class or completely deleting it in the future, but that is fine we will refactor our app when the time comes.
Refactoring - Adding a new Repository Class
Let’s create a new package called model and inside it create a new class called Repository. After taking a look at what github.com, they list name, description, stars, language, updated at and license on every item when you do a search, so for now I have added these to our class and generated getter and setter methods for each one of them.
// Repository.class
package com.avinsharma.githubrepositorysearch.model;
public class Repository {
private String name = null;
private String description = null;
private Integer stargazersCount = null;
private String language = null;
private String updatedAt = null;
private String license = null;
public Repository(String name, String description, Integer stargazersCount, String language, String updatedAt, String license) {
this.name = name;
this.description = description;
this.stargazersCount = stargazersCount;
this.language = language;
this.updatedAt = updatedAt;
this.license = license;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getStargazersCount() {
return stargazersCount;
}
public void setStargazersCount(Integer stargazersCount) {
this.stargazersCount = stargazersCount;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(String updatedAt) {
this.updatedAt = updatedAt;
}
public String getLicense() {
return license;
}
public void setLicense(String license) {
this.license = license;
}
}
Now that we have a class that stores everything that we need, we need to use it. Just to make our life easier I also added another class in utilities called JSONUtils where I parse JSON and return a new Repository item that contains all the details that we parsed.
package com.avinsharma.githubrepositorysearch.utilities;
import com.avinsharma.githubrepositorysearch.model.Repository;
import org.json.JSONException;
import org.json.JSONObject;
public class JSONUtils {
public static Repository parseRepositoryJSON(JSONObject repo){
Repository newRepository = null;
try {
String name = repo.getString("name");
String updatedAt = repo.getString("updated_at");
Integer stargazersCount = repo.getInt("stargazers_count");
// These could be null
String description = null;
if (!repo.isNull("description")){
description = repo.getString("description");
}
String language = null;
if (!repo.isNull("language")){
language = repo.getString("language");
}
String license = null;
if (!repo.isNull("license")){
license = repo.getJSONObject("license").getString("spdx_id");
}
newRepository = new Repository(name, description, stargazersCount, language, updatedAt, license);
}catch (JSONException e){
e.printStackTrace();
}
return newRepository;
}
}
Now finally we make changes in our AsyncTask and use the class and JSON utility that we just made to display the search result.
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
try {
// Get the main JSON object from the String
JSONObject json = new JSONObject(s);
// Get all the repos
JSONArray repos = json.getJSONArray("items");
mRepos = new Repository[repos.length()];
// loop every repo and add the name to the TextView
for(int i = 0; i < repos.length(); i++){
JSONObject repo = repos.getJSONObject(i);
// Using the util we created here
mRepos[i] = JSONUtils.parseRepositoryJSON(repo);
// Adding name and description to the TextView
mSearchResultTextView.append(mRepos[i].getName());
if (mRepos[i].getDescription() != null){
mSearchResultTextView.append("\n" + mRepos[i].getDescription());
}
mSearchResultTextView.append("\n\n");
}
}catch (JSONException e){
e.printStackTrace();
}
mSearchResultTextView.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
}
Although we haven’t added new functionality this class will make our life easier in the future when we generate more complex views.
This is what our app looks like right now:
You can find everything we have done in this post here.
This does not look bad but we can do better, we can use the 6 things that we parse from the JSON and display it. In the next post we will explore Recycler View. Recycler view will give us a better user interface and a better user experience, it allows us to display lists with more complex views and gives us the ability to do something when we click an item.
Top comments (0)