I want to get an ArrayList<ItemList> from my Retrofit Callback and save it in as a ArrayList variable in my class.
In other word I need to use data from retrofitList even when I leave the onResponse method.
What is the best way to do it?
Here is my code.
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
retrofitList = new ArrayList<>();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://b98afcf5.ngrok.io/")
.addConverterFactory(GsonConverterFactory.create())
.build();
jsonPlaceHolder = retrofit.create(JsonPlaceHolder.class);
Call<List<ItemList>> call = jsonPlaceHolder.getItemList();
call.enqueue(new Callback<List<ItemList>>() {
#Override
public void onResponse(Call<List<ItemList>> call, Response<List<ItemList>> response) {
if(!response.isSuccessful()) {
return;
}
List<ItemList> listOfitems = response.body();
for(ItemList itemList : listOfitems){
retrofitList.add(new ItemList(itemList.getId(),
itemList.getName(),
itemList.getPhone(),
itemList.getIsLocated()));
}
//I WANT TO SAVE "retrofitList" INTO MY CLASS FROM HERE
}
#Override
public void onFailure(Call<List<ItemList>> call, Throwable t) {}
});
}
I recommend serialization it will make your life easier. Try this and this.
Create a method in your class that you will call from onResponse with your list. Save the list in some field variable. If you call this variable before it is filled with items from onResponse it won't have them.
Related
What I am trying to do is, fetch the datas from server using GET method and display them in multiple textfields.
I have already made model class, interface and created constructor, but still the app throws onFailure message.
TextView name;
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
String url="https://jsonplaceholder.typicode.com/";
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
name = view.findViewById(R.id.proName);
name.setText("");
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build();
PlaceHolderApi placeHolderApi = retrofit.create(PlaceHolderApi.class);
Call<List<profileDetails>> call = placeHolderApi.getDetails();
call.enqueue(new Callback<List<profileDetails>>() {
#Override
public void onResponse(Call<List<profileDetails>> call, Response<List<profileDetails>> response) {
List<profileDetails> data=response.body();
**for (int i=0; i<data.size();i++)
name.append("Aa"+ data.get(i).getTitle());**
}
#Override
public void onFailure(Call<List<profileDetails>> call, Throwable t) {
Toast.makeText(getContext(),"nah it",Toast.LENGTH_LONG).show();
}
});
}
}
The result you are getting is a json object so try to create a model class having a data member of type List and making a call of type List make a call of that model type. This may resolve your issue.
So, I'm trying to connect to Scryfall's API and do an autocomplete call. I've been able to use their other call properly but this one I think where I'm having issue.
Here is the call: https://api.scryfall.com/cards/autocomplete?q=fire
q is the query and it will return a list of up to 20 items that could be auto-completed with the word 'fire'.
{
"object":"catalog",
"total_values":20,
"data": [
"Fire // Ice","Fire Imp","Firefly","Fire Whip","Fire Ants","Firebolt","Fireball","Fire Drake","Fire Snake","Firespout","Firestorm","Fireblast","Fire-Field Ogre","Fire Urchin","Fire Bowman","Fire Dragon","Fire at Will","Fire Ambush","Firemaw Kavu","Fire Juggler"
]
}
I am using retrofit2 for android.
Here is some of my code.
This is my interface for the endpoints
public interface ScryfallEndPoints {
//https://api.scryfall.com/cards/named?fuzzy=
#GET("cards/named")
Call<Card> getCard(
#Query(value=("fuzzy")) String name);
//https://api.scryfall.com/cards/autocomplete?q=
#GET("cards/autocomplete")
Call<Card> getCardAutoComplete(
#Query(value=("q")) String name);
}
This is a method I use in my activity to perform the call.
private void loadCardList()
{
final ScryfallEndPoints apiService =
APIClient.getClient().create(ScryfallEndPoints.class);
Call<Map<String, String>> call = apiService.getCardAutoComplete(str);
Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
call.enqueue(new Callback<Map<String, String>>()
{
#Override
public void onResponse(Call<Map<String, String>> call, Response<Map<String, String>> response)
{
Toast.makeText(SuggestionResults.this, "onResponse()", Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<Map<String, String>> call, Throwable t)
{
Toast.makeText(SuggestionResults.this, "onFailure()", Toast.LENGTH_SHORT).show();
}
});
//tv.setText(str);
}
Here is a method that is part of my model class.
#SerializedName("data")
private Map<String, String> cardList;
public Map<String, String> getCardList() {return cardList;}
So, I feel like there is definitely something maybe wrong in the way I am trying to access he data in my model class and maybe with the way I have it set up in my interface. When I make the call, it doesn't fail so I don't have error logs to show, i just know that it is going to the onFailure() method and I'm not sure why. I mostly need to figure this out then I can work on getting the list to populate. Also, if there is a way that I can see more of what is going on with the calls that I am making, that would be great too. Thanks!
#GET("cards/autocomplete")
Call<Card> getCardAutoComplete(
#Query(value=("q")) String name);
}
Then the calling part
//Call<Map<String, String>> call = apiService.getCardAutoComplete(str);
//It returns Call of Card type, hence it will be as follows
Call<Card> call = apiService.getCardAutoComplete(str);
Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
call.enqueue(new Callback<Card>()
{
#Override
public void onResponse(Call<Card> call, Response<Card> response)
{
Toast.makeText(SuggestionResults.this, "onResponse()", Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<Card> call, Throwable t)
{
Toast.makeText(SuggestionResults.this, "onFailure()", Toast.LENGTH_SHORT).show();
}
});
I want to get notifications from a server using API. I'm using Retrofit2 to work with API.
The problem is when I'm passing parameter in POST method I'm getting "IllegalArgumentException URL does not contain the parameter."
The parameter is correct and working in iOS. I want to implement in android.
Below is the result when debugging the app.
Caused by: java.lang.IllegalArgumentException: URL
"notification/newnotification" does not contain "{userid}". (parameter #1)
I've tried changing parameters and asked the API developer too. He says parameter is correct.
This is code for API Interface:
public interface API{
#FormUrlEncoded
#POST("notification/newnotification")
Call<ResponseBody> getUserNotification(
#Path("userid") int userid
);
}
RetrofitClient.java
public class RetrofitClient {
public static final String BASE_URL = "http://danceglobe.co/dance/api/";
private static RetrofitClient mInstance;
private Retrofit retrofit;
private RetrofitClient(){
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
public static synchronized RetrofitClient getInstance(){
if(mInstance == null) {
mInstance = new RetrofitClient();
}
return mInstance;
}
public API getApi(){
return retrofit.create(API.class);
}
}
Calling Function from MainActivity
private void getNotification(String currentUserId) {
Call<ResponseBody> call = RetrofitClient.getInstance().getApi().getUserNotification(Integer.parseInt(currentUserId));
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(!response.isSuccessful()){
Toast.makeText(MainActivity.this,response.message(),Toast.LENGTH_SHORT).show();
}
try {
String s = response.body().string();
Toast.makeText(MainActivity.this,s,Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(MainActivity.this,t.getMessage(),Toast.LENGTH_SHORT).show();
}
});
}
I want it to respond to some data.
Please help me. I got stuck into this from past 2 days.
Caused by: java.lang.IllegalArgumentException: URL
"notification/newnotification" does not contain "{userid}". (parameter #1)
means you should add the userId to the path like
public interface API {
#POST("notification/newnotification/{userid}")
Call<ResponseBody> getUserNotification(
#Path("userid") int userid
);
}
#Path("userid") maps the variable to the placeholder {userid}, that was missing.
I got it working by making some changes in API interface.
Below is new Code for API interface
#FormUrlEncoded
#POST("notification/newnotification")
Call<ResponseBody> getUserNotification(
#Field("userid") String userid // changed line
);
I'm trying to get the data I parse from onResponse method via Callback. Here is my ApiClient:
public class ApiClient implements Callback<Map<String, Channel>> {
private ChannelCallback listener;
static final String BASE_URL = "https://www.radyoodtu.com.tr/";
public void start(ChannelCallback listener) {
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
RestInterface restInterface = retrofit.create(RestInterface.class);
Call<Map<String, Channel>> call = restInterface.getChannels();
call.enqueue(this);
}
#Override
public void onResponse(retrofit2.Call<Map<String, Channel>> call, Response<Map<String, Channel>> response) {
System.out.println(response.code());
if(response.isSuccessful()) {
Map<String, Channel> body = response.body();
listener.setChannels(body);
List<Channel> channels = new ArrayList<>(body.values());
for (Channel channel : body.values()) {
System.out.println(channel.getSong());
}
}
}
#Override
public void onFailure(retrofit2.Call<Map<String, Channel>> call, Throwable t) {
//TODO
}
}
and this is the class I'm trying to get the data:
public class Radio implements ChannelCallback {
private ApiClient apiClient = new ApiClient();
public Radio(){
apiClient.start(this);
}
#Override
public void setChannels(Map<String, Channel> body) {
this.apiClient.onResponse(body); // NOT WORKING
}
}
here is my Interface:
public interface ChannelCallback {
void setChannels(Map<String, Channel> body);
}
what I need to do is get the onResponse body data for Radio class I'm using right now. In Radio class I have to create a List of channel objects with that data I need but I can't even get the data so I can't even create that list. I don't know how to manipulate the data from listener at all and I don't know how can I access that listener I use in ApiClient in Radio class.
It looks like you've got a cyclic reference here. Radio calls ApiClient start, which triggers the network request, which calls Radio.setChannels, which tries to call the client again.
I think you need to resolve two things:
Avoid this cyclic reference
You pass the listener to ApiClient.start() but you never assign it to the actual value inside ApiClient. So, my guess is that you get an NPE here if you have a successful response.
//i think no need to impliments ChannelCallback if this code works
//just asign your interface and apiclient in class
public class Radio implements ChannelCallback {
private ApiClient apiClient = new ApiClient();
private ChannelCallback channelCallback;
and in inside radio()
public Radio(){
apiClient.start(this);
channelCallback = apiClient.onResponse(body).create(ChannelCallback.class);
channelCallback.setChannels(Map<String, Channel> body)
}
//and recieve callback
}
I wanted to refactor code for simplicity and readability and that's why I want to move the code outside the class and return a result to class whenever the method is called.
Trying:
ArrayList<MovieReview> movieReview;
public ArrayList<MovieReview> getReviews(String id) {
if (NetworkUtil.isNetworkConnected(getActivity())) {
ApiInterface apiService =
ApiClient.getClient().create(ApiInterface.class);
Call<MovieReviewResponse> call = null;
call = apiService.getMovieReviews(id, BuildConfig.THE_MOVIE_DB_API_KEY);
call.enqueue(new Callback<MovieReviewResponse>() {
#Override
public void onResponse(Call<MovieReviewResponse> call, Response<MovieReviewResponse> response) {
movieReview= (ArrayList<MovieReview>) response.body().getMovieReviews();
}
#Override
public void onFailure(Call<MovieReviewResponse> call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
}
return movieReview;
}
Output: if I used array list outside the on response gives null value.
but if I called a method from on response and pass the result movieReview, as a parameter, it works fine.
Previously used:
public void getReviews(String id) {
if (NetworkUtil.isNetworkConnected(getActivity())) {
ApiInterface apiService =
ApiClient.getClient().create(ApiInterface.class);
Call<MovieReviewResponse> call = null;
call = apiService.getMovieReviews(id, BuildConfig.THE_MOVIE_DB_API_KEY);
call.enqueue(new Callback<MovieReviewResponse>() {
#Override
public void onResponse(Call<MovieReviewResponse> call, Response<MovieReviewResponse> response) {
movieReview = (ArrayList<MovieReview>) response.body().getMovieReviews();
setData(movieReview);
}
#Override
public void onFailure(Call<MovieReviewResponse> call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
}
}`
Output: if I used array list outside the on response gives null value
Because that is how asyncronus methods work. Your return happens before onResponse ever happens, so the list object is null.
Tip: In ideal situations, you want to always return an empty list, not null anyway.
Rename your method.
public ArrayList<MovieReview> getReviews(String id)
To Instead
public ArrayList<MovieReview> getReviews(String id, Callback<MovieReviewResponse> callback)
Replace this code
call.enqueue(new Callback<MovieReviewResponse>() {
...
});
With this
call.enqueue(callback);
Wherever you call that method
// In Activity
String id = "X";
api.getReviews(id);
Now do....
// In Activity
String id = "X";
api.getReviews(id, new Callback<MovieReviewResponse>() {
...
});
And now from within onResponse, you can update a ListView adapter, or whatever you need to do
Instead of using only Retrofit make use of RxAndroid. By using this you will get response of Observable<T> which consists of three Override methods onCompleted(), onError() and onNext().
In onNext() method call your specific activity, pass your data through putExtra and get through getExtra.