Retrofit - avinotec/Stundenplaner.FHE_EAH GitHub Wiki

Set up

A basic example of the Retrofit setup can be found here.

In this article, we will explained the set up on the basis of TimeTableResponse. We use this to request a list of all EAH study programs including their semesters and the semester's study groups.

Model class

The model class (in this project called Value Object) will contain the fetched information, thus the structure and serialized names are required to match the field names in the retrieved JSON object. When parsing the JSON object, it is split into its levels meaning that we need a model class for each level. That can be String, int, ArrayList, Map, etc. or an individual class.

The first and second level of the JSON object requested looks like this:

{ "studentset": {
       "AO(BA)": { ... },
       ...
   }
}

Thus, we specify the field "studentset" in the model class TimeTableResponse as shown in the following code snippet and say that it stores a Map containing a Value Object (VO) for each study program.

public class TimeTableResponse {

    public TimeTableResponse(){    }

    //Getter and Setter

    @SerializedName("studentset")
    private Map<String, TimeTableStudyProgramVo> mStudyPrograms;
}

The third level of the JSON object contains information for each study program. Here we use TimeTableStudyProgramVo as model class. Above we specified the Map holding a TimeTableStudyProgramVo for each key, thus RetroFit is reading each object stored under a study program (e.g. "AO(BA)") into a TimeTableStudyProgramVo object.

JSON till level three:

{ "studentset": {
       "AO(BA)": { 
            "stgNameshort": "AO(BA)",
            "stgNamelong":  "Augenoptik/Optometrie",
            "stgDegree":    "Bachelor",
            "semesterData":  { ... }
        },
   }
}

The model class corresponding to level three:

public class TimeTableStudyProgramVo implements Parcelable {

    public TimeTableStudyProgramVo() {}

    //Getter and Setter

    //methods for implementation of Parcelable needed but to simplify not shown here

    @SerializedName("stgNameshort")
    private String              mShortTitle;

    @SerializedName("stgNamelong")
    private String              mLongTitle;

    @SerializedName("stgDegree")
    private String              mDegree;

    @SerializedName("semesterData")
    private Map<String, TimeTableSemesterVo> mSemesters;
}

This goes on until the last level of the JSON object is reached.

RetroFit instance

Our RetroFit instance is called NetworkHandler. "This Java class is used to send requests to an API. We specify the URL that contains the data required and use the Retrofit Builder class."(Briana Nzivu)

Because we use an API from FH Erfurt as well as the API from EAH Jena, we construct our RetroFit instance in the following way:

public class NetworkHandler {

	private static final NetworkHandler ourInstance = new NetworkHandler();

	private Retrofit mRestAdapter = null;
	private Retrofit mRestAdapterEah = null;
	private ApiDeclaration mApi = null;
	private ApiDeclaration mApiEah = null;

	private NetworkHandler() {
		final Gson gson = new GsonBuilder()
				.setDateFormat("HH:mm:ss'T'yyyy-MM-dd")
				.create();

		mRestAdapter = new Retrofit.Builder()
				.baseUrl(Endpoints.BASE_URL + Endpoints.APP_NAME)
				.addConverterFactory(GsonConverterFactory.create(gson))
				.build();
		mRestAdapterEah = new Retrofit.Builder()
				.baseUrl(Endpoints.BASE_URL_EAH)
				.addConverterFactory(GsonConverterFactory.create(gson))
				.build();

		mApi = mRestAdapter.create(ApiDeclaration.class);
		mApiEah = mRestAdapterEah.create(ApiDeclaration.class);


	}

        public static NetworkHandler getInstance() {
		Assert.assertTrue( ourInstance != null);
		return ourInstance;
	}

We add a method to NetworkHandler to fetch the JSON object using our first level model class TimeTableResponse:

       public void fetchTimeTable(final Callback<TimeTableResponse> _Callback) {

		mApiEah.fetchTimeTable().enqueue(_Callback);
	}

Endpoints

For sure, we need to give the API URL that RetroFit should use. Because we have a lot of Endpoints, we are having a separate class for them called Endpoints. Usually we are splitting the URLs into a Base URL and a special second URL part. We need to distinguish between EAH Api and FH Erfurt Api again. The following code is simplified for the example:

public class Endpoints {
     public static final String BASE_URL_EAH         = "https://stundenplanung.eah-jena.de/";
     public static final String TIMETABLE            = "api/mobileapp/v1/studentset/list";

}

In the interface ApiDeclaration, we tell which Endpoint and first level model class to use when fetching the TimeTable:

public interface ApiDeclaration {

    @GET(Endpoints.TIMETABLE)
    Call<TimeTableResponse> fetchTimeTable();

}

It should be mentioned that you can use parameters in the request:

@GET(Endpoints.MENSA + "/{mensaId}")
Call<MensaFoodItemVo[]> fetchMensaData(@Path("mensaId") String _MensaId);

Sending a GET request

If you want to get the information from the API, you use a Callback where you specify what to do with the response you are getting (or what to do in case of failure).

Callback<TimeTableResponse> mTimeTableResponseCallback = new Callback<TimeTableResponse>() {
        @Override
        public void onResponse(Call<TimeTableResponse> call, Response<TimeTableResponse> response) {
            if ( response.body() != null ) {

                mResponse = response.body();
                
                //do something with the respone, for example:
                mView.setStudyProgramItems(mResponse.getStudyProgramsAsList());
                mView.toggleProgressIndicatorVisibility(false);
            }
        }

        @Override
        public void onFailure(Call<TimeTableResponse> call, Throwable t) {
            Log.d(TAG, "failure: request " + call.request().url());
        }
    };

private TimeTableResponse       mResponse;

For fetching the data, you simple call NetworkHandler.getInstance().fetchTimeTable(mTimeTableResponseCallback); and hopefully find your code under onResponse being run and the TimeTableResponse object being stored under mRespsonse.