How to parse json with retrofit on Android - java

I try to write app which parse decoding of abbreviations and frequency of their use. User input abbreviation, for example "kg". So, app should connect to "http://nactem.ac.uk/software/acromine/dictionary.py?sf=kg" and parse it.
What should model classes look like? Did I describe #Geth correctly in the interface? How can I get the list, I made an adapter, bind it to the list, but I'm not sure about getResponse ().
Interface:
public interface SService {
#GET("dictionary.py?")
Call<Example> getResponse(#Query("sf=") String searchString);
}
Retrofit client:
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl) {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
And addition class ApiUtils
public class ApiUtils {
public static final String BASE_URL = "http://nactem.ac.uk/software/acromine/";
public static SService getSOService() {
return RetrofitClient.getClient(BASE_URL).create(SService.class);
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
private ArrayList<Lf> elements = new ArrayList();
EditText editText1;
ElementAdapter stateAdapter;
ListView list;
private SService mService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText1 = (EditText) findViewById(R.id.edit_text);
mService = ApiUtils.getSOService();
list = (ListView) findViewById(R.id.fragment_list);
stateAdapter = new ElementAdapter(this, R.layout.list_item, elements);
list.setAdapter(stateAdapter);
}
public void loadAnswers() {
mService.getResponse(editText1.getText().toString()).enqueue(new Callback<Example>() {
#Override
public void onResponse(Call<Example> call, Response<Example> response) {
if(response.isSuccessful()) {
stateAdapter.updateAnswers(response.body().getLfs());
} else {
int statusCode = response.code();
// handle request errors depending on status code
}
}
#Override
public void onFailure(Call<Example> call, Throwable t) {
}
});
}
public void activity_button(View view) {
//stateAdapter.clear();
loadAnswers();
}
}
UPD!!
All input data is an array: Array[Object{...}]. Right interface for parsing it:
public interface SService {
#GET("dictionary.py")
Call<List<Example>> getResponse(#Query("sf") String searchString);
}
So, we get with Call List with Example object (Only one object in this case).

Change the SService interface to the following,
public interface SService {
#GET("dictionary.py")
Call<Example> getResponse(#Query("sf") String searchString);
}

Related

Retrofit expecting an array not an object

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.

How to solve Retrofit2 interface null pointer

i try to connect my server and i stuck here about 3 hours. Simply use this in another project but... anyway here is my interface and service generator. Please help me...
ServiceGenerator
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class ServiceGenerator {
private ServiceInterface serviceInterface;
private String BASE_URL = "http://xxxxxxxxx.com/xxxxx/xxx/";
public ServiceInterface init() {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.build();
serviceInterface = retrofit.create(ServiceInterface.class);
return serviceInterface;
}
public ServiceInterface getServiceInterface() {
return serviceInterface;
}
}
SevrviceInterface
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface ServiceInterface {
#GET("login.php")
Call<LoginResponse> login(#Query("UserName") String id,
#Query("Password") String pass,
#Query("token") String token
);
}
xxxxxxApp
import android.app.Application;
import com.xxxxxxxxxxxxx.network.ServiceGenerator;
import com.xxxxxxxxxxxxx.network.ServiceInterface;
public class xxxxxxApp extends Application {
private static xxxxxxApp instance;
private ServiceGenerator serviceGenerator = new ServiceGenerator();
public static xxxxxxApp getInstance() {
return instance;
}
#Override
public void onCreate() {
super.onCreate();
instance = this;
serviceGenerator.init();
}
public ServiceInterface getServiceInterface() {
return serviceGenerator.getServiceInterface();
}
}
LoginAct.java
public class LoginAct extends BaseActivity {
SharedPreferences preferences;
Button btn_login;
EditText edt_username;
EditText edt_pass;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_login);
btn_login = findViewById(R.id.login_btn_login);
edt_username = findViewById(R.id.lgn_et_username);
edt_pass = findViewById(R.id.lgn_et_pass);
btn_login.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
xxxxxxApp.getInstance().getServiceInterface().login(edt_username.getText().toString(),edt_pass.getText().toString(),"").enqueue(new Callback<LoginResponse>() {
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
if (response.isSuccessful()){
LoginAct.super.showToast(LoginAct.this," UserID : "+response.body().getUsers().get(0).getUser_ıd());
}
}
#Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
}
});
}
});
}
}
And if you cath my url doesn't have SSL its http:// . My error says :
java.lang.NullPointerException: Attempt to invoke virtual method 'com.xxxxxxxxxxxxxxxx.network.ServiceInterface com.xxxxxxxxxxxxxxxx.xxxxxxApp.getServiceInterface()' on a null object reference
at com.xxxxxxxxxxxxxxxx.ui.LoginAct$1.onClick(LoginAct.java:40)
I can't figure out how to solve this i try everything i can. please help.
.
.
.
.
.
.
.
.
Set your base url into
private String BASE_URL = "http://xxxxxxxxx.com/xxxxx";
and interface into
#GET("/xxx/login.php")
Call<LoginResponse> login(#Query("UserName") String id,
#Query("Password") String pass,
#Query("token") String token
);

