I am implementing get request with Retrofit in Mvvm architecture, but call.enqueue is not getting executed. When i try it without mvvm architecture in simple activity it works fine.
Github:
https://github.com/nikolabozicbg/Retrofit
I tried to log onresponse and onfailure but nothing gets logged
Here is my Fragment code:
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listItemViewModel = ViewModelProviders.of(this, viewModelFactory)
.get(ListGamesViewModel.class);
listItemViewModel.getListItems().observe(this, new Observer<List<ListGames>>() {
#Override
public void onChanged(#Nullable List<ListGames> listItems) {
}
});
}
View model code:
public class ListGamesViewModel extends ViewModel {
private RetrofitRpository repository;
public ListGamesViewModel(RetrofitRpository repository) {
this.repository = repository;
}
public LiveData<List<ListGames>> getListItems() {
System.out.println("iz live model");
return (LiveData<List<ListGames>>) repository.getListOfData();
}
}
Repository code:
public class RetrofitRpository {
List<ListGames> listItemList;
public RetrofitRpository() {
}
public List<ListGames> getListOfData() {
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("http://mobilews.365scores.com/").addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
LisgGamesCLient client = retrofit.create(LisgGamesCLient.class);
Call<Example> call = client.reposForUser();
call.enqueue(new Callback<Example>() {
#Override
public void onResponse(Call<Example> call, Response<Example> response) {
System.out.println("onresponse");
}
#Override
public void onFailure(Call<Example> call, Throwable t) {
System.out.println("onfail");
}
});
return listItemList;
}
}
CLient code:
public interface LisgGamesCLient {
#GET("Data/Games/?lang=1&uc=6&tz=15&countries=1")
Call<Example> reposForUser();
}
Example class code:
Related
. Get stuck with a basic scenario of loading the data in oncreate of an activity. So I am trying to load the data as soon as i open my activity but when i change the screen orientation it gets called again.
below is my rest client for retrofit
public class MyRestApiClient {
private static Retrofit retrofit = null;
public static Retrofit getClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).connectTimeout(30,TimeUnit.SECONDS).readTimeout(30,TimeUnit.SECONDS).build();
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:8080/rest/")
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build();
return retrofit;
}
}
below is my resturl interface for loading the data
public interface MyRestUrlInterface {
#GET("user/{user_id}")
Call<Object> getData(#Path("user_id") String user_id);
}
below is my viewmodel class:
public class MyViewModelObserver extends ViewModel {
private MutableLiveData<Object> httpCallBackObserver;
public MutableLiveData<Object> getHttpCallBackObserver() {
if (httpCallBackObserver == null) {
httpCallBackObserver = new MutableLiveData<Object>();
}
return httpCallBackObserver;
}
}
below is my Activity code :
public class MyActivity extends AppCompatActivity {
private static final String TAG = "MyActivity" ;
MyRestUrlInterface restUrlInterface;
public MyViewModelObserver myViewModelObserver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
restUrlInterface = MyRestApiClient.getClient().create(MyRestUrlInterface.class);
myViewModelObserver = ViewModelProviders.of(this).get(MyViewModelObserver.class);
myViewModelObserver.getHttpCallBackObserver().observe(this, getData());
//load data via http
Call<Object> call = restUrlInterface.getData("123");
call.enqueue(new Callback<Object>() {
#Override
public void onResponse(Call<Object> call, Response<Object> response) {
myViewModelObserver.getHttpCallBackObserver().setValue(response.body());
}
#Override
public void onFailure(Call<Object> call, Throwable t) {
}
});
}
private Observer<Object> getData(){
return new Observer<Object>() {
#Override
public void onChanged(#Nullable final Object responseString) {
Log.d(TAG,"***** Loaded Data --- "+responseString);
}
};
}
}
How to use view model so that it wont make http call again in screen orientation change
suggested answer:
public class MyViewModelObserver extends ViewModel {
private MutableLiveData<Object> httpCallBackObserver;
public MutableLiveData<Object> getHttpCallBackObserver() {
if (httpCallBackObserver == null) {
httpCallBackObserver = new MutableLiveData<Object>();
loadData();
}
return httpCallBackObserver;
}
private void loadData(){
Call<Object> call = restUrlInterface.getData("123");
call.enqueue(new Callback<Object>() {
#Override
public void onResponse(Call<Object> call, Response<Object> response) {
myViewModelObserver.getHttpCallBackObserver().setValue(response.body());
}
#Override
public void onFailure(Call<Object> call, Throwable t) {
}
});
}
}
I have an API interface which has two overloaded methods:
public interface Api {
#GET("movie/now_playing")
Call<ApiResponse> getMovies(#Query("page") int page);
#GET("search/movie")
Call<ApiResponse> getMovies(#Query("query") String query, #Query("page") int page);
}
First one is used to get now playing movies and the second one to search for movies.
In my MainActivity I use this code to display the data in a RecyclerView:
MovieViewModel movieViewModel = ViewModelProviders.of(this).get(MovieViewModel.class);
MovieAdapter adapter = new MovieAdapter(this);
movieViewModel.moviePagedList.observe(this, adapter::submitList);
recyclerView.setAdapter(adapter);
This is my MovieViewModel class:
public class MovieViewModel extends ViewModel {
LiveData<PagedList<ApiResponse.Movie>> moviePagedList;
public MovieViewModel() {
MovieDataSourceFactory movieDataSourceFactory = new MovieDataSourceFactory();
PagedList.Config config = new PagedList.Config.Builder().setEnablePlaceholders(false).setPageSize(20).build();
moviePagedList = new LivePagedListBuilder<>(movieDataSourceFactory, config).build();
}
}
And this my MovieDataSourceFactory class:
public class MovieDataSourceFactory extends DataSource.Factory<Integer, ApiResponse.Movie> {
private MutableLiveData<PageKeyedDataSource<Integer, ApiResponse.Movie>> movieLiveDataSource = new MutableLiveData<>();
#Override
public DataSource<Integer, ApiResponse.Movie> create() {
MovieDataSource movieDataSource = new MovieDataSource();
movieLiveDataSource.postValue(movieDataSource);
return movieDataSource;
}
}
And this is my MovieDataSource class:
public class MovieDataSource extends PageKeyedDataSource<Integer, ApiResponse.Movie> {
#Override
public void loadInitial(#NonNull LoadInitialParams<Integer> params, #NonNull LoadInitialCallback<Integer, ApiResponse.Movie> callback) {
Api api = RetrofitClient.getInstance().getApi();
Callback<ApiResponse> call = new Callback<ApiResponse>() {
#Override
public void onResponse(#NonNull Call<ApiResponse> call, #NonNull Response<ApiResponse> response) {
if(response.body() != null){
callback.onResult(response.body().movieList, null, page + 1);
}
}
#Override
public void onFailure(#NonNull Call<ApiResponse> call, #NonNull Throwable t) {}
};
api.getMovies(page).enqueue(call);
}
//loadBefore and loadAfter methods
}
If I run this code, everything works fine, the first query is invoked and I get the result correctly. The question is, how can I dynamically use one or the other?
api.getMovies(query, page).enqueue(call);
boolean globalVariableShouldUseGetMoviesCallWithOnlyOneArgument = true
private void doNetworkCallAndCheckBooleanStatus(){
if (globalVariableShouldUseGetMoviesCallWithOnlyOneArgument) {
getMovies(thisIsOneArgumentAsYouCanSee);
} else {
getMovies(thisIsUsingTwoArguments, asYouCanSee);
}
}
private void someOtherMethodInTheApp() {
globalVariableShouldUseGetMoviesCallWithOnlyOneArgument = false
doNetworkCallAndCheckBooleanStatus()
}
I am trying to get values from a web using retrofit and rxAndroid but onNext doesn't called.
Here, my classes:
public class ForumService {
private static final String FORUM_SERVER_URL = "http://192.168.1.104:8080/curso-fullstack/symfony/web";
private ForumApi mForumApi;
public ForumService(){
RequestInterceptor requestInterceptor = new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
request.addHeader("Accept", "application/json");
}
};
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(FORUM_SERVER_URL)
.setRequestInterceptor(requestInterceptor)
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
mForumApi = restAdapter.create(ForumApi.class);
}
public ForumApi getmForumApi() {
return mForumApi;
}
public interface ForumApi{
#GET("/video/lasts_videos")
public Observable<List<Data>> getVideos();
/*#GET("/posts/{id}")
public Observable<Post>
getPost(#Path("id") int postId);
#GET("/comments")
public Observable<List<Comment>>
getComments(#Query("postId") int postId);
#POST("/posts")
public Observable<Post> postPost(Post post);*/
}
}
public class ListPresenter {
ListActivity mView;
ForumService mForum;
public ListPresenter(ListActivity mView, ForumService mForum) {
this.mView = mView;
this.mForum = mForum;
}
public void loadPosts() {
mForum.getmForumApi()
.getVideos()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<Data>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(List<Data> posts) {
mView.displayPosts(posts);
}
});
}
}
And then, I execute the method loadPosts() from my activity, to fill a list and display in a ListView.
If i look about android logs, I can see how retrofit displays to me that found the results, but for any reason onNext is never called.
From the discussion in the comments:
onNext wan't been called because there was a problem in the JSON deserialization. onError was called instead.
I am using retrofit2 with rxjava2.
I have used mostly the latest library in my gradle and I have tried many methods for creating adapter .
I have also created some custom adapter but nothing seems to work with it
service :
public static Retrofit getClient() {
if (retrofit==null) {
retrofit = new Retrofit.Builder().baseUrl(AppConstants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create()).
addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();
}
return retrofit;
}
fragment code:
ApiInterface apiInterface
=ApiClient.getClient().create(ApiInterface.class);
apiInterface.getCategoryVideos(AppConstants.API_KEY)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Observer<Video>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Video value) {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
I have tried many adapters but no adapter is working . I am
the log output is :
Any suggestion or solution is appreciated .
I have also tried the solution in this link stackoverflow solution
Try to change create client
public class MyClient {
private static MyClient instance;
private ApiInterface apiInterface;
private MyClient() {
final Retrofit retrofit = new Retrofit.Builder().baseUrl(AppConstants.BASE_URL)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
gitHubService = retrofit.create(ApiInterface.class);
}
public static MyClient getInstance() {
if (instance == null) {
instance = new MyClient();
}
return instance;
}
}
and fragment code
private Subscription subscription;
...
subscription = MyClient.getInstance().getCategoryVideos(AppConstants.API_KEY)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Video>() {
#Override public void onCompleted() {
Log.d(TAG, "In onCompleted()");
}
#Override public void onError(Throwable e) {
e.printStackTrace();
Log.d(TAG, "In onError()");
}
#Override public void onNext(Video value) {
Log.d(TAG, "In onNext()");
}
});
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).