Hi I am new to the Retrofit 2.0 library, I am having problems parsing some json. I have looked at some other solutions on Stackoverflow but not having much luck with my problem. I am trying to call an api from android with retrofit 2.0.But it is throwing error Expected BEGIN_ARRAY but was BEGIN_OBJECT.
Any ideas what im doing wrong?
Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 2 column 2 path $
Fragment.java
ListView superListView;
static Retrofit retrofit = null;
#Override
public void onCreate (#Nullable Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
connect2();
}
private void connect2() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
HomeApiService movieApiService = retrofit.create(HomeApiService.class);
Call<List<Movie3>> call = movieApiService.popularMovies2();
call.enqueue(new Callback<List<Movie3>>() {
#Override
public void onResponse(Call<List<Movie3>> call, Response<List<Movie3>> response) {
List<Movie3> myheroList2 = response.body();
String[] oneHeroes = new String[myheroList2.size()];
for (int i2 = 0; i2 < myheroList2.size(); i2++) {
oneHeroes[i2] = myheroList2.get(i2).getTitle();
}
superListView.setAdapter(new ArrayAdapter<String>(getActivity().getApplicationContext(),
android.R.layout.simple_list_item_2, oneHeroes));
}
#Override
public void onFailure(Call<List<Movie3>> call, Throwable throwable) {
Log.e("Error: ", throwable.toString());
}
});
}
HomeApiService.java
public interface HomeApiService {
#GET("movie/test")
Call<List<Movie3>> popularMovies2 ();
}
Movie3.java
public class Movie3 {
#SerializedName("title")
private String title;
public Movie3(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
}
Ok...First of all your POJO for accepting the response is not correct. This is a crucial part while accepting a response. Your POJO should look like this :
public class Result{
public boolean adult;
public String backdrop_path;
public List<int> genre_ids;
public int id;
public String original_language;
public String original_title;
public String overview;
public double popularity;
public String poster_path;
public String release_date;
public String title;
public boolean video;
public double vote_average;
public int vote_count;
}
public class Root{
public int page;
public List<Result> results;
public int total_pages;
public int total_results;
}
Where root is the class and result is another class. As you can see the response contains result as a list.
And also the HomeApiService should look like this:
public interface HomeApiService {
#GET("movie/popular?api_key=ffd597419be5a256066dc51c49bc659f")
Call<Root> popularMovies2 ();
}
Hope you got the point. Add necessary getters and setters. Normally it's easy to use a JSON to POJO online converter. Here is one: https://json2csharp.com/json-to-pojo ..... paste the response in JSON and get the POJO converted.
Related
When I try to call rest API in the android studio I get an error that:
E/error: End of input at line 1 column 1 path $
I use firebase for the database and retrofit2 library.
But when I call the values a go to the firebase database and call the onFailure in call.enqueue() method.
public class APis {
public static final String URL = "http://192.168.178.43:8081/api/";
public static userService setuser() {
return client.getClient(URL).create(userService.class);
}
}
public interface userService {
#Headers("Content-Type: application/json")
#POST("signup")
Call<userlog> adduser(#Body userlog userlog);
}
public class userlog {
#SerializedName("email")
#Expose
private String emial_;
#SerializedName("password")
#Expose
private String password_;
#SerializedName("name")
#Expose
private String name_;
public userlog() {
}
public userlog(String emial_, String password, String name_) {
this.emial_ = emial_;
this.password_ = password;
this.name_ = name_;
}
public String getEmial_() {
return emial_;
}
public void setEmial_(String emial_) {
this.emial_ = emial_;
}
public String getPassword_() {
return password_;
}
public void setPassword_(String password_) {
this.password_ = password_;
}
public String getName_() {
return name_;
}
public void setName_(String name_) {
this.name_ = name_;
}
}
public void setPassword_(String password_) {
this.password_ = password_;
}
}
private void adduser_(userlog userll) {
service = APis.setuser();
Call<userlog> call = service.adduser(userll);
call.enqueue(new Callback<userlog>() {
#Override
public void onResponse(Call<userlog> call, Response<userlog> response) {
if (response.isSuccessful()) {
Toast.makeText(getApplicationContext(), "Success", Toast.LENGTH_SHORT).show();
/* userdetails.setUserid(firebaseAuth.getUid());
userdetails.setEmail_(emailId.getText().toString());
startActivity(new Intent(SignupActivity.this, MainnewActivity.class));*/
}
}
#Override
public void onFailure(Call<userlog> call, Throwable t) {
Log.e("error", t.getMessage());
Toast.makeText(getApplicationContext(), "not Successdd", Toast.LENGTH_SHORT).show();
}
});
}
when I call "adduser_(userll)" method, I get a notification that "not Successdd".
The problem related to retrofit, i think the problem because the response of the call come as null or empty
you can create NullConverterFactory.class :
public class NullConverterFactory extends Converter.Factory {
#Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
final Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations);
return new Converter<ResponseBody, Object>() {
#Override
public Object convert(ResponseBody body) throws IOException {
if (body.contentLength() == 0) return null;
return delegate.convert(body);
}
};
}
}
and add to the create of the retrofit
baseUrl(Config.URL+"/")
.client(okHttpClient)
// -----add here-------
.addConverterFactory(new NullConverterFactory())
//---------------------
.addConverterFactory(GsonConverterFactory.create())
.build()
I am using Google Books API to display a list of various books by searching for terms, queries....
So far everything is working as it is supposed to be, one problem though, I need to get a book by it's id, I believe the problem is with my BookResponse class
UPDATE I figured I should add a Serialized id in BookItems class but I don't know where to go from there
PS. below you will find every class and a an image attached to display the JSON structure
Search in MainActivity
ApiInterface apiService =
RetrofitInstance.getRetrofitInstance().create(ApiInterface.class);
retrofit2.Call<BookResponce> call = apiService.getBooksById("zyTCAlFPjgYC", BOOKS_API_KEY);
call.enqueue(new Callback<BookResponce>() {
#Override
public void onResponse(retrofit2.Call<BookResponce> call, Response<BookResponce> response) {
bookResp = response.body();
for (int i = 0; i == 0; i++){
bookList.add(i, bookResp.getBooks().get(i).getBookData());
}
cAdapter.notifyDataSetChanged();
}
#Override
public void onFailure(retrofit2.Call<BookResponce> call, Throwable t) {
Toast.makeText(this, "failed", Toast.LENGTH_LONG).show();
}
});
BookResponse class
public class BookResponce {
#SerializedName(value="items")
ArrayList<BookItems> bookItems;
#SerializedName(value="totalItems")
int totalItems;
public int getTotalItems() { return totalItems; }
public ArrayList<BookItems> getBooks() { return bookItems; }
}
BookItems class
public class BookItems {
//This is what I added
#SerializedName(value = "id")
String id;
#SerializedName(value="volumeInfo")
Book bookData;
//and this...
public String getId() {
return id;
}
public Book getBookData(){return bookData; }
}
API Interface class
public interface ApiInterface {
#GET("volumes/{id}")
Call<BookResponce> getBooksById(#Path("id") String bookId,
#Query("API_KEY") String apiKey);
#GET("volumes")
Call<BookResponce> getBooksByQuery(#Query("q") String query,
#Query("API_KEY") String apiKey, #Query("maxResults") int maxResults);
}
when ever you're performing a search, after adding items in your bookList just add:
bookList.get(i).setBookId(bookResp.getBooks().get(i).getId());
Here's the full example in your case:
ApiInterface apiService =
RetrofitInstance.getRetrofitInstance().create(ApiInterface.class);
retrofit2.Call<BookResponce> call = apiService.getBooksById("zyTCAlFPjgYC", BOOKS_API_KEY);
call.enqueue(new Callback<BookResponce>() {
#Override
public void onResponse(retrofit2.Call<BookResponce> call, Response<BookResponce> response) {
bookResp = response.body();
for (int i = 0; i == 0; i++){
bookList.add(i, bookResp.getBooks().get(i).getBookData());
//This is what you must add
bookList.get(i).setBookId(bookResp.getBooks().get(i).getId());
}
cAdapter.notifyDataSetChanged();
}
#Override
public void onFailure(retrofit2.Call<BookResponce> call, Throwable t) {
Toast.makeText(this, "failed", Toast.LENGTH_LONG).show();
}
});
If anyone has a more optimal solution is welcome to edit/add his!
I want to parse nested json using retrofit and bind it in recyclerview. Am familiar with Parsing simple json using Retrofit. But i dont know how to parse nested json using retrofit. i am newbie to retrofit. any help will be appreciated ?
Here is that Link: http://api.wunderground.com/api/356d60036a9374e9/conditions/forecast/alert/q/22.897,88.879.json
JSON DATA :
{
"response": {
"version":"0.1",
"termsofService":"http://www.wunderground.com/weather/api/d/terms.html",
"features": {
"conditions": 1
,
"forecast": 1
}
,
"error": {
"type": "unknownfeature"
}
}
, "current_observation": {
"image": {
"url":"http://icons.wxug.com/graphics/wu2/logo_130x80.png",
"title":"Weather Underground",
"link":"http://www.wunderground.com"
},
"display_location": {
"full":"Tentulbaria, India",
"city":"Tentulbaria",
"state":"WB",
"state_name":"India",
"country":"IN",
"country_iso3166":"IN",
"zip":"00000",
"magic":"608",
"wmo":"41946",
"latitude":"22.890000",
"longitude":"88.870000",
"elevation":"11.9"
},
"observation_location": {
"full":"Kolkata, ",
"city":"Kolkata",
"state":"",
"country":"IN",
"country_iso3166":"IN",
"latitude":"22.64999962",
"longitude":"88.44999695",
"elevation":"20 ft"
},
"estimated": {
},
"station_id":"VECC",
"observation_time":"Last Updated on February 5, 5:30 PM IST",
"observation_time_rfc822":"Mon, 05 Feb 2018 17:30:00 +0530",
"observation_epoch":"1517832000",
"local_time_rfc822":"Mon, 05 Feb 2018 17:44:32 +0530",
"local_epoch":"1517832872",
"local_tz_short":"IST",
"local_tz_long":"Asia/Kolkata",
"local_tz_offset":"+0530",
"weather":"Clear",
"temperature_string":"81 F (27 C)",
"temp_f":81,
"temp_c":27,
"relative_humidity":"61%",
"wind_string":"Calm",
"wind_dir":"North",
"wind_degrees":0,
"wind_mph":0,
"wind_gust_mph":0,
"wind_kph":0,
"wind_gust_kph":0,
"pressure_mb":"1013",
"pressure_in":"29.92",
"pressure_trend":"0",
"dewpoint_string":"66 F (19 C)",
"dewpoint_f":66,
"dewpoint_c":19,
"heat_index_string":"83 F (28 C)",
"heat_index_f":83,
"heat_index_c":28,
"windchill_string":"NA",
"windchill_f":"NA",
"windchill_c":"NA",
"feelslike_string":"83 F (28 C)",
"feelslike_f":"83",
"feelslike_c":"28",
"visibility_mi":"1.7",
"visibility_km":"2.8",
"solarradiation":"--",
"UV":"-1","precip_1hr_string":"-9999.00 in (-9999.00 mm)",
"precip_1hr_in":"-9999.00",
"precip_1hr_metric":"--",
"precip_today_string":"0.00 in (0.0 mm)",
"precip_today_in":"0.00",
"precip_today_metric":"0.0",
"icon":"clear",
"icon_url":"http://icons.wxug.com/i/c/k/nt_clear.gif",
"forecast_url":"http://www.wunderground.com/global/stations/41946.html",
"history_url":"http://www.wunderground.com/history/airport/VECC/2018/2/5/DailyHistory.html",
"ob_url":"http://www.wunderground.com/cgi-bin/findweather/getForecast?query=22.64999962,88.44999695",
"nowcast":""
}
}
In that json data i want to fetch the following json data:
"current_observation": {
"image": {
"url":"http://icons.wxug.com/graphics/wu2/logo_130x80.png",
"title":"Weather Underground",
"link":"http://www.wunderground.com"
},
First, create Model i.e POJO class to parse your response
It will look something like this
package app.com.socket;
/**
* Created by akshay.katariya on 05-Feb-18.
*/
import com.google.gson.annotations.SerializedName;
public class Pojo
{
#SerializedName("response")
public Response response;
#SerializedName("current_observation")
public Current_observation current_observation;
public static class Features {
#SerializedName("conditions")
public int conditions;
#SerializedName("forecast")
public int forecast;
}
public static class Error {
#SerializedName("type")
public String type;
}
public static class Response {
#SerializedName("version")
public String version;
#SerializedName("termsofService")
public String termsofService;
#SerializedName("features")
public Features features;
#SerializedName("error")
public java.lang.Error error;
}
public static class Image {
#SerializedName("url")
public String url;
#SerializedName("title")
public String title;
#SerializedName("link")
public String link;
}
public static class Display_location {
#SerializedName("full")
public String full;
#SerializedName("elevation")
public String elevation;
}
public static class Observation_location {
#SerializedName("elevation")
public String elevation;
}
public static class Estimated {
}
public static class Current_observation {
#SerializedName("image")
public Image image;
#SerializedName("display_location")
public Display_location display_location;
#SerializedName("observation_location")
public Observation_location observation_location;
#SerializedName("estimated")
public Estimated estimated;
#SerializedName("nowcast")
public String nowcast;
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
public Display_location getDisplay_location() {
return display_location;
}
public void setDisplay_location(Display_location display_location) {
this.display_location = display_location;
}
public Observation_location getObservation_location() {
return observation_location;
}
public void setObservation_location(Observation_location observation_location) {
this.observation_location = observation_location;
}
public Estimated getEstimated() {
return estimated;
}
public void setEstimated(Estimated estimated) {
this.estimated = estimated;
}
public String getNowcast() {
return nowcast;
}
public void setNowcast(String nowcast) {
this.nowcast = nowcast;
}
}
public Response getResponse() {
return response;
}
public void setResponse(Response response) {
this.response = response;
}
public Current_observation getCurrent_observation() {
return current_observation;
}
public void setCurrent_observation(Current_observation current_observation) {
this.current_observation = current_observation;
}
}
Generate proper getter & setter
Then in your main class create
Pojo model = new Pojo();
Call API & Parse the response
model = response.body(); // retrofit api call parsing
You have all your values ready to set
mEditText.setText(model.getCurrent_observation().image.url);
You can add json convertor to Retrofit and you can parse it.
Parsing Nested Json
Retrofit best tutorial i have found till now.
Retrofit complete turoial.
This will help you in all your concerns related to Retrofit.
Create mode like this and in your response type pass the model it will automatically parse the json into model for image data
public class Example {
#SerializedName("current_observation")
#Expose
private CurrentObservation currentObservation;
public CurrentObservation getCurrentObservation() {
return currentObservation;
}
public void setCurrentObservation(CurrentObservation currentObservation) {
this.currentObservation = currentObservation;
}
public static class CurrentObservation {
#SerializedName("image")
#Expose
private Image image;
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
}
public static class Image {
#SerializedName("url")
#Expose
private String url;
#SerializedName("title")
#Expose
private String title;
#SerializedName("link")
#Expose
private String link;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
}
}
sample api call
public interface Service {
#GET("users/info")
Call<Example> getInfo();
}
Edit:
you can call this retrofit function anywhere in your MainActivity and use the data.
public void getImageData(){
Call<Example> call = apiService.getInfo();
call.enqueue(new Callback<Example>() {
#Override
public void onResponse(Call<Example> call, Response<Example> response) {
//this is how you can use the parsed model
Example info = response.body();
}
#Override
public void onFailure(Call<Example> call, Throwable t) {
//handle the error here
}
}
Simple way is to receive response as a JsonObject / JsonArray and parse it to create object with your own Model class.
So that you can avoid unwanted data, yes your code will be lengthy but its worth it. You can format and store the data. Easy to display.
Also "Opt" methods can be used instead of "Get", so NULL can be avoided.
I am trying to get a specific Item from an API in my android application.
Here is the JSON response of the api:
{
"response": {
"items": [
{
"episode_id": 9599548,
"type": "RECORDED",
"title": "Adabule muferad 100916",
"duration": 3165940,
"explicit": false,
"show_id": 1392538,
"author_id": 7725967,
"site_url": "https://www.spreaker.com/episode/9599548",
"image_url": "https://d1bm3dmew779uf.cloudfront.net/large/f390b915e356de35055d971be5110dcb.jpg",
"image_original_url": "https://d3wo5wojvuv7l.cloudfront.net/images.spreaker.com/original/f390b915e356de35055d971be5110dcb.jpg",
"published_at": "2016-10-09 11:01:48",
"download_enabled": true,
"waveform_url": "https://d3770qakewhkht.cloudfront.net/episode_9599548.gz.json?v=qB6pQ6"
}
],
"next_url": "https://api.spreaker.com/v2/users/7725967/episodes?filter=listenable&last_id=9599548&limit=1"
}
}
I have three Java classes Items, Response and RadioProgramInfo.
Here are their codes respectively:
Items.java
public class Items
{
public String duration;
public String title;
public String download_enabled;
public String image_original_url;
public String image_url;
public String explicit;
public String episode_id;
public String author_id;
public String show_id;
public String type;
public String waveform_url;
public String published_at;
public String site_url;
public String getDuration ()
{
return duration;
}
public void setDuration (String duration)
{
this.duration = duration;
}
public String getTitle ()
{
return title;
}
public void setTitle (String title)
{
this.title = title;
}
public String getDownload_enabled ()
{
return download_enabled;
}
public void setDownload_enabled (String download_enabled)
{
this.download_enabled = download_enabled;
}
public String getImage_original_url ()
{
return image_original_url;
}
public void setImage_original_url (String image_original_url)
{
this.image_original_url = image_original_url;
}
public String getImage_url ()
{
return image_url;
}
public void setImage_url (String image_url)
{
this.image_url = image_url;
}
public String getExplicit ()
{
return explicit;
}
public void setExplicit (String explicit)
{
this.explicit = explicit;
}
public String getEpisode_id ()
{
return episode_id;
}
public void setEpisode_id (String episode_id)
{
this.episode_id = episode_id;
}
public String getAuthor_id ()
{
return author_id;
}
public void setAuthor_id (String author_id)
{
this.author_id = author_id;
}
public String getShow_id ()
{
return show_id;
}
public void setShow_id (String show_id)
{
this.show_id = show_id;
}
public String getType ()
{
return type;
}
public void setType (String type)
{
this.type = type;
}
public String getWaveform_url ()
{
return waveform_url;
}
public void setWaveform_url (String waveform_url)
{
this.waveform_url = waveform_url;
}
public String getPublished_at ()
{
return published_at;
}
public void setPublished_at (String published_at)
{
this.published_at = published_at;
}
public String getSite_url ()
{
return site_url;
}
public void setSite_url (String site_url)
{
this.site_url = site_url;
}
#Override
public String toString()
{
return "ClassPojo [duration = "+duration+", title = "+title+", download_enabled = "+download_enabled+", image_original_url = "+image_original_url+", image_url = "+image_url+", explicit = "+explicit+", episode_id = "+episode_id+", author_id = "+author_id+", show_id = "+show_id+", type = "+type+", waveform_url = "+waveform_url+", published_at = "+published_at+", site_url = "+site_url+"]";
}
}
Response.java
public class Response
{
private Items[] items;
private String next_url;
public Items[] getItems ()
{
return items;
}
public void setItems (Items[] items)
{
this.items = items;
}
public String getNext_url ()
{
return next_url;
}
public void setNext_url (String next_url)
{
this.next_url = next_url;
}
#Override
public String toString()
{
return "ClassPojo [items = "+items+", next_url = "+next_url+"]";
}
}
RadioProgramInfo.java
public class RadioProgramInfo
{
private Response response;
public Response getResponse ()
{
return response;
}
public void setResponse (Response response)
{
this.response = response;
}
#Override
public String toString()
{
return "ClassPojo [response = "+response+"]";
}
}
I am trying to access a specific Item called "site_url" which is located in Items.java
The code in my main class to try to access site_url is this:
Items url2 = new Items();
String streamURL = String.valueOf(url2)+"/shoutcast?force_http=true";
// new HttpRequestTask().execute();
// return true;
String url = "http://api.spreaker.com/listen/episode/9451446/shoutcast?force_http=true";
//String url2 = Items.class.getName(site_url);
public MainActivity() {
}
//System.out.println(streamURL);
public class HttpRequestTask extends AsyncTask<Void, Void, Items> {
protected Items doInBackground(Void... params) {
try {
final String url = String.valueOf(streamURL);
RestTemplate restTemplate = new RestTemplate();
//restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
Items streamlink = restTemplate.getForObject(url, Items.class);
return streamlink;
}
catch (Exception e) {
Log.e("MainActivity", e.getMessage(), e);
}
return url2;
}
}
When I run my program (a media player app):
It tells me that the url is null in value (I debug mode on the program as it executes).
How do I correctly access the item in the JSON response I am after?
I am really stuck on this one.
---UPDATE-----
Here is the response from the console:
10-09 15:25:39.522 2586-2647/software.blackstone.com.salafimasjidradioseries E/MainActivity: 'messageConverters' must not be empty
java.lang.IllegalArgumentException: 'messageConverters' must not be empty
at org.springframework.util.Assert.notEmpty(Assert.java:269)
at org.springframework.web.client.HttpMessageConverterExtractor.<init>(HttpMessageConverterExtractor.java:53)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:235)
at software.blackstone.com.salafimasjidradioseries.MainActivity$HttpRequestTask.doInBackground(MainActivity.java:46)
at software.blackstone.com.salafimasjidradioseries.MainActivity$HttpRequestTask.doInBackground(MainActivity.java:39)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
.... and the complete MainActivity Code is this:
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.Toast;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
static MediaPlayer mPlayer;
ImageButton buttonPlay;
ImageButton buttonStop;
Items url2 = new Items();
String streamURL = String.valueOf(url2)+"/shoutcast?force_http=true";
// new HttpRequestTask().execute();
// return true;
String url = "http://api.spreaker.com/listen/episode/9451446/shoutcast?force_http=true";
//String url2 = Items.class.getName(site_url);
public MainActivity() {
}
//System.out.println(streamURL);
public class HttpRequestTask extends AsyncTask<Void, Void, Items> {
protected Items doInBackground(Void... params) {
try {
final String url = String.valueOf(streamURL);
RestTemplate restTemplate = new RestTemplate();
//restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
Items streamlink = restTemplate.getForObject(url, Items.class);
return streamlink;
}
catch (Exception e) {
Log.e("MainActivity", e.getMessage(), e);
}
return url2;
}
}
#Override
protected void onStart() {
super.onStart();
new HttpRequestTask().execute();
}
i admittedly don't have any experience using Spring libraries for mobile development. there are, however, several other popular libraries at your disposal that are typically used to accomplish your goal.
below is an example i whipped using your DTO classes. i added these dependencies via my app's build.gradle:
compile 'com.squareup.okhttp:okhttp:2.7.5'
compile 'com.google.code.gson:gson:2.4'
OkHttp is a library for creating + executing HTTP requests
Gson is a library for (un)marshaling data as json
the code should be pretty self-explanatory. i've just plugged in the bits to do my HTTP GET and marshal the data into the DTO within the AsyncTask.
public class MainActivity extends AppCompatActivity {
private MediaPlayer mPlayer = new MediaPlayer();
private OkHttpClient client = new OkHttpClient();
private Gson gson = new Gson();
public class HttpRequestTask extends AsyncTask<Void,Void,Items[]> {
protected Items[] doInBackground(Void... params) {
final Request request = new Request.Builder()
.url("https://api.myjson.com/bins/1z98u")
.build();
Items[] items = null;
try {
final com.squareup.okhttp.Response response = client.newCall(request).execute();
if(response.isSuccessful()) {
final RadioProgramInfo radioProgramInfo = gson.fromJson(response.body().charStream(), RadioProgramInfo.class);
items = radioProgramInfo.getResponse().getItems();
} else {
throw new RuntimeException("ooops!");
}
} catch (Throwable t) {
Log.e("MainActivity", t.getMessage(), t);
}
return items;
}
#Override
protected void onPostExecute(Items[] items) {
try {
mPlayer.setDataSource(items[0].getSite_url());
mPlayer.prepareAsync();
} catch(IOException e) {
e.printStackTrace();
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
new HttpRequestTask().execute();
}
}
hope that helps!
Since youre not really sure what to use and are currently using Spring, I'd recommend you to take a look at Retrofit which does exactly what you are looking for. It has very good documentation and a lot of examples of exactly what you're trying to do.. Here's a pretty good introduction to it: square.github.io/retrofit
I am working on the final project for an intro to Java class. Part of the project involves getting a lyric snippet from MusixMatch using their API. I am able to get lyrics from the API using track.lyrics.get, but cannot get snippets using tracks.snippet.get.
I started with a Java wrapper found here: https://github.com/sachin-handiekar/jMusixMatch and added my own classes to get a snippet based on the track.snippet.get API method.
When I run the program I get this error:
java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at
line 1 column 102 path $.message.body
My getSnippet method and applicable classes follow. They are based on the getLyrics method and classes found in the original wrapper.
public Snippet getSnippet(int trackID) throws MusixMatchException {
Snippet snippet = null;
SnippetGetMessage message = null;
Map<String, Object> params = new HashMap<String, Object>();
params.put(Constants.API_KEY, apiKey);
params.put(Constants.TRACK_ID, new String("" + trackID));
String response = null;
response = MusixMatchRequest.sendRequest(Helper.getURLString(
Methods.TRACK_SNIPPET_GET, params));
Gson gson = new Gson();
try {
message = gson.fromJson(response, SnippetGetMessage.class);
} catch (JsonParseException jpe) {
handleErrorResponse(response);
}
snippet = message.getContainer().getBody().getSnippet();
return snippet;
}
The Snippet Class
package org.jmusixmatch.entity.snippet;
import com.google.gson.annotations.SerializedName;
/**
* Created by kyledhebert on 4/30/15.
* Objects of this clas represent a lyric snippet from the
* MusixMatch API.
*/
public class Snippet {
#SerializedName("snippet_language")
private int snippetLanguage;
#SerializedName("restricted")
private int restricted;
#SerializedName("instrumental")
private int instrumental;
#SerializedName("snippet_body")
private String snippetBody;
#SerializedName("script_tracking_url")
private String scriptTrackingURL;
#SerializedName("pixel_tracking_url")
private String pixelTrackingURL;
#SerializedName("html_tracking_url")
private String htmlTrackingURL;
#SerializedName("updated_time")
private String updatedTime;
public int getSnippetLanguage() {
return snippetLanguage;
}
public void setSnippetLanguage(int snippetLanguage) {
this.snippetLanguage = snippetLanguage;
}
public int getRestricted() {
return restricted;
}
public void setRestricted(int restricted) {
this.restricted = restricted;
}
public int getInstrumental() {
return instrumental;
}
public void setInstrumental(int instrumental) {
this.instrumental = instrumental;
}
public String getSnippetBody() {
return snippetBody;
}
public void setSnippetBody(String snippetBody) {
this.snippetBody = snippetBody;
}
public String getPixelTrackingURL() {
return pixelTrackingURL;
}
public void setPixelTrackingURL(String pixelTrackingURL) {
this.pixelTrackingURL = pixelTrackingURL;
}
public String getScriptTrackingURL() {
return scriptTrackingURL;
}
public void setScriptTrackingURL(String scriptTrackingURL) {
this.scriptTrackingURL = scriptTrackingURL;
}
public String getHtmlTrackingURL() {
return htmlTrackingURL;
}
public void setHtmlTrackingURL(String htmlTrackingURL) {
this.htmlTrackingURL = htmlTrackingURL;
}
public String getUpdatedTime() {
return updatedTime;
}
public void setUpdatedTime(String updatedTime) {
this.updatedTime = updatedTime;
}
}
The SnippetGetBody class:
package org.jmusixmatch.entity.snippet.get;
import com.google.gson.annotations.SerializedName;
import org.jmusixmatch.entity.snippet.Snippet;
public class SnippetGetBody {
#SerializedName("snippet")
private Snippet snippet;
public Snippet getSnippet() {
return snippet;
}
public void setSnippet(Snippet snippet) {
this.snippet = snippet;
}
}
The SnippetGetContainer class:
package org.jmusixmatch.entity.snippet.get;
import com.google.gson.annotations.SerializedName;
import org.jmusixmatch.entity.Header;
public class SnippetGetContainer {
#SerializedName("body")
private SnippetGetBody body;
#SerializedName("header")
private Header header;
public SnippetGetBody getBody() {
return body;
}
public void setBody(SnippetGetBody body) {
this.body = body;
}
public Header getHeader() {
return header;
}
public void setHeader(Header header) {
this.header = header;
}
}
The SnippetGetMessage class:
package org.jmusixmatch.entity.lyrics.get;
import com.google.gson.annotations.SerializedName;
public class SnippetGetMessage {
#SerializedName("message")
private SnippetGetContainer container;
public void setContainer(SnippetGetContainer container) {
this.container = container;
}
public SnippetGetContainer getContainer() {
return container;
}
}
I was not able to reproduce your exact error message, but I did find the following error: snippet_language is a String, not an int. Change the type (and associated getters and setters) to:
#SerializedName("snippet_language")
private String snippetLanguage;
I used the sample Json response from here to make this work. If these two changes don't fix your problem, please edit your question with the actual Json response that is making your program not work.