im using Retrofit for the first time here.
I want to put my List from the Callback to UsersData class. Its not possible. But if i erase everything from UsersData and put the content from Profile in UsersData then it works. But it doesn´t fulfill my needs. I need to be able to put List from Callback to UsersData class.
Thank you in advantage
In my fragment
App.getRestClient().getAttendanceService().getUsers(48, new Callback<List<UsersData>>() {
#Override
public void success(List<UsersData> usersDao, Response response) {
String ble = usersDao.get(0).getResults().get(0).getFirstName();
Toast.makeText(getActivity(),ble, Toast.LENGTH_SHORT).show();
}
#Override
public void failure(RetrofitError error) {
}
});
App
public class App extends Application {
private static RestClient restClient;
public static App instance = null;
public static Context getInstance() {
if (null == instance) {
instance = new App();
}
return instance;
}
#Override
public void onCreate(){
super.onCreate();
restClient = new RestClient();
}
public static RestClient getRestClient(){
return restClient;
}
}
And my client
public class RestClient {
private static final String BASE_URL = "www.Link_to_json.com" ;
private AttendanceService attendanceService;
public RestClient()
{
Gson gson = new GsonBuilder()
.setDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'")
.create();
RestAdapter restAdapter = new RestAdapter.Builder()
//.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint(BASE_URL)
//.setClient(new OkClient(new OkHttpClient()))
//.setConverter(new GsonConverter(gson))
.build();
attendanceService = restAdapter.create(AttendanceService.class);
}
public AttendanceService getAttendanceService()
{
return attendanceService;
}
}
My interface
public interface AttendanceService {
#GET("/GetUsers")
void getUsers(#Query("companyId") int i, Callback<List<UsersData>> u );
}
and UsersData
public class UsersData {
private List<Profile> results;
public List<Profile> getResults() {
return results;
}
}
Profile data class:
public String firstName;
public String lastname;
public int userId;
public String userNameId;
...
Example of json:
[
{
"AttendanceDate":null,
"AttendanceStatus":1,
"AttendanceStatusDescription":null,
"CompanyId":48,
"Email":"",
"FirstName":"Sindri",
"Gender":1,
"Gsm":"",
"Id":259,
"LastName":"yeh",
"MiddleName":"",
"Role":0,"UserId":"corp\\marg"
},{
"AttendanceDate":null,
"AttendanceStatus":1,
"AttendanceStatusDescription":null,
"CompanyId":48,
"Email":"",
"FirstName":"David",
"Gender":1,
"Gsm":"",
"Id":165,
"LastName":"Guðmundsson",
"MiddleName":"",
"Role":0,"UserId":"corp\\marg"
}
]
Try wrapping the list/array inside the UsersData class itself:
public interface AttendanceService {
#GET("/GetUsers")
void getUsers(#Query("companyId") int i, Callback<UsersData> u );
}
UsersData.java:
public class UsersData {
public Profile[] results;
public class Profile {
public String firstName;
public String lastname;
public int userId;
public String userNameId;
}
}
In the callback you can then iterate over the results array.
As UMESH0492 comments you should also name your list in the JSON:
{
"profile": [
{
"AttendanceDate":null,
"AttendanceStatus":1,
"AttendanceStatusDescription":null,
"CompanyId":48,
"Email":"",
"FirstName":"Sindri",
"Gender":1,
"Gsm":"",
"Id":259,
"LastName":"yeh",
"MiddleName":"",
"Role":0,"UserId":"corp\\marg"
},{
"AttendanceDate":null,
"AttendanceStatus":1,
"AttendanceStatusDescription":null,
"CompanyId":48,
"Email":"",
"FirstName":"David",
"Gender":1,
"Gsm":"",
"Id":165,
"LastName":"Guðmundsson",
"MiddleName":"",
"Role":0,"UserId":"corp\\marg"
}
]
}
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 want to post this object
public class EditTask {
#SerializedName("id")
private int id;
#SerializedName("active")
private int active;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getActive() {
return active;
}
public void setActive(int active) {
this.active = active;
}
public EditTask(int id, int active) {
this.id = id;
this.active = active;
}
}
My api:
public interface TaskApi {
#GET("func.php?load")
Call<List<Task» getTaskList();
#FormUrlEncoded
#POST("func.php?add")
Call<String> addTask(#Field("name") String name);
#POST("func.php?edit")
Call<EditTask> editTask(#Body EditTask editTask);
}
My Repositary:
public class TaskRepository {
private static TaskRepository taskRepository;
public static TaskRepository getInstance() {
if (taskRepository == null) {
taskRepository = new TaskRepository();
}
return taskRepository;
}
private TaskApi taskApi;
public TaskRepository() {
taskApi = RetrofitService.createService(TaskApi.class);
}
public void editTask(int id, int active) {
EditTask editTask = new EditTask(id, active);
taskApi.editTask(editTask).enqueue(new Callback<EditTask>() {
#Override
public void onResponse(Call<EditTask> call, Response<EditTask> response) {
Log.i("Artemy", "cool");
}
#Override
public void onFailure(Call<EditTask> all, Throwable t) {
Log.i("Artemy", "notcool");
}
});
}
}
My RetrofitService:
public class RetrofitService {
private static Gson gson = new GsonBuilder()
.setLenient()
.create();
private static Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://loginov.tech/android/")
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
public static <S> S createService(Class<S> serviceClass) {
return retrofit.create(serviceClass);
}
}
My ViewModel:
public class TaskViewModel extends ViewModel {
private MutableLiveData<List<Task»mutableLiveData;
private TaskRepository taskRepository;
public void init() {
if (mutableLiveData != null) {
return;
}
taskRepository = TaskRepository.getInstance();
mutableLiveData = taskRepository.getTasks();
}
public LiveData<List<Task»
getTaskRepository() {
return mutableLiveData;
}
public void addTask(String name) {
taskRepository.addTask(name);
}
public void editTask(int id, int active) {
taskRepository.editTask(id, active);
}
}
Main Activity:
public class TaskViewModel extends ViewModel {
private MutableLiveData<List<Task»mutableLiveData;
private TaskRepository taskRepository;
public void init() {
if (mutableLiveData != null) {
return;
}
taskRepository = TaskRepository.getInstance();
mutableLiveData = taskRepository.getTasks();
}
public LiveData<List<Task»
getTaskRepository() {
return mutableLiveData;
}
public void addTask(String name) {
taskRepository.addTask(name);
}
public void editTask(int id, int active) {
taskRepository.editTask(id, active);
}
}
I must create post request to server and post int id and int active parameters.But i always get error :java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 2 column 1 path
I tried to post List of EditTasks also i tried to make post with #FormUrlEncoded it did not help.
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.
I am using room as data store for my app. I am trying to save a list of sessions from a successful network call in viewmodel class. I have used a repository for interacting with the dao and asynctask for making crud operations async.
Now, I'm trying to display the "saved data" in a recyclerview but it shows nothing. On inspection of my database table, I find that nothing was saved. Here's my model class:
#Entity(tableName = "sessions")
public class Sessions{
// #PrimaryKey(autoGenerate = true)
// public int id;
#SerializedName("prg_session_image")
public String sessionImage;
#SerializedName("prg_session_name")
public String session_name;
#SerializedName("prg_session_id") // used session id as PK
#PrimaryKey
#NonNull
public String prog_sessionId;
#SerializedName("prg_session_description")
public String session_desc;
#SerializedName("reference_id")
public String reference_id;
#SerializedName("prg_name")
public String program_name;
#SerializedName("batch_name")
public String batch_name;
#SerializedName("player_count")
public String participants_count;
#SerializedName("prg_session_focus_points")
public String session_focus_points;
#SerializedName("prg_session_equipment")
public String equipments_reqd;
#SerializedName("session_complete")
public String is_complete;
public Sessions() {
}
// public int getId() {
// return id;
// }
public String getSessionImage() {
return sessionImage;
}
public void setSessionImage(String sessionImage) {
this.sessionImage = sessionImage;
}
public String getSession_name() {
return session_name;
}
public void setSession_name(String session_name) {
this.session_name = session_name;
}
public String getProg_sessionId() {
return prog_sessionId;
}
public void setProg_sessionId(String prog_sessionId) {
this.prog_sessionId = prog_sessionId;
}
public String getSession_desc() {
return session_desc;
}
public void setSession_desc(String session_desc) {
this.session_desc = session_desc;
}
public String getReference_id() {
return reference_id;
}
public void setReference_id(String reference_id) {
this.reference_id = reference_id;
}
public String getProgram_name() {
return program_name;
}
public void setProgram_name(String program_name) {
this.program_name = program_name;
}
public String getBatch_name() {
return batch_name;
}
public void setBatch_name(String batch_name) {
this.batch_name = batch_name;
}
public String getParticipants_count() {
return participants_count;
}
public void setParticipants_count(String participants_count) {
this.participants_count = participants_count;
}
public String getSession_focus_points() {
return session_focus_points;
}
public void setSession_focus_points(String session_focus_points) {
this.session_focus_points = session_focus_points;
}
public String getEquipments_reqd() {
return equipments_reqd;
}
public void setEquipments_reqd(String equipments_reqd) {
this.equipments_reqd = equipments_reqd;
}
public String getIs_complete() {
return is_complete;
}
public void setIs_complete(String is_complete) {
this.is_complete = is_complete;
}
}
And Dao class:
#Dao
public interface SessionsDAO {
// #Insert
// LiveData<List<Sessions>> saveSessions(List<Sessions> sessions);
#Insert
void addSessions(List<Sessions> list);
#Query("select * from sessions")
LiveData<List<Sessions>> getAllSessions();
#Query("select * from sessions where prog_sessionId = :id")
Sessions getSessionById(String id);
}
In repository, I have asynctasks for various operations with the Dao:
public class SessionsRepository {
public SessionsDAO dao;
private MutableLiveData<List<Sessions>> querySingleSession;
private LiveData<List<Sessions>> allSessions;
public SessionsRepository(Application application){
SportsDatabase database = SportsDatabase.getInstance(application);
dao = database.sessionsDAO();
querySingleSession = new MutableLiveData<>();
allSessions = dao.getAllSessions();
}
public void saveSessions(List<Sessions> sessions){
new SaveSessionsTask(dao).execute(sessions);
}
public LiveData<List<Sessions>> getAllSessions() {
return allSessions;
}
public void getSessionById(List<Sessions> sessions){
querySingleSession.setValue(sessions);
}
public class SaveSessionsTask extends AsyncTask<List<Sessions>, Void, Void>{
private SessionsDAO dao;
public SaveSessionsTask(SessionsDAO dao) {
this.dao = dao;
}
#Override
protected Void doInBackground(List<Sessions>... lists) {
dao.addSessions(lists[0]);
return null;
}
}
// public void getSessions(){
// new GetSessionsTask(dao).execute();
// }
// public class GetSessionsTask extends AsyncTask<Void, >
}
I am trying to at the moment save all the results from network call and display them from the database. Here's my operation in viewmodel class:
public class HomeSessionsViewModel extends AndroidViewModel {
private static final String TAG = HomeSessionsViewModel.class.getSimpleName();
private MutableLiveData<SessionDetails> liveDetails;
private SessionsRepository repository;
public HomeSessionsViewModel(#NonNull Application application) {
super(application);
repository = new SessionsRepository(application);
}
// public HomeSessionsViewModel (Application application){
// repository = new SessionsRepository(application);
// }
public MutableLiveData<SessionDetails> getSessions(){
if (liveDetails == null){
liveDetails = new MutableLiveData<>();
fetchSessions();
}
return liveDetails;
}
private void fetchSessions(){
String coachId = "4086";
Call<SessionDetails> call = RestClient.getRestInstance().getSessionsService().fetchSessions(coachId);
call.enqueue(new Callback<SessionDetails>() {
#Override
public void onResponse(Call<SessionDetails> call, Response<SessionDetails> response) {
if (response.isSuccessful()){
SessionDetails details = response.body();
List<Sessions> sessions = details.getSessions();
Log.d(TAG, "N/w sesh size:\t" + sessions.size());
liveDetails.setValue(details); // now just displaying from network
saveSessions(sessions);
}
}
#Override
public void onFailure(Call<SessionDetails> call, Throwable t) {
}
});
}
private void saveSessions(List<Sessions> sessions) {
repository.saveSessions(sessions);
}
public LiveData<List<Sessions>> fetchSessionsDB(){
return repository.getAllSessions();
}
}
and in ui controller (fragment), I have called the viewmodel's fetchSessionsDB() method but no data is shown. The network request works well as I was displaying from there before adding room. What could be wrong here? Thank you.
API Response:
{
"session_details": [
{
"prg_session_name": "Session-16",
"prg_session_id": "987",
"prg_session_equipment": null,
"prg_session_description": "",
"prg_session_focus_points": "",
"prg_session_image": "http://devsports.copycon.in/includes/uploads/Jellyfish5.jpg",
"session_complete": "0",
"prg_name": "cricket coaching",
"reference_id": "293",
"batch_id": "57",
"batch_name": "Batch 3",
"player_count": "10"
}, .... ]}
and SessionDetails POJO:
public class SessionDetails {
#SerializedName("session_details")
#Expose
private List<Sessions> sessions;
#SerializedName("status")
private String status;
#SerializedName("message")
private String msg;
public List<Sessions> getSessions() {
return sessions;
}
}
fragment class where db data should be displayed:
private void populateSessions() {
sessionsRV = fragmentBinding.sessionsRV;
sessionsRV.setHasFixedSize(false);
LinearLayoutManager hlm = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
sessionsRV.setLayoutManager(hlm);
sessionsViewModel = ViewModelProviders.of(this).get(HomeSessionsViewModel.class);
// sessionsViewModel.fetchSessions(""); // TODO: 3/16/2019 Use coach id from db
// calling db from viewmodel
sessionsViewModel.fetchSessionsDB().observe(this, new Observer<List<Sessions>>() {
#Override
public void onChanged(#Nullable List<Sessions> sessions) {
sessionsAdapter = new SessionsAdapter(getActivity(), sessions);
sessionsRV.setAdapter(sessionsAdapter);
Log.d(TAG, "Sessions Count:\t" + sessionsAdapter.getItemCount()); // logs 0
}
});
// previously from network directly displayed
// sessionsViewModel.getSessions().observe(this, new Observer<SessionDetails>() {
// #Override
// public void onChanged(#Nullable SessionDetails details) {
// List<Sessions> list = details.getSessions();
// sessionsAdapter = new SessionsAdapter(getActivity(), list);
// sessionsRV.setAdapter(sessionsAdapter);
// Log.d(TAG, "Sessions Count:\t" + sessionsAdapter.getItemCount());
// }
// });
}
Sports Database class:
#Database(entities = {CoachDB.class, Sessions.class}, version = 1, exportSchema = false)
public abstract class SportsDatabase extends RoomDatabase {
private static SportsDatabase instance;
public abstract CoachDAO coachDAO();
public abstract SessionsDAO sessionsDAO();
public static synchronized SportsDatabase getInstance(Context context) {
if (instance == null){
instance = Room.databaseBuilder(context.getApplicationContext(), SportsDatabase.class, "sports_db")
.fallbackToDestructiveMigration()
.build();
}
return instance;
}
}
I have solved this issue by modifying my #insert method in dao like
#Dao
public interface SessionsDAO {
#Insert
void addSessions(List<Sessions> sessions);
#Query("select * from sessions")
LiveData<List<Sessions>> getAllSessions();
#Query("select * from sessions where prog_sessionId = :id")
Sessions getSessionById(String id);
}
and run my async task with a list of sessions as input and it worked successfully.
private void saveSessions(List<Sessions> sessions) {
new SaveSessionsTask(dao).execute(sessions);
}
public class SaveSessionsTask extends AsyncTask<List<Sessions>, Void, Void> {
private SessionsDAO dao;
public SaveSessionsTask(SessionsDAO dao) {
this.dao = dao;
}
#Override
protected Void doInBackground(List<Sessions>... lists) {
dao.addSessions(lists[0]);
return null;
}
}
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.