I'm making a response to this Google Books API URL
I have an Retrofit request:'
public interface BookApiService {
#GET("/books/v1/volumes")
Call<Books> getBooks(#Query("q") String query);
}
And have an Entity classes
Books.java
public class Books {
#SerializedName("items")
#Expose
private List<Book> items;
public List<Book> getItems() {
return items;
}
}
and Book.java
public class Book {
#SerializedName("title")
#Expose
private String mTitle;
public String getTitle() {
return mTitle;
}
}
Request is working correct, i mean no errors with connection, and retrofit returns onResponse, not onFailure.
But my String "title" is null. How can i get this. Please check JSON response by link above.
UPDATE:
Retrofit call:
public class BookService{
private static final String BASE_URL = "https://www.googleapis.com/";
private BookApiService mApiService;
private BookCallback mListener;
public BookService(BookCallback listener){
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.build();
mApiService = retrofit.create(BookApiService.class);
mListener = listener;
}
public void getBooks(String query){
Call<Books> call = mApiService.getBooks(query);
call.enqueue(new Callback<Books>() {
#Override
public void onResponse(Call<Books> call, Response<Books> response) {
mListener.notifyDataReceived(response.body());
}
#Override
public void onFailure(Call<Books> call, Throwable t) {
mListener.notifyErrorReceived(t);
}
});
}
public interface BookCallback{
void notifyDataReceived(Books books);
void notifyErrorReceived(Throwable error);
}
BookCallback listener is my MainActivity:
When i check Logs, there is
"SUCCESS" "TITLE 1 null"
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.recycler_view);
mRecyclerView.addItemDecoration(new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL));
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
new BookService(this).getBooks("android");
}
#Override
public void notifyDataReceived(Books books) {
if(books.getItems() != null) {
List<Book> items = books.getItems();
Log.d(TAG, "Success");
Log.d(TAG, "TITLE 1" + items.get(0).getTitle());
setupAdapter(items);
}
}
You can request the JSON directly in your browser here. Looking closely at this data, you will see that items[0] doesn't have a property title. Instead, there is a property volumeInfo that contains title. Your Retrofit entity class needs to correctly navigate to that property in order to get the data you need.
Related
I was testing the API in the Retrofit for first time, I was putting the code that they were showing but I don't know why my code doesn't work
it just shows that I am receiving the null value;
I was learning to implement the Retrofit library in my android app . so i was following some tutorial and i was following the code but don't know why i am getting this error
i tried to solve the error by changing the url but the response is the same it shows the null.
Please help me out
public class Todo {
private int userId;
private int id;
private String todo;
private boolean completed;
public int getUserId() {
return userId;
}
public int getId() {
return id;
}
public String getTitle() {
return todo;
}
public boolean isCompleted() {
return completed;
}
}
public interface ApiInterface {
#GET("/todo/{id}")
Call<Todo> getTodo(#Path("id") int id);
}
public class ApiClient {
private static final String BASE_URL ="https://dummyjson.com";
private static Retrofit retrofit= null;
public static Retrofit getclient(){
if(retrofit == null){
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
public class MainActivity extends AppCompatActivity {
TextView hello;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
hello= findViewById(R.id.textview);
ApiInterface apiInterface = ApiClient.getclient().create(ApiInterface.class);
Call<Todo> call =apiInterface.getTodo(1);
call.enqueue(new Callback<Todo>() {
#Override
public void onResponse(Call<Todo> call, Response<Todo> response) {
Log.e("info","onResponse"+response.body());
#Override
public void onFailure(Call<Todo> call, Throwable t) {
Log.e("info","onFailure" + t.getLocalizedMessage());
}
});
}
}
You are missing the plural 's' in todo. Change your path to #GET("/todos/{id}")
I'm making requets to Google Books API with Retrofit2 and use GSON converter, but have an error
ErrorExpected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path
$
API URL to JSON
This is my
BookService.java
public class BookService{
private static final String BASE_URL = "https://www.googleapis.com/";
private BookApiService mApiService;
private BookCallback mListener;
public BookService(BookCallback listener){
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.build();
mApiService = retrofit.create(BookApiService.class);
mListener = listener;
}
public void getBooks(String query){
final ApiResponse apiResponse = new ApiResponse();
Call<List<Book>> call = mApiService.getBooks(query);
call.enqueue(new Callback<List<Book>>() {
#Override
public void onResponse(Call<List<Book>> call, Response<List<Book>> response) {
apiResponse.setBooks(response.body());
mListener.notifyDataReceived(apiResponse);
}
#Override
public void onFailure(Call<List<Book>> call, Throwable t) {
apiResponse.setError(t);
mListener.notifyDataReceived(apiResponse);
}
});
}
public interface BookCallback{
void notifyDataReceived(ApiResponse apiResponse);
}
}
and my Interface
BookApiService.java
public interface BookApiService {
#GET("/books/v1/volumes")
Call<List<Book>> getBooks(#Query("q") String query);
}
Then making request from MainActivity.java that implements BookCallback
public class MainActivity extends AppCompatActivity implements BookService.BookCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main)
new BookService(this).getBooks("android");
}
}
Your response is not an array. its an object with array in it.
For fix this you must create other response class like BookResponse
BookResponse.java
public class BookResponse{
#SerializedName("kind")
private Sting kind;
#SerializedName("totalItems")
private Int totalItems;
#SerializedName("items")
private List<Book> items;
}
And change your interface like this
public interface BookApiService {
#GET("/books/v1/volumes")
Call<BookResponse> getBooks(#Query("q") String query);
}
The response you are having is not an array of Books, but it is an object, which perhaps is a response that has an array with books. So what the error says: Your JsonResponse is not starting with [] but is starting with {}
I am very new to Android development. I have this little project of mine that I need to get to work by accessing an api that I created locally on my mac with deployd. The api is accessible from localhost:2403/subjects. I have followed the retrofit and gson guide but so far I only keep errors and nothing viable to work with. At this point im kinda stuck. I need to get the subjects from the api and show them in a scrollable list.
I have set up Retrofit and Gson to be able to talk to the API. Therefore I have made a few classes and interfaces.
First the Subject class
public class Subject {
int id;
String name;
int ects;
int grade;
int period;
int main;
public int getMain() {
return main;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getEcts() {
return ects;
}
public int getGrade() {
return grade;
}
public int getPeriod() {
return period;
}
}
then I created a HslSubjects class which is plain and simple to hold all the subjects I get.
public class HslSubjects {
List<Subject> subjects;
}
and the api interface
public interface subjectEndpointApi {
#GET("/subjects")
Call<HslSubjects> loadSubjects();
}
followed by an adapter
public class SubjectResponse {
#SerializedName("subjects")
List<Subject> subjects;
public SubjectResponse() {
subjects = new ArrayList<Subject>();
}
public static SubjectResponse parseJSON(String response) {
Gson gson = new GsonBuilder().create();
SubjectResponse subjectResponse = gson.fromJson(response, SubjectResponse.class);
return subjectResponse;
}
}
Finally in my mainActivity I run everything
public class MainActivity extends ListActivity implements Callback<HslSubjects> {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
requestWindowFeature(Window.FEATURE_PROGRESS);
ArrayAdapter<Subject> arrayAdapter = new ArrayAdapter<Subject>(this, android.R.layout.simple_list_item_1, android.R.id.text1, new ArrayList<Subject>());
setListAdapter(arrayAdapter);
setProgressBarIndeterminateVisibility(true);
setProgressBarVisibility(true);
Log.i("api", "preparing to make the api call");
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://10.0.3.2:2403") //10.0.3.2
.addConverterFactory(GsonConverterFactory.create())
.build();
// preparing the call in retrofit
subjectEndpointApi subjectEndpointApi = retrofit.create(subjectEndpointApi.class);
Call<HslSubjects> call = subjectEndpointApi.loadSubjects();
call.enqueue(this);
}
#Override
public void onResponse(Call<HslSubjects> call, Response<HslSubjects> response) {
setProgressBarIndeterminateVisibility(false);
HslSubjects hslSubjects = response.body();
Log.i("subjects", "end of response");
}
#Override
public void onFailure(Call<HslSubjects> call, Throwable t) {
Toast.makeText(MainActivity.this, t.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
Log.i("subjects", "Oops error");
}
}
But somehow it always goes to the onFailure class. The emulator gives the following error:
Seems like your server JSON is not what you are expecting on your device.
Error says that android wants JSON object, but the json you pass is kinda array.
Try to add logging and see what is the problem there.
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
So I guess you should write something like:
public interface subjectEndpointApi {
#GET("/subjects")
Call<List<Subject>> loadSubjects();
}
I'm trying to get data from web api but something is wrong and I can't figure it out.
My JSON looks like this
{
"partners":
[
"partner1",
"partner2",
"partner3",
... ,
"partner150"
]
}
I have Table partners (ActiveAndroid) in which I would like to save all partners from api.
#Table(name = "Partners")
public class Partners extends Model {
#Column(name = "Name")
String name;
public Partners() {}
public Partners(String name) {
this.name = name;
}
}
Here is my Pojo model class:
public class Partners extends ArrayList<String> {
#SerializedName("partners")
#Expose
public List<String> partners = new ArrayList<String>();
public List<String> getPartners() {
return partners;
}
public void setName(List<String> partners) {
this.partners = partners;
}
}
This is my interface
public interface APIService {
#GET("Partners")
Call<Partners> getPartners();
}
This is my APIHelper class
public class APIHelper {
public static final String PARTNERS_URL = "https://part-of-link.com/partners.json/";
public static APIService apiService;
public static APIService getApiService() {
if (apiService == null) {
Retrofit retrofit = new Retrofit.Builder().baseUrl(PARTNERS_URL)
.addConverterFactory(GsonConverterFactory.create()).build();
apiService = retrofit.create(APIService.class);
}
return apiService;
}
}
And this is Fragment where I have an Button on which I would like to implement onClick method to get data from API and save it into Partners table.
public class DownloadMain extends Fragment implements Callback<Partners> {
private Button dloadPartners;
private Call<Partners> callPartners;
public static APIService apiService;
public DownloadMain() {}
public DownloadMain newInstance() { return new DownloadMain(); }
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.download_main, container, false);
dloadPartners = (Button) view.findViewById(R.id.downloadPartners);
dloadPartners.setOnClickListener(btnListener);
callPartners = APIHelper.getApiService().getPartners();
callPartners.enqueue(this);
return view;
}
Button.OnClickListener btnListener = (new View.OnClickListener() {
#Override
public void onClick(View v) {
APIHelper helper = new APIHelper();
apiService = helper.getApiService();
Call<Partners> call = apiService.getPartners();
call.enqueue(new Callback<Partners>() {
#Override
public void onResponse(Call<Partners> call, Response<Partners> response) {
APIHelper helper = new APIHelper();
helper.getApiService();
Call<Partners> call = apiService.getPartners();
call.enqueue(new Callback<Partners>() {
#Override
public void onResponse(Call<Partners> call, Response<Partners> response) {
List<String> partners = response.body().getPartners();
Log.d(TAG, "Number of partners received: " + partners.size());
/*if (response.body() != null) {
ArrayList<String> partnersList;
partnersList = response.body();
Log.d("DOWNLOAD", String.valueOf(partnersList));
}*/
}
#Override
public void onFailure(Call<Partners> call, Throwable t) {
Toast.makeText(getActivity(), "FAIL!!!", Toast.LENGTH_SHORT).show();
}
});
}
});
#Override
public void onResponse(Call<Partners> call, Response<Partners> response) {
}
#Override
public void onFailure(Call<Partners> call, Throwable t) {
}
}
And here is my problem. Everything works and there is no errors but when I click on button nothing happens.
So I presume I've made some mistake but I can't figure it out (First time doing with retrofit).
What I want on button click is to get all partners from web and save it into my Partners table.
Question: Could somebody guide me and tell me what is wrong and help me to fix this?
EDIT:
Button.OnClickListener btnListener = (new View.OnClickListener() {
#Override
public void onClick(View v) {
APIHelper helper = new APIHelper();
apiService = helper.getApiService();
Call<ArrayList<String>> call = null;
call.enqueue(new Callback<ArrayList<String>>() {
#Override
public void onResponse(Call<ArrayList<String>> call, Response<ArrayList<String>> response) {
ArrayList<String> partners = response.body();
Log.d(TAG, "Number of partners received: " + partners.size());
}
#Override
public void onFailure(Call<ArrayList<String>> call, Throwable t) {
Toast.makeText(getActivity(), "FAIL!!!", Toast.LENGTH_SHORT).show();
}
});
}
});
Error logs:
Error:(68, 60) error: is not abstract and does not
override abstract method
onResponse(Call>,Response>) in
Callback
Error:(72, 53) error: cannot find symbol method body()
Error:(69, 17) error: method does not override or implement a method
from a supertype
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
Compilation failed; see the compiler error output for details.
your problem is here in the onClick()
helper.getApiService();
you did not assign the service into the variable
change it to this:
apiService = helper.getApiService();
EDIT:
based on new updates i think you dont need to use a POJO
just use the following in your Call
Call<ArrayList<String>>
and to get response just use response.body() without .partners() .
try to replace it everywhere in your code and check
Based on your JSON response, your POJO class should be:
public class Partners {
private ArrayList<String> partners = new ArrayList<>(0);
// Get; Set methods //
}
Try putting this in your APIHelper class to get more information about what you are sending
public static APIService apiService;
//this http loggin interceptor allows you debug requests and responses
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
// set your desired log level
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
// add your other interceptors …
// add logging as last interceptor
httpClient.addInterceptor(logging); // <-- this is the important line!
public static APIService getApiService() {
if (apiService == null) {
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build())
.build();
}
return apiService;
}
Maybe you are sending information in a wrong way...
And remember that in server side you must decode the information that receive (with json_decode).
I have an web api which gives me array of partners and it looks like this:
[
"partner1",
"partner2",
"partner3",
"....",
"parner222"
]
I have Table partners (ActiveAndroid) in which I would like to save all partners from api.
#Table(name = "Partners")
public class Partners extends Model {
#Column(name = "Name")
String name;
public Partners() {}
public Partners(String name) {
this.name = name;
}
}
Here is my Pojo model class:
public class Partners {
#SerializedName("name")
#Expose
private List<String> name = new ArrayList<String>();
public List<String> getName() {
return name;
}
public void setName(List<String> name) {
this.name = name;
}
}
This is my interface
public interface APIService {
#GET("Partners")
Call<Partners> getPartners();
}
And this is my APIHelper with api url
public class APIHelper {
public static APIService apiService;
public static APIService getApiService() {
if (apiService == null) {
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://part-oflink.domain.com/partners.json/")
.addConverterFactory(GsonConverterFactory.create()).build();
apiService = retrofit.create(APIService.class);
}
return apiService;
}
}
And this is Fragment where I have an Button on which I would like to implement onClick method to get data from API and save it into Partners table.
public class DownloadMain extends Fragment implements Callback<Partners> {
private Button dloadPartners;
private Call<Partners> callPartners;
public static APIService apiService;
public DownloadMain() {}
public DownloadMain newInstance() { return new DownloadMain(); }
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.download_main, container, false);
dloadPartners = (Button) view.findViewById(R.id.downloadPartners);
dloadPartners.setOnClickListener(btnListener);
callPartners = APIHelper.getApiService().getPartners();
callPartners.enqueue(this);
return view;
}
Button.OnClickListener btnListener = (new View.OnClickListener() {
#Override
public void onClick(View v) {
//here I need to implement that on click downloads me data
// and save it into my Partners table
}
});
#Override
public void onResponse(Call<Partners> call, Response<Partners> response) {
//here I'm trying to put api response into array list
if (response.body() != null) {
ArrayList<String> partnersList = new ArrayList<>();
partnersList = response.body();
}
}
#Override
public void onFailure(Call<Partners> call, Throwable t) {
}
}
And now I have stuck. I would like to implement onClick Button method to get data from API. In onResponse() method I'm trying to put data into ArrayList to check if data is recieved. And also I would like to save this data into my table partners.
I would be grateful if someone could help me or guide me to fix this. This is first time I'm doing with retrofit and api.
Can somebody help me or guide me to successfully get data from API and save it into table Partners?
The way you are trying to parse the JSON string(array of partners) is not the appropriate. Your JSON should like this:
{
"partners":
["partner1", "partner2", "partner3", ...]
}
And the POJO model class should be:
class Partners{
private List<String> partners;
public Partners(){}
public void setList(List<String> partners) {
this.partners = partners;
}
public List<String> getList() {
return this.partners;
}
//setter and getter methods
}
If the response is not empty then for printing the values:
for(Partner partner: response){
Log.d("Partner Name",partner.name);
}
And if you are using any ORM for the database, then call its DAO and pass the values to save in the DB.