Problems in understating execution flow in android studio - android

The following code is using retrofit and youtubedata api to get subscriber count of two youtube channels.
public class NavigationActivity extends AppCompatActivity {
private static String GOOGLE_YOUTUBE_API_KEY = "AIzaSyBV4XQEZ9l1HZeBQFL6ZZvHYfMhtnqUkmw";
private static String CHANNEL_ID_TS = "UCq-Fj5jknLsUf-MWSy4_brA";
private static String CHANNEL_ID_PDP = "UC-lHJZR3Gqxm24_Vd_AJ5Yw";
public static int SUBS_TS = 0;
public static int SUBS_PDP = 0;
//?part=snippet%2CcontentDetails%2Cstatistics&id=UC_x5XG1OV2P6uZZ5FSM9Ttw&key=AIzaSyBV4XQEZ9l1HZeBQFL6ZZvHYfMhtnqUkmw
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_navigation);
Map<String, String> qMap = new HashMap<>();
qMap.put("part", "snippet,contentDetails,statistics");
qMap.put("id", CHANNEL_ID_TS);
qMap.put("key", GOOGLE_YOUTUBE_API_KEY);
Map<String, String> qMap2 = new HashMap<>();
qMap2.put("part", "snippet,contentDetails,statistics");
qMap2.put("id", CHANNEL_ID_PDP);
qMap2.put("key", GOOGLE_YOUTUBE_API_KEY);
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
Call<ChannelResponse> call = apiService.getSubs(qMap);
call.enqueue(new Callback<ChannelResponse>() {
#Override
public void onResponse(Call<ChannelResponse> call, Response<ChannelResponse> response) {
List<Channel> channels = response.body().getChannels();
SUBS_TS = channels.get(0).getStatistics().getSubscriberCount();
Log.d("GEEK", SUBS_TS + "");
}
#Override
public void onFailure(Call<ChannelResponse> call, Throwable t) {
Log.d("GEEK", t.toString());
}
});
Call<ChannelResponse> call2 = apiService.getSubs(qMap2);
call2.enqueue(new Callback<ChannelResponse>() {
#Override
public void onResponse(Call<ChannelResponse> call, Response<ChannelResponse> response) {
List<Channel> channels = response.body().getChannels();
SUBS_PDP = channels.get(0).getStatistics().getSubscriberCount();
Log.d("GEEK", SUBS_PDP + "");
}
#Override
public void onFailure(Call<ChannelResponse> call, Throwable t) {
Log.d("GEEK", t.toString());
}
});
//This statement seems to be executed before the SUSB_TS and SUSB_PDP variables are updated using the response.
Log.d("GEEK", SUBS_PDP + "AFTER");
}
}
Why is the
Log.d("GEEK", SUBS_PDP + "AFTER");
statement executed before the onResponse method?
Log
2018-12-12 14:30:26.993 17518-17518/com.geek.wartube D/GEEK: 0AFTER
2018-12-12 14:30:27.863 17518-17518/com.geek.wartube D/GEEK: 76222082
2018-12-12 14:30:27.885 17518-17518/com.geek.wartube D/GEEK: 75161493
I have also checked using the debugger that statements inside onResponse were not executed before the log statement in last line.
What should I do to achieve the desired result?

The calls to apiService.getSubs(qMap) and apiService.getSubs(qMap2) methods are done in background thread. That's why the next statement is executed before response finishes. Hence statement Log.d("GEEK", SUBS_PDP + "AFTER"); executes before onResponse() method
You can execute second call in onResponse() of first call and in onResponse() of second call do whatever you want to do next or if possible use Rxjava. But first way is simple to understand

Related

Rapid API Error code 500 with Retrofit2 Android

