i made interface like this in "TestService.java"
public interface TestService {
#GET("/api/users/2")
Call<String> getTest();
}
and
"RetrofitClient.java"
public class RetrofitClient {
private static Retrofit instance;
public static Retrofit getInstance() {
if(instance == null)
instance = new Retrofit.Builder()
.baseUrl("https://reqres.in/")
.build();
return instance;
}
}
in "MainActivity.java"
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Retrofit retrofitClient = RetrofitClient.getInstance();
TestService testService = retrofitClient.create(TestService.class);
Call<String> repos = testService.getTest(); //problem
}
}
i'm first at android java, and i don't know how to use Retrofit..
what is the problem and how to print response? ( i need also header information)
You need to asynchronously call it on the main thread.
Call<ResponseBody> repos = testService.getTest();
repos.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
//response
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
//error
}
});
There are plenty of resources online, to know more you can go through the following articles.
vogella
android.jlelse
Related
Android newly here. I am working on a popular movies app that fetches some movie data from moved.org and display to users when tapping on movie thumbnail. Recently, I have been working on setting up retrofit in my app for two weeks. I am trying to use MVVM pattern. My goals is to get response from api.moviedb.org so that, eventually, I can display movie posters in recycler view. For some reason, I am not able to get any response from the api call using retrofit. I think I did something wrong with setting up retrofit but can't find out how I messed up... I feel like I am hard stuck.. Any help from experienced android developers would be much appreciated:)
Github link to my project
On create method in MainActivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.rvMovies);
movieViewModel = ViewModelProviders.of(this).get(MovieViewModel.class);
// Log.d("viewmodel", String.valueOf(movieViewModel));
movieViewModel.getMoviesLiveData().observe(this, new Observer<MovieResult>() {
#Override
public void onChanged(MovieResult movieResult) {
Log.d("movieResult", String.valueOf(movieResult));
}
});
}
ViewModel Class:
public class MovieViewModel extends AndroidViewModel {
private MutableLiveData<MovieResult> movieLiveData;
private MovieRepository movieRepository;
public MovieViewModel(#NonNull Application application){
super(application);
}
public void init(){
if (movieLiveData != null){
return;
}
movieRepository = MovieRepository.getInstance();
movieLiveData = movieRepository.getMovies("api_key_here");
}
public LiveData<MovieResult> getMoviesLiveData() {
init();
return movieLiveData;
}
}
Respository:
public class MovieRepository {
private static MovieRepository movieRepository;
public static MovieRepository getInstance(){
if (movieRepository == null){
movieRepository = new MovieRepository();
}
return movieRepository;
}
private GetMovieService service;
public MovieRepository(){
service = RetrofitInstance.getRetrofitInstance().create(GetMovieService.class);
}
public MutableLiveData<MovieResult> getMovies(String api){
Log.d("getmovies","called");
final MutableLiveData<MovieResult> movieData = new MutableLiveData<>();
service.getMovieResult(api).enqueue(new Callback<MovieResult>() {
#Override
public void onResponse(Call<MovieResult> call, Response<MovieResult> response) {
if (response.isSuccessful()){
movieData.setValue(response.body());
Log.d("debug", String.valueOf(movieData));
}
}
#Override
public void onFailure(Call<MovieResult> call, Throwable t) {
movieData.setValue(null);
Log.d("onfailure","why");
}
});
return movieData;
}
}
RetrofitInstance:
public class RetrofitInstance {
private static Retrofit retrofit;
private static final String BASE_URL = "http://api.themoviedb.org/3/";
public static Retrofit getRetrofitInstance(){
if(retrofit == null){
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
GetMovieService.Java
public interface GetMovieService {
#GET("movie/popular")
Call<MovieResult> getMovieResult(#Query("api_key") String apiKey);
}
logical:
log output
I don't have any type of error when I run the application, but the problem is I don't retrieve the data from my interface.
I use Dagger to inject dependencies, and retrofit to retrieve the data from Last.fm Api.
When I try to use a log to check if the data is null, the message is not displayed in logcat and don't work with a toast message.
Service interface
public interface GenreTopTracksService {
#GET("?method=tag.gettoptracks&format=json")
Single<GenreTopTracksResponse> getGenreTopTracks(#Query("tag") String user, #Query("limit") int limit, #Query("api_key") String apiKey);
}
Presenter interface
public interface GenreTopTracksPresenter {
void getGenreTopTracks(String tag, int limit, String apiKey);
}
Interactor interface
public interface GenreTopTracksInteractor {
Single<GenreTopTracksResponse> getGenreTopTracks(String tag, int limit, String apiKey);
}
View interface -- here i have the update data method
public interface GenreTopTracksView {
void updateData(List<Track> tracks);
}
this class is an a implementation of the GenreTopTrackPresneter
public class GenreTopTracksPrensenterImpl implements GenreTopTracksPresenter {
Disposable mDisposable;
GenreTopTracksInteractor mInteractor;
GenreTopTracksView mGenreViewData;
public GenreTopTracksPrensenterImpl(GenreTopTracksInteractor mInteractor, GenreTopTracksView mGenreViewData) {
this.mInteractor = mInteractor;
this.mGenreViewData = mGenreViewData;
}
#Override
public void getGenreTopTracks(String tag, int limit, String apiKey) {
disposeRequest();
mDisposable = mInteractor.getGenreTopTracks(tag, limit, apiKey)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(new Function<GenreTopTracksResponse, List<Track>>() {
#Override
public List<Track> apply(#NonNull GenreTopTracksResponse topTracksResponse) throws Exception {
if (topTracksResponse != null && topTracksResponse.getTopTracks() != null && topTracksResponse.getTopTracks().getTracks() != null) {
return topTracksResponse.getTopTracks().getTracks();
}
return new ArrayList<Track>();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<Track>>() {
#Override
public void accept(#NonNull List<Track> tracks) throws Exception {
if (tracks.size() == 0) {
// NO se muestra nada
}else{
mGenreViewData.updateData(tracks);
}
}
}, new Consumer<Throwable>() {
#Override
public void accept(#NonNull Throwable throwable) throws Exception {
Log.d("ERRORGENRE", "Errorxd");
}
});
}
private void disposeRequest() {
if (mDisposable != null && !mDisposable.isDisposed()) {
mDisposable.dispose();
}
}
}
THis is my module class to inject dependencies to my main activity
#Module
public class GenreTopTracksModule {
GenreTopTracksView mView;
public GenreTopTracksModule(GenreTopTracksView view) {
mView = view;
}
// provides the view to create the top tracks presenter
#Singleton
#Provides
public GenreTopTracksView providesTopTracksView() {
return this.mView;
}
// provides a converter factory to create the retrofit instance
#Singleton
#Provides
public Converter.Factory providesConverterFactory() {
return GsonConverterFactory.create();
}
// provides a call adapter factory needed to integrate rxjava with retrofit
#Singleton
#Provides
public CallAdapter.Factory providesCallAdapterFactory() {
return RxJava2CallAdapterFactory.create();
}
// provides a retrofit instance to create the top tracks interactor
#Singleton
#Provides
public Retrofit providesRetrofit(Converter.Factory converter, CallAdapter.Factory adapter) {
return new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addCallAdapterFactory(adapter)
.addConverterFactory(converter)
.build();
}
// provides top tracks interactor to make an instance of the presenter
#Singleton
#Provides
public GenreTopTracksInteractor providesTopTopTracksInteractor(Retrofit retrofit) {
return new GenreTopTracksInteractorImplementation(retrofit);
}
// provides top track presenter
#Singleton
#Provides
public GenreTopTracksPresenter providesTopTracksPresenter(GenreTopTracksInteractor interactor, GenreTopTracksView mView) {
return new GenreTopTracksPrensenterImpl(interactor, mView);
}
}
And this is my main activity
public class SelectionActivity extends AppCompatActivity implements GenreTopTracksView{
#Inject
GenreTopTracksPresenter mPresenter;
Button mButton;
EditText mEditText;
String tag;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_selection);
DaggerGenreTopTracksComponent.builder().genreTopTracksModule(new GenreTopTracksModule(this)).build().inject(this);
mButton = (Button) findViewById(R.id.button_prueba);
mEditText = (EditText) findViewById(R.id.edit_prueba);
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tag = mEditText.getText().toString();
mPresenter.getGenreTopTracks(tag, Constants.TOP_ITEMS_LIMIT, Constants.API_KEY);
}
});
}
#Override
public void updateData(List<Track> tracks) {
if(tracks != null){
for(int x = 0; x<tracks.size(); x++){
Log.d("datasetTrack", tracks.get(x).getName());
Toast.makeText(SelectionActivity.this, tracks.get(x).getName(), Toast.LENGTH_SHORT).show();
}
}else if(tracks == null){
Log.d("datasetTrack", "datos nulos :(");
Toast.makeText(SelectionActivity.this, "Datos nulos", Toast.LENGTH_SHORT).show();
}
}
}
I need to see the data in the "updateData" method.
First of all recommend you add retrofit client interceptor
Add dependency in build.gradle:
compile 'com.squareup.okhttp3:logging-interceptor:$your_version'
in GenreTopTrackModule change method
#Singleton
#Provides
public Retrofit providesRetrofit(Converter.Factory converter, CallAdapter.Factory adapter) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
return new Retrofit.Builder()
.client(client)
.baseUrl(Constants.BASE_URL)
.addCallAdapterFactory(adapter)
.addConverterFactory(converter)
.build();
}
As a result in Logcat you will see response what last.fm api return. If response return right check you implementation
Trying to use Robolectric and Mockito to test my Retrofit calls in my Android app but I am getting the following error:
Wanted but not invoked: mockApi.register(
,
);
-> at ServiceTest.testAPI(ServiceTest.java:58) Actually, there were zero interactions with this mock.
The RetroFit API call is defined in an interface as follows:
#FormUrlEncoded
#POST("/register")
void register(
#FieldMap Map<String, String> registrationParams,
Callback<JsonObject> response) ;
My test class is as follows:
#Config(constants = BuildConfig.class)
#RunWith(TestRunner.class)
public class SharedServiceTest {
private RegistrationActivity activity;
#Mock
private SharedService mockApi;
#Captor
private ArgumentCaptor<Callback<JsonObject>> cb;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
ActivityController<RegistrationActivity> controller = Robolectric.buildActivity(RegistrationActivity.class);
activity = controller.get();
controller.create();
}
#Test
public void testAPI() throws Exception {
activity.populateFields();
activity.validateFields();
activity.register("");
Mockito.verify(mockApi).register(Mockito.anyMap(), cb.capture());
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("sessionToken", Mockito.anyString());
jsonObject.addProperty("userId", Mockito.anyString());
cb.getValue().success(jsonObject, null);
Assert.assertTrue(ShadowToast.getTextOfLatestToast().contains("Registration completed"));
}
}
The method in my RegistrationActivity that uses the API is as follows:
public void register(){
MyApplication.getInstance().getSharedService().register(mRegistrationParams, new Callback<JsonObject>() {
#Override
public void success(JsonObject jsonObject, retrofit.client.Response response) {
Toast.makeText(RegistrationActivity.this, "Registration completed", Toast.LENGTH_LONG).show();
}
#Override
public void failure(RetrofitError error) {
Toast.makeText(RegistrationActivity.this, RetrofitUtils.getErrorMessage(error), Toast.LENGTH_LONG).show();
}
});
}
The real Retrofit service comes from my own Application class which I have mocked in my test folder for robolectric to use:
public class TestMyApplication extends MyApplication
implements TestLifecycleApplication {
#Override
public void onCreate() {
super.onCreate();
}
#Override public void beforeTest(Method method) {
}
#Override public void prepareTest(Object test) {
}
#Override public void afterTest(Method method) {
}
#Override public CPSharedService getCPSharedService() {
return Mockito.mock(SharedService.class);
}
}
I have searched over the other questions on SO that have this error but none of them match what I am trying to do here or provide a solution to my issue so I am just wondering what I am doing wrong?
The mocked instance of SharedService in your TestMyApplication is not the same you declared your test class.
The Mockito.verify(mockApi).register(Mockito.anyMap(), cb.capture()); is failing because the instance referred by mockApi field is actually never called.
Another problem is that the getter in TestMyApplication always returns a new mock for each invokation:
#Override public CPSharedService getCPSharedService() {
return Mockito.mock(SharedService.class); //this creates a new "mocked" instance
}
Your scenario is not 100% clear to me, but it would be better if you could let your test set the instance of the mockApi field in your TestMyApplication instance:
public class TestMyApplication extends MyApplication
implements TestLifecycleApplication {
private SharedService sharedService;
#Override
public void onCreate() {
super.onCreate();
}
#Override public void beforeTest(Method method) {
}
#Override public void prepareTest(Object test) {
}
#Override public void afterTest(Method method) {
}
#Override public CPSharedService getCPSharedService() {
return this.sharedService;
}
public void setCPSharedService(SharedService sharedService) {
// store your mock
this.sharedService = sharedService;
}
}
and in your test class:
#Test
public void testAPI() throws Exception {
// configure you TestMyApplication
assertTrue(MyApplication.getInstance() instanceof TestMyApplication);
TestMyApplication testMyApp = (TestMyApplication) MyApplication.getInstance();
testMyApp.setCPSharedService(this.mockApi);
activity.populateFields();
activity.validateFields();
activity.register("");
Mockito.verify(this.mockApi).register(Mockito.anyMap(), cb.capture());
...
}
I am new to android programming and I am trying to connect to server with retrofit and get some data. I made a little example just to check if it would return some data. First there is a problem that I don't know if I even wrote the code to do what I want and second I get the errors:
"Error:(64, 52) error: is not abstract and does not override abstract method failure(RetrofitError) in Callback"
and 2 errors " Error:(67, 13) error: method does not override or implement a method from a supertype"
Here is my code
public class MainActivity extends ListActivity{
public static final String ENDPOINT = "http://tinoba.hostzi.com";
List<Jelovnik> jelovnik;
Button gumb;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gumb = (Button)findViewById(R.id.gumb);
}
public void stisni(View view) {
RestAdapter adapter = new RestAdapter.Builder()
.setEndpoint(ENDPOINT)
.build();
JelovnikAPI api = adapter.create(JelovnikAPI.class);
api.getFeed(new Callback<List<Jelovnik>>() {
#Override
public void onResponse(Response<List<Jelovnik>> response, Retrofit retrofit) {
jelovnik = response.body();
gumb.setText(jelovnik.get(0).getIme().toString());
}
#Override
public void onFailure(Throwable throwable) {
}
});
}
}
and my retrofit interface
public interface JelovnikAPI {
#GET("/read.php")
public void getFeed(Callback<List<Jelovnik>> response);
}
The version of Callback you are using is from Retrofit 2 and you are still using Retrofit 1.x. Callback has two methods, failure and success. Your callback should look like
new Callback<List<Jelovnik>>() {
#Override
success(List<Jelovnik> t, Response response) {
}
#Override
public void failure(RetrofitError error) {
}
});
Replace Throwable with RetrofitError:
#Override
public void onFailure(RetrofitError retrofitError) {
}
In my MainActivity I have a method called getAPI that returns an OTBServiceWrapper. This is used to setup retrofit for calling to an API.
In my MainActivityTest file I am trying to stub out the new OTBService().getService() call that the getApi method is making so I can return a MockedOTBService which changes the client to a custom one that return json.
As is, the current implementation will it the MockedOTBService if I had to place a logger within MockedOTBService but also falls through and calls the real api, which is not want I want in a test.
I am trying to stub the Retrofit API calls using Mockito and return json. I cant seem to understand why the stub is being called yet is not stubbing the method in question.
Notes:
I am using ActivityInstrumentationTestCase2
I am only running one test
If I add a verify(mockedOTBService, atLeastOnce()).getService(); is says it was never called.
If I change the when...thenReturn to use a mMainActivity = spy(getActivity()) there is not change and the real API is called.
Logcat Output
Logger﹕ MockedOTBService was called // Mock is called
Logger﹕ Real OTBService was called // Real API is called
Logger﹕ MainActivity getAPI method class is "$Proxy1" // Mock is shown in MainActivity
Logger﹕ RealAPIResponse JSON Parsed ID: 266 // Real API response returned
Real Flow
MainActivity.onCreate() > OTBService.getService() > OTBServiceWrapper.createSearch(...)
Trying to Achieve within Tests
MainActivity.onCreate() > MockedOTBService.getService() > OTBServiceWrapper.createSearch(...)
MainActivity.java
public class MainActivity extends Activity {
private OTBServiceWrapper serviceWrapper;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getApi().createSearch(...)
}
public OTBServiceWrapper getApi() {
return new OTBService().getService();
}
}
OTBService.java
public class OTBService {
public OTBServiceWrapper getService() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(Constants.API_URL)
.build();
return restAdapter.create(OTBServiceWrapper.class);
}
}
OTBServiceWrapper.java
public interface OTBServiceWrapper {
#POST(Constants.API_SEARCHES_POST_URL)
void createSearch(#Body Request request, Callback<Request.Response> callback);
}
MainActivityTest.java
public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
private OTBService mMockedOTBService;
private MainActivity mMainActivity;
private View mSearchButton;
public MainActivityTest() { super(MainActivity.class); }
#Override
protected void setUp() throws Exception {
super.setUp();
setActivityInitialTouchMode(true);
System.setProperty("dexmaker.dexcache", getInstrumentation().getTargetContext().getCacheDir().getPath());
mMockedOTBService = mock(OTBService.class);
when(mMockedOTBService.getService()).thenReturn(new MockedOTBService(getInstrumentation().getContext()).getService());
mMainActivity = getActivity();
mSearchButton = mMainActivity.findViewById(R.id.AbSearchButton);
mYourHolidayButton = mMainActivity.findViewById(R.id.AbYourHolidayButton);
}
public void testButtonActions() {
TouchUtils.clickView(this, mSearchButton);
...
}
}
MockedOTBService.java
public class MockedOTBService {
private Context context;
public MockedOTBService(Context context) { this.context = context; }
public OTBServiceWrapper getService() {
RestAdapter restAdapter;
restAdapter = new RestAdapter.Builder()
.setClient(new LocalJsonClient(context))
.setEndpoint(Constants.API_TEST_URL)
.build();
return restAdapter.create(OTBServiceWrapper.class);
}
}
LocalJsonClient.java
#SuppressLint("DefaultLocale")
public class LocalJsonClient implements Client { ... }
build.gradle
dependencies {
androidTestCompile 'com.google.dexmaker:dexmaker:1.0'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.0'
}
Remove the need for mocking your request by allowing the Activity to set the service.
In your MainActivity create a class variable and a class setter for the service. It needs to be a at the class scope to prevent the OnCreate method being called before you have set the service to what you want it to be. Also create an instance getter which sets the service if you have not already.
In your test before you call getActivity() set the service to be your mock service. (Maybe think about moving this out to a support object).
MainActivity.java
public class MainActivity extends Activity {
private static OTBServiceWrapper serviceWrapper;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getServiceWrapper.createSearch(...)
}
public OTBServiceWrapper getServiceWrapper() {
if (serviceWrapper == null) {
MainActivity.setServiceWrapper(new OTBService().getService());
}
return serviceWrapper;
}
public static void setServiceWrapper(OTBServiceWrapper serviceWrapper) {
MainActivity.serviceWrapper = serviceWrapper;
}
}
MainActivityTest.java
public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
private MainActivity mMainActivity;
public MainActivityTest() { super(MainActivity.class); }
#Override
protected void setUp() throws Exception {
super.setUp();
setActivityInitialTouchMode(true);
MainActivity.setServiceWrapper(
new MockedOTBService(getInstrumentation().getContext()).getService()
);
mMainActivity = getActivity();
}
}