Retrofit call contains error Required retrofit2.Call, found void

Hello I recently started retrofit While implementing the code im getting this error
Incompatible types.
Required: retrofit2.Call <java.util.List<com.my.package.Youtube.YoutubePost>>
Found: void
I was trying to get YouTube channel playlist using Youtube v3 API
This is my code for the same
YoutubeActivity
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(ScalarsConverterFactory.create())
.baseUrl(AppConstant.API_YT_BASE)
.addConverterFactory(GsonConverterFactory.create())
.build();
YoutubeApiInterface youtubeApiInterface = retrofit.create(YoutubeApiInterface.class);
Call<List<YoutubePost>> call = youtubeApiInterface.getPlayList().enqueue(new Callback<List<YoutubePost>>() {
#Override
public void onResponse(Call<List<YoutubePost>> call, Response<List<YoutubePost>> response) {
if (response.isSuccessful()) {
} else {
}
}
#Override
public void onFailure(Call<List<YoutubePost>> call, Throwable t) {
t.printStackTrace();
}
});
YoutubePost
public class YoutubePost implements Parcelable {
#SerializedName("items")
private List<YoutubeItems> ytItems = new ArrayList<>();
private String nextPageToken;
public List<YoutubeItems> getYtItems() {
return ytItems;
}
public String getNextPageToken() {
return nextPageToken;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeList(ytItems);
dest.writeString(nextPageToken);
}
protected YoutubePost(Parcel in) {
ytItems = in.readParcelable(YoutubeItems.class.getClassLoader());
nextPageToken = in.readString();
}
public static final Creator<YoutubePost> CREATOR = new Creator<YoutubePost>() {
#Override
public YoutubePost createFromParcel(Parcel source) {
return new YoutubePost(source);
}
#Override
public YoutubePost[] newArray(int size) {
return new YoutubePost[size];
}
};
}
Screenshot of error message attached below
I suggest you, to modify the getPlayList method a little bit, to return with a Call, then break the lines.
Without your YoutubeApiInterface this is all I got.
Call<List<YoutubePost>> call = youtubeApiInterface.getPlayList();
call.enqueue(new Callback<List<YoutubePost>>() {
#Override
public void onResponse(Call<List<YoutubePost>> call, Response<List<YoutubePost>> response) {
if (response.isSuccessful()) {
} else {
}
}.
#Override
public void onFailure(Call<List<YoutubePost>> call, Throwable t) {
t.printStackTrace();
}
});
By this you won't have a type problem, because the call itself will be modified, during the enqueue.

How do I get an item from POJO classes in Android?

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

Updating class field from callback

I'm trying to connect to API using Retrofit. I need to login user and after this set "user" field which contains session key which is required to all other api calls. So I need to have it available before executing any code but I don't know how to check or block code until this field will be set. Any ideas how to do it?
public class ApiClient {
public static final String developerKey = "";
public static final String applicationKey = "";
static final String BASE_URL =
"https://secure.techfortesco.com/tescolabsapi";
public ApiService mApiService;
public User user;
public ApiClient() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel( RestAdapter.LogLevel.FULL )
.setEndpoint( BASE_URL )
.build();
if(mApiService == null) {
mApiService = restAdapter.create( ApiService.class );
}
}
public void login() {
mApiService.login( developerKey, applicationKey, new Callback<User>() {
#Override
public void success ( User user, Response response ) {
//code which should update user field
}
#Override
public void failure ( RetrofitError error ) {
}
} );
}
public interface ApiService {
#GET ("/restservice.aspx?command=LOGIN&email=&password=")
public void login (
#Query ("developerkey") String developerKey,
#Query ("applicationkey") String applicationKey,
Callback<User> callback );
#GET ("/restservice.aspx?command=PRODUCTSEARCH")
public void search (
#Query ("searchtext") String searchText,
#Query ("sessionkey") String sessionKey,
Callback<Pojo.SearchResult> callback);
}
}
You can try using callback:
Example:
public interface LoginCallback {
void ready();
}
And in the Activity / Fragment
public MainActivity extends Activity {
public void onCreate() {
super.onCreate();
ApiClient client = new ApiClient();
client.login(new LoginCallback() {
#Override
public void ready() {
//... do your next request in the API.
}
});
}
}
and your login method became:
public void login(final LoginCallback loginCallback) {
mApiService.login( developerKey, applicationKey, new Callback<User>() {
#Override
public void success ( User user, Response response ) {
//code which should update user field
loginCallback.ready();
}
#Override
public void failure ( RetrofitError error ) {
}
} );
}

Categories

Resources