I am using spoonacular API for a recipe app project. The problem occurs when trying to making multiple GET requests to the API. The first request is a simple search with a query parameter. The resulting JSON of the first request contains a Recipe ID and I use that ID to make the second GET request , where the problem occurs.
The API responds only when I make the request the first time but after that it responds with error code 500 [Internal Server Error].
I have tested the GET request on Postman but there it works fine every time.
I'm new to working with API's and any help would be immensely appreciated.
This is my Retrofit Service Class
public class ServiceGenerator {
public static final String API_BASE_URL = "https://spoonacular-recipe-food-nutrition-v1.p.rapidapi.com/";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
private static Retrofit retrofit = builder.build();
public static <S> S createService(Class<S> serviceClass, final String HostName, final String KeyVal)
{
if (!TextUtils.isEmpty(HostName) && !TextUtils.isEmpty(KeyVal))
{
HeadersInterceptor interceptor = new HeadersInterceptor(HostName,KeyVal);
if (!httpClient.interceptors().contains(interceptor))
{
httpClient.addInterceptor(interceptor);
builder.client(httpClient.build());
retrofit = builder.build();
}
}
return retrofit.create(serviceClass);
}
This is the Interceptor I am using to add Headers with the request.
public class HeadersInterceptor implements Interceptor {
private String HostName,KeyVal;
HeadersInterceptor(final String HostName,final String KeyVal) {
this.HostName = HostName;
this.KeyVal = KeyVal;
}
#NotNull
#Override
public Response intercept(#NotNull Chain chain) throws IOException {
Request original = chain.request();
Request.Builder builder = original.newBuilder()
.addHeader("X-RapidAPI-Host",HostName)
.addHeader("X-RapidAPI-Key",KeyVal);
Request request = builder.build();
return chain.proceed(request);
}
}
This is my Fragment which makes a search query and SUCCESSFULLY return results[Receipe ID's]
public class ListSelectedFragments extends Fragment {
private ProgressBar PreviewFragPrg;
private final String TAG = "ListSelectedFragment->";
private PreviewRecipeAdapter adapter;
private RecyclerView SelectedItemRV;
private ArrayList<RecipePreviewHolder> RecipePreviewsList = new ArrayList<>();
public ListSelectedFragments() {
// Required empty public constructor
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View view = inflater.inflate(R.layout.fragment_list_selected_fragments, container, false);
SelectedItemRV = view.findViewById(R.id.SelectedItemRV);
TextView DisplayNameTV = view.findViewById(R.id.DisplayNameTV);
PreviewFragPrg = view.findViewById(R.id.PreviewFragPrg);
ImageView BackBtn = view.findViewById(R.id.BackBtn);
BackBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (getFragmentManager() != null) {
getFragmentManager().popBackStackImmediate();
}
}
});
if (getArguments() != null) {
final String QueryTag = getArguments().getString("QueryTag");
final String CuisineName = getArguments().getString("CuisineName");
if(CuisineName!=null){
DisplayNameTV.setText(CuisineName);
}
if(QueryTag!=null){
ProcessQuery(QueryTag);
}
}
return view;
}
private void ProcessQuery(final String QueryStr){
String hostname = getResources().getString(R.string.spoonacular_host_name);
String key = getResources().getString(R.string.spoonacular_apikey_val);
final ServiceGenerator.GetDataService mService =
ServiceGenerator.createService(ServiceGenerator.GetDataService.class, hostname,key);
Call<RecipeInfoModel> call = mService.getRecipes(QueryStr);
call.enqueue(new Callback<RecipeInfoModel>() {
#Override
public void onResponse(#NonNull Call<RecipeInfoModel> call,
#NonNull Response<RecipeInfoModel> response)
{
Log.d(TAG, "Request Response Received");
Log.d(TAG, response.toString());
if (response.body() != null) {
Results[] mRES = response.body().getResults();
SetUpRecipePreviews(mRES);
PreviewFragPrg.setVisibility(View.GONE);
}
}
#Override
public void onFailure(#NonNull Call<RecipeInfoModel> call, #NonNull Throwable t) {
Log.d(TAG, "Request Failed");
Log.d(TAG, call.toString());
Log.d(TAG, "Throwable ->" + t);
PreviewFragPrg.setVisibility(View.GONE);
Toast.makeText(getActivity(),"Could not get required recipes",Toast.LENGTH_SHORT).show();
}
});
Log.d(TAG, "User Inputed Request\n"+call.request().url().toString());
}
private void SetUpRecipePreviews(final Results[] mRES) {
RecipePreviewsList.clear();
adapter = new PreviewRecipeAdapter(getActivity(),RecipePreviewsList);
SelectedItemRV.setLayoutManager(new GridLayoutManager(getActivity(), 2));
SelectedItemRV.setAdapter(adapter);
for (Results mRE : mRES) {
String ImgUrls = mRE.getImage();
RecipePreviewHolder obj = new RecipePreviewHolder(Integer.valueOf(mRE.getId()),
mRE.getTitle(), ImgUrls);
Log.d("GlideLogs->","Rid->"+mRE.getId());
Log.d("GlideLogs->","Img URL->"+ ImgUrls);
Log.d("GlideLogs->","Name->"+mRE.getTitle());
RecipePreviewsList.add(obj);
}
if(RecipePreviewsList.size()>1){
adapter.notifyDataSetChanged();
}
}
This is the Activity I transition to from my Fragment after clicking on a Recipe Card... Sending the Recipe ID in the extras. This function is called immediately after receiving intent extras.
private void RetrieveRecipeInfo(final int recipeID) {
String hostname = getResources().getString(R.string.spoonacular_host_name);
String key = getResources().getString(R.string.spoonacular_apikey_val);
final ServiceGenerator.GetDataService mService =
ServiceGenerator.createService(ServiceGenerator.GetDataService.class, hostname,key);
Call<RecipeDetailedInfo> call = mService.getInformation(185071);
Log.d(TAG , "Your GET Request:\n"+call.request().url().toString());
call.enqueue(new Callback<RecipeDetailedInfo>() {
#Override
public void onResponse(#NonNull Call<RecipeDetailedInfo> call, #NonNull Response<RecipeDetailedInfo> response)
{
Log.d(TAG,"OnResponse() Called\n");
Log.d(TAG,"Response = "+ response);
if(response.body()!=null) {
String obj = response.body().getSourceUrl();
Log.d(TAG,"Getting Recipe Info\n");
Log.d(TAG, String.valueOf(obj));
}
}
#Override
public void onFailure(#NonNull Call<RecipeDetailedInfo> call, #NonNull Throwable t){
}
});
}
Using postman I get the results every time but in my application the API stops responding after the first request. Is there a problem with the way I'm including headers?
So I finally got things working. The problem was with the HeadersInterceptor.java. I was using the Interceptor to add the Headers with the call but I found out a much easier way and it works like a charm.
Simply add #Header with the call to add headers without interceptor in Retrofit.
public interface GetDataService {
#GET("recipes/complexSearch?")
Call<RecipeInfoModel> getRecipes(
#Header("X-RapidAPI-Host") String api,
#Header("X-RapidAPI-Key") String apiKey,
#Query("query") String query_str);
}

Android Json parsing with retrofit

I'm using retrofit for the first time and I'm looking to parse some json data but I may have made a mistake initiating the network request on MainActivity. The App doesn't crush but it's not returning any values. it's a Gridlayout with an OnclickListener on each item and I'm only looking to return 2 values (name and Id ). The object currently has 3 items (name, id, and a List<>) this is the Full API end point "https://d17h27t6h515a5.cloudfront.net/topher/2017/May/59121517_baking/baking.json"
public class MainActivity extends AppCompatActivity implements
CakeAdapter.CakeClickedListener {
RecyclerView mRecyclerView;
TextView mCakeName;
ImageView mCakeImage;
TextView mCakeId;
private List<CakesItem> mCakeList = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.cake_list_recycler_view);
mRecyclerView.setHasFixedSize(true);
GridLayoutManager mGridLayoutManager = new GridLayoutManager(MainActivity.this, 2);
final CakeAdapter mCakeAdapter = new CakeAdapter(this);
mRecyclerView.setLayoutManager(mGridLayoutManager);
mRecyclerView.setAdapter(mCakeAdapter);
mCakeAdapter.getCakeData(mCakeList);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
BakingJsonApi bakingJsonApi = retrofit.create(BakingJsonApi.class);
Call<List<CakesItem>> call = bakingJsonApi.getCakes(Constants.JSON_PATH);
call.enqueue(new Callback<List<CakesItem>>() {
#Override
public void onResponse(Call<List<CakesItem>> call, Response<List<CakesItem>> response) {
if (!response.isSuccessful()) {
Toast.makeText(MainActivity.this, "Code: " + response.code(), Toast.LENGTH_SHORT).show();
return;
}
List<CakesItem> cakeItem = response.body();
mCakeAdapter.getCakeData(cakeItem);
}
#Override
public void onFailure(Call<List<CakesItem>> call, Throwable t) {
Toast.makeText(MainActivity.this, "Unable to load data" + t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
public interface BakingJsonApi {
#GET("/topher/2017/May/59121517_baking/{json}")
Call<List<CakesItem>> getCakes(#Path("json") String path);
}
class Constants {
static final String BAKING_API = "https://d17h27t6h515a5.cloudfront.net/topher/2017/May/59121517_baking/baking.json";
static final String BASE_URL = "https://d17h27t6h515a5.cloudfront.net/";
static final String JSON_PATH = "baking.json";
}
Maybe update Recycler-Adapter can work. I also modified your condition.
call.enqueue(new Callback<List<CakesItem>>() {
#Override
public void onResponse(Call<List<CakesItem>> call, Response<List<CakesItem>> response) {
if (response.isSuccessful()) {
mCakeList = new ArrayList();
mCakeList.addAll(response.body());
mCakeAdapter.notifyDataSetChanged();
}
}
#Override
public void onFailure(Call<List<CakesItem>> call, Throwable t) {
Toast.makeText(MainActivity.this, "Unable to load data" + t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
Try change this condition :
if (!response.isSuccessful()) {
To something like t:
if(response.isSuccessful()){
Modelcake respuesta = response.body();
listcake.addAll(respuesta.getcake()); //in getcake() you get what are you want in your model
adapter.notifyDataSetChanged();
}else{
Log.e("API","onResponse"+response.errorBody());
}
With that should be work.

how to deserialize json object and add response to arraylist

I am creating an app using soundcloud api but I am getting error while parsing json object, I am new in this things so don't know what I am doing wrong here
Here is my interface
ScService.java
public interface SCService
{
#GET("/resolve.json?url=https://m.soundcloud.com/kshmr/sets/materia&client_id=iZIs9mchVcX5lhVRyQGGAYlNPVldzAoX")
Call<Track> getTrack();
}
Here is my model class
Track.java
public class Track
{
#SerializedName("title")
private String mTitle;
#SerializedName("stream_url")
private String mStreamUrl;
public String getTitle()
{
return mTitle;
}
public String getStreamUrl()
{
return mStreamUrl;
}
}
MainActivity.class
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Config.API_URL)
.addConverterFactory(GsonConverterFactory.create()).build();
SCService Scservice = retrofit.create(SCService.class);
Call<Track> call = Scservice.getTrack();
call.enqueue(new Callback<Track>(){
#Override
public void onResponse(Call<Track> call, Response<Track> response)
{
// TODO: Implement this method
if(response.isSuccessful())
{
//String track = response.body().toString();
//Log.e("jsonres",track);
//gson = new GsonBuilder().create();
gson = new Gson();
Track track = gson.fromJson(response.body().toString(), Track.class);
}
#Override
public void onFailure(Call p1, Throwable p2)
{
// TODO: Implement this method
}
});
}
Here is the JSON response from api callcall
enter code here
{"kind":"track","id":399448641,"created_at":"2018/02/14 11:40:02 +0000","user_id":319295181,"duration":188726,"commentable":true,"state":"finished","original_content_size":33279566,"last_modified":"2018/03/10 17:33:18 +0000","sharing":"public","tag_list":"KSHMR \"House of Cards\" \"Sidnie Tipton\" Dharma \"Spinnin' \"","permalink":"houseofcards-mixmaster-05b","streamable":true,"embeddable_by":"all","purchase_url":"http://www.spinninrecords.com/releases/house-of-cards","purchase_title":"Download/Stream","label_id":null,"genre":"Dance & EDM","title":"KSHMR - House of Cards (Ft. Sidnie Tipton)","description":"KSHMR and Sidnie Tipton team up again, this time for the bittersweet sound of \"House of Cards\" \n\nDownload / Stream here: https://www.spinninrecords.com/releases/house-of-cards/","label_name":null,"release":null,"track_type":null,"key_signature":null,"isrc":null,"video_url":null,"bpm":null,"release_year":null,"release_month":null,"release_day":null,"original_format":"wav","license":"all-rights-reserved","uri":"https://api.soundcloud.com/tracks/399448641","user":{"id":319295181,"kind":"user","permalink":"dharmaworldwide","username":"Dharma Worldwide","last_modified":"2018/03/09 12:08:27 +0000","uri":"https://api.soundcloud.com/users/319295181","permalink_url":"http://soundcloud.com/dharmaworldwide","avatar_url":"https://i1.sndcdn.com/avatars-000324744374-jdrkyv-large.jpg"},"permalink_url":"https://soundcloud.com/dharmaworldwide/houseofcards-mixmaster-05b","artwork_url":"https://i1.sndcdn.com/artworks-000302088414-recq7g-large.jpg","stream_url":"https://api.soundcloud.com/tracks/399448641/stream","download_url":"https://api.soundcloud.com/tracks/399448641/download","playback_count":135077,"download_count":0,"favoritings_count":7351,"reposts_count":1354,"comment_count":120,"downloadable":false,"waveform_url":"https://w1.sndcdn.com/0Bcy6WpC8dzY_m.png","attachments_uri":"https://api.soundcloud.com/tracks/399448641/attachments","policy":"ALLOW","monetization_model":"NOT_APPLICABLE"}
I can't use gson.fromJson(...) method, how could I fix this?
Ps-I have pretty much changed my code.
You should do:
EDIT:
ScService.java
public interface SCService
{
#GET("users/17586135/tracks?client_id=iZIs9mchVcX5lhVRyQGGAYlNPVldzAoX")
Call<Track> getTrack();
}
MainActivity.class
Call<Track> call = Scservice.getTracks();
call.enqueue(new Callback<Track>(){
#Override
public void onResponse(Call call, Response<Track> response)
{
// Get the result
Track track = response.body();
}
#Override
public void onFailure(Call p1, Throwable p2)
{
// TODO: Implement this method
}
});
}
More here
The Gson object should be used in this way:
gson = new GsonBuilder().create();
Track track = gson.fromJson(response.body().toString(),Track.class);

How to fetch data from multiple APIs using RxJava with retrofit 2

I am new to RxJava. I want to fetch data from the JSON API. Assume there are two APIs, API 1 and API 2. We fetch a JSON object "mediaId" from API 1. Now, I want to fetch JSON from API 2 with "mediaId". How can I achieve this using RxJava, along with retrofit in Android?
public void gettdata(final Listerner listerner){
postitemses= new ArrayList<>();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://www.mytrendin.com")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
APiService networkAPI = retrofit.create(APiService.class);
Observable<List<Postitems>> observable = networkAPI.getFriendObservable()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
observable.subscribe(new Observer<List<Postitems>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
listerner.onFailure("oops... Something went wrong");
}
#Override
public void onNext(List<Postitems> postitemsList1) {
Postitems postitems;
for (int i=0;i<postitemsList1.size();i++){
postitems = new Postitems();
int id = postitemsList1.get(i).getId();
String title = postitemsList1.get(i).getTitle().getRendered();
String shortdesc= postitemsList1.get(i).getExcerpt().getRendered();
String mediaid= postitemsList1.get(i).getFeatured_media();
String authorid= postitemsList1.get(i).getAuthor();
String date = postitemsList1.get(i).getDate();
String slug = postitemsList1.get(i).getSlug();
Log.i("Hello-slug",""+slug);
String[] mediaurl= mydata(mediaid);
Log.i("Hello-mediaurl",""+mediaurl);
postitems.setId(id);
postitems.setDate(date);
postitems.setSlug(""+slug);
postitems.setPostExcerpt(shortdesc);
postitems.setPostTitle(title);
postitemses.add(postitems);
}
listerner.showpostitems(postitemses);
}
});
}
public String[] mydata(String mediaid){
final String[] mediaurl = new String[1];
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://www.mytrendin.com")
.build();
APiService aPiService = retrofit.create(APiService.class);
Call<Postitems> call = aPiService.getmediaurl(mediaid);
call.enqueue(new Callback<Postitems>() {
#Override
public void onResponse(Call<Postitems> call, Response<Postitems> response) {
Postitems postitemsList1 = response.body();
mediaurl[0] =postitemsList1.getGuid().getRendered();
// mediaurl[0][0] =postitemsList1.get(0).getGuid().getRendered();
}
#Override
public void onFailure(Call<Postitems> call, Throwable t) {
}
});
return mediaurl;
}
error occured
https://www.mytrendin.com
05-09 03:42:09.227 15315-15315/? D/AndroidRuntime: Shutting down VM
--------- beginning of crash
05-09 03:42:09.228 15315-15315/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.mytrendin.mytrendin, PID: 15315
java.lang.NullPointerException: Attempt to invoke virtual method .mytrendin.dashboard.utils.Po stitems$Guid (ZygoteInit.java:755)
Sure you can use the merge operator along with the IO scheduler.By definition,merge can combine multiple Observables into one by merging their emissions.here is an example,
Observable<Integer> odds = Observable.just(1, 3, 5).subscribeOn(someScheduler);
Observable<Integer> evens = Observable.just(2, 4, 6);
Observable.merge(odds, evens)
.subscribe(new Subscriber<Integer>() {
#Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
#Override
public void onError(Throwable error) {
System.err.println("Error: " + error.getMessage());
}
#Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
Output :
Next: 1
Next: 3
Next: 5
Next: 2
Next: 4
Next: 6
Sequence complete.
Something like this in your case,
public Observable<Data> getMergedData() {
return Observable.merge(
networkRepository.getData().subscribeOn(Schedulers.io()),
networkRepository.getData().subscribeOn(Schedulers.io())
);
}
Alright there is another way to solve this, first create a observable for both API, then subscribe and observe changes from your first API subscription.Next create a PublishSubject instance. Which is useful because,once an Observer has subscribed, emits all subsequently observed items to the subscriber.For example publish string values from the api response.
private PublishSubject<String> subject = PublishSubject.create();
subject.observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).filter((s) -> s.size() > 0).subscribe(new Observer<String>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(String str) {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
Then to trigger the observable call onNext from the subject.
subject.onNext("some data from api");
Advantages, very flexible to changes to anywhere in your class scope.
Hope this helps.
for the below snippet
call.enqueue(new Callback<Postitems>() {
#Override
public void onResponse(Call<Postitems> call, Response<Postitems> response) {
Postitems postitemsList1 = response.body();
mediaurl[0] =postitemsList1.getGuid().getRendered();
// mediaurl[0][0] =postitemsList1.get(0).getGuid().getRendered();
//use the concept of publish subject here, which i detailed in answer, example
subject.onNext(postitemsList1.getGuid().getRendered());
//the string data will be passed to the above observable for the subject instance.
}
#Override
public void onFailure(Call<Postitems> call, Throwable t) {
}
});

How to use a Retrofit response in another places

I am using Retrofit in my application and receiving data from my server.
I receive data from my server in responseBody in Retrofit, but when I want to use these received data, my array is null?!!
Here is my class:
public class ActivityApplicationsList extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_applications_list);
Log.i(TAG , "size of response array: " + populateDataFromServer().size())
//this size is 0 but have to be 4 !
}
private ArrayList<StructApplication> populateDataFromServer() {
final ArrayList<StructApplication> mine = new ArrayList<>();
final APIService service = ServiceGenerator.createService(APIService.class, "2015-03-01 14:26:00", "123456", "123456");
Call<ArrayList<AppModel>> call = service.getApp();
call.enqueue(new Callback<ArrayList<AppModel>>() {
#Override
public void onResponse(Call<ArrayList<AppModel>> call, Response<ArrayList<AppModel>> response) {
ArrayList<AppModel> newAppModel = response.body();
for(int i=0 ; i < newAppModel.size();i++){
StructApplication structApplication = new StructApplication();
structApplication.setName(String.valueOf(newAppModel.get(i).getAppId()));
structApplication.setId(newAppModel.get(i).getAppId());
structApplication.setAppVersionReleaseDate(newAppModel.get(i).getAppVersionReDate());
structApplication.setAppDeleted(newAppModel.get(i).getAppDeleted());
mine.add(structApplication);
}
}
#Override
public void onFailure(Call<ArrayList<AppModel>> call, Throwable t) {
}
});
return mine;
}
}
And I debugged to make sure that all data received in onResponse:
As you can see, I received all data correctly, but when I use this response in onCreate of this class it's null!
I really appreciate your answer about this weird problem.
This is because you are printing your list size before the response comes. As request is being sent asynchronously, and your are trying to get size before onResponse() callback method.
try to add this line
Log.i(TAG , "size of response array: " + populateDataFromServer().size())
in onResponse() method after mine.add(structApplication); you will see the right size.
Its return first and execute later, try this way...
private ArrayList<StructApplication> populateDataFromServer() {
final ArrayList<StructApplication> mine = new ArrayList<>();
final APIService service = ServiceGenerator.createService(APIService.class, "2015-03-01 14:26:00", "123456", "123456");
Call<ArrayList<AppModel>> call = service.getApp();
Response<ArrayList<AppModel>> response = responseCall.execute();
ArrayList<AppModel> newAppModel = response.body();
for(int i=0 ; i < newAppModel.size();i++){
StructApplication structApplication = new StructApplication();
structApplication.setName(String.valueOf(newAppModel.get(i).getAppId()));
structApplication.setId(newAppModel.get(i).getAppId());
structApplication.setAppVersionReleaseDate(newAppModel.get(i).getAppVersionReDate());
structApplication.setAppDeleted(newAppModel.get(i).getAppDeleted());
mine.add(structApplication);
}
return mine;
}
It is happening due to api calling because api taking few seconds to get response and meanwhile you returned your mine array. So please return response once you got value from server.
Do like this
Make a global instance for this class like
public class ActivityApplicationsList extends Activity {
ArrayList<StructApplication> mine = new ArrayList();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_applications_list);
populateDataFromServer();
Log.i(TAG , "size of response array: " + mine.size());
}
private void populateDataFromServer() {
final APIService service = ServiceGenerator.createService(APIService.class, "2015-03-01 14:26:00", "123456", "123456");
Call<ArrayList<AppModel>> call = service.getApp();
call.enqueue(new Callback<ArrayList<AppModel>>() {
#Override
public void onResponse(Call<ArrayList<AppModel>> call, Response<ArrayList<AppModel>> response) {
ArrayList<AppModel> newAppModel = response.body();
for(int i=0 ; i < newAppModel.size();i++){
StructApplication structApplication = new StructApplication();
structApplication.setName(String.valueOf(newAppModel.get(i).getAppId()));
structApplication.setId(newAppModel.get(i).getAppId());
structApplication.setAppVersionReleaseDate(newAppModel.get(i).getAppVersionReDate());
structApplication.setAppDeleted(newAppModel.get(i).getAppDeleted());
mine.add(structApplication);
}
}
#Override
public void onFailure(Call<ArrayList<AppModel>> call, Throwable t) {
}
});
}
}
You need to get the response after the request. See code comments
public class ActivityApplicationsList extends Activity
implements Callback<ArrayList<AppModel>> { // Implement callback here
// These are final, so make them fields
final ArrayList<StructApplication> mine = new ArrayList<>();
final APIService service = ServiceGenerator.createService(APIService.class, "2015-03-01 14:26:00", "123456", "123456");
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_applications_list);
populateDataFromServer();
}
// Callback implementation
#Override
public void onResponse(Call<ArrayList<AppModel>> call, Response<ArrayList<AppModel>> response) {
final ArrayList<AppModel> responseBody = response.body();
for(AppModel model : responseBody){
StructApplication structApplication = new StructApplication();
structApplication.setName(String.valueOf(model.getAppId()));
structApplication.setId(model.getAppId());
structApplication.setAppVersionReleaseDate(model.getAppVersionReDate());
structApplication.setAppDeleted(model.getAppDeleted());
mine.add(structApplication);
}
// adapter.notifyDataSetChanged(); // Need this if using ListView
Log.d("SIZE", ""+mine.size()); // Correct size
}
#Override
public void onFailure(Call<ArrayList<AppModel>> call, Throwable t) {
// error
}
private void populateDataFromServer() { // this is void; it can't return
service.getApp().enqueue(ActivityApplicationsList.this);
}
Suggestion, make this constructor
public class StructApplication {
public StructApplication(AppModel model) {
setName(String.valueOf(model.getAppId());
setId(model.getAppId());
setAppDeleted(model.getAppDeleted());
setAppVersionReleaseDate(model.getAppVersionReDate());
}
}
Then, that loop can simply be
mine.add(new StructApplication(model));

Categories

Resources