No response from Retrofit2 - java

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

Related

How can i return a list from retrofit onResponse?

I've seen a few similar questions but they don't seem to answer my problem exactly. I'm pulling a list with Retrofit and I want to export it to a list and create a listview. But I am not getting any return from onResponse. I've also tried returning a list directly with return. Please help.
this is the callback func
listCatcher just holds a list
Ibreeds is interface
public ListCatcher allBreeds(View view){
ArrayList<String> breedList = new ArrayList<>(breeds);
Ibreeds.allBreeds().enqueue(new Callback<Breeds>() {
#Override
public void onResponse(Call<Breeds> call, Response<Breeds> response) {
List<String> breeds = response.body().getMessage();
for (String b: breeds){
breedList.add(b);
}
}
#Override
public void onFailure(Call<Breeds> call, Throwable t) {
Snackbar.make(view,R.string.connectionStatus, 3000 ).show();
}
});
ListCatcher listcatcher = new ListCatcher(breedList);
return listcatcher;
}
public interface BreedsDAOInterface {
#GET("breeds/list")
Call<Breeds> allBreeds();
#GET("breed/{breed}/list")
Call<Breeds> listSubBreed(#Path("breed") String breed);
#GET("breed/{breed}/images")
Call<Breeds> listBreedImages(#Path("breed") String breed);
#GET("breed/{breed}/{subBreed}/images")
Call<Breeds> listSubBreedImages(#Path("breed") String breed, #Path("subBreed") String subBreed);
#GET("breeds/image/random")
Call<Breeds> iFeelLucky();
}
public class ApiUtils {
public static final String BASE_URL = "https://dog.ceo/api/";
public static BreedsDAOInterface getBreedsDaoInterface(){
return RetrofitClient.getClient(BASE_URL).create(BreedsDAOInterface.class);
}
}
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseURL){
if (retrofit == null){
retrofit = new Retrofit
.Builder()
.baseUrl(baseURL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
public class Breeds {
#SerializedName("message")
#Expose
private List<String> message;
public List<String> getMessage() {
return message;
}
public void setMessage(List<String> message) {
this.message = message;
}
}
EDIT
I found the solution to the problem:
listCatcher deleted
public class HomeActivity extends AppCompatActivity {
List<String> breedsList = new ArrayList<>();
private BreedsInterface Ibreeds;
private RecyclerViewAdapter RWAdapter;
private ActivityHomeBinding binding;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityHomeBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
Ibreeds = ApiUtils.getBreedsDaoInterface();
allBreeds();
}
public void allBreeds(){
Ibreeds.allBreeds().enqueue(new Callback<Answer>() {
#Override
public void onResponse(Call<Answer> call, Response<Answer> response) {
List<String> breedResponceList = response.body().getMessage();
breedsList.clear();
breedsList.addAll(breedResponceList);
initRecyclerView();
}
#Override
public void onFailure(Call<Answer> call, Throwable t) {
throwError();
}
});
}
private void throwError() {
Snackbar.make(binding.getRoot(), R.string.connectionStatus, 3000).show();
}
private void initRecyclerView() {
RWAdapter = new RecyclerViewAdapter(breedsList);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
binding.recyclerView.setAdapter(RWAdapter);
}
}
I added the adapter to the enqueue function via a function

How to pass an intent variable to retrofit using Android Pagination Library

I am implementing android pagination library in my app and would like to pass "id" of an item from my activity to the data source where my network call is made
AddCommentActivity.java
//I want to pass this string to the network call.
String image_id = getIntent().getStringExtra("image_id");
CommentViewModel commentViewModel = new ViewModelProvider(this).get(CommentViewModel.class);
CommentDataSource.java
public class CommentDataSource extends PageKeyedDataSource<Long, Comment> {
public CommentDataSource(){
progress_bar = new MutableLiveData<>();
}
#Override
public void loadInitial(#NonNull final LoadInitialParams<Long> params, #NonNull final LoadInitialCallback<Long, Comment> callback) {
RestApi restApi = RetrofitApi.create();
Call<CommentResponse> call = restApi.getComments(FIRST_PAGE, "I want the image_id from activity here");
call.enqueue(new Callback<CommentResponse>() {
#Override
public void onResponse(Call<CommentResponse> call, Response<CommentResponse> response) {
}
CommentDataSourceFactory.java
public class CommentDataFactory extends DataSource.Factory<Long, Comment> {
public MutableLiveData<CommentDataSource> commentLiveDataSource = new MutableLiveData<>();
public CommentDataFactory() {
}
#Override
public DataSource<Long, Comment> create() {
CommentDataSource commentDataSource = new CommentDataSource();
commentLiveDataSource.postValue(commentDataSource);
return commentDataSource;
}
CommentViewModel.java
public class CommentViewModel extends ViewModel {
public LiveData<PagedList<Comment>> commentPagedList;
public LiveData<CommentDataSource> liveDataSource;
public LiveData progressBar;
public CommentViewModel(){
CommentDataFactory commentDataFactory = new CommentDataFactory();
liveDataSource = commentDataFactory.commentLiveDataSource;
progressBar = Transformations.switchMap(liveDataSource, CommentDataSource::getProgressBar);
PagedList.Config config = new PagedList.Config.Builder()
.setEnablePlaceholders(false)
.setPageSize(CommentDataSource.PAGE_SIZE)
.build();
commentPagedList = new LivePagedListBuilder<>(commentDataFactory, config).build();
}
public LiveData<PagedList<Comment>> getCommentData(){
return commentPagedList;
}
public void getRefreshedData(){
getCommentData().getValue().getDataSource().invalidate();
}
}
How to do that.? I checked Passing variable to paging library class which is exactly what I want to do but I dont understand it and the code gives errors. Errors such as
Cannot create an instance of class CommentViewModel
CommentViewModel has no zero argument constructor
Okay do:
commentViewmodel1.getCommentData().observe(this, new Observer<PagedList<Comments>>(){
#Override
public void onChanged(PagedList<Comment>
comments){
adapter.submitList(comments);
}
});

Android Architecture SingleLiveEvent and EventObserver Practicle Example in Java

I try to make sample login page with two fields (username, password) and save button with android architecture component, using android data binding, validating the data in viewmodel and from view model I make call to repository for remote server call as mentioned in official doc, remote server return me userid with success so how can I start new fragment from view model using this success? I learn something about singleLiveEvent and EventObserver, but I'm not able to find there clear usage example:
LoginViewModel
private MutableLiveData<String> snackbarStringSingleLiveEvent= new MutableLiveData<>();
#Inject
public LoginViewModel(#NonNull AppDatabase appDatabase,
#NonNull JobPortalApplication application,
#NonNull MyApiEndpointInterface myApiEndpointInterface) {
super(application);
loginRepository = new LoginRepository(application, appDatabase, myApiEndpointInterface);
snackbarStringSingleLiveEvent = loginRepository.getLogin(username.get(), password.get(), type.get());
}
public MutableLiveData<String> getSnackbarStringSingleLiveEvent() {
return snackbarStringSingleLiveEvent;
}
Repository
public SingleLiveEvent<String> getLogin(String name, String password, String type) {
SingleLiveEvent<String> mutableLiveData = new SingleLiveEvent<>();
apiEndpointInterface.getlogin(name, password, type).enqueue(new Callback<GenericResponse>() {
#Override
public void onResponse(Call<GenericResponse> call, Response<GenericResponse> response) {
mutableLiveData.setValue(response.body().getMessage());
}
#Override
public void onFailure(Call<GenericResponse> responseCall, Throwable t) {
mutableLiveData.setValue(Constant.FAILED);
}
});
return mutableLiveData;
}
Login Fragment
private void observeViewModel(final LoginViewModel viewModel) {
// Observe project data
viewModel.getSnackbarStringSingleLiveEvent().observe(this, new Observer<String>() {
#Override
public void onChanged(String s) {
}
});
}
How can I use EventObserver in above case? Any practical example?
Check out below example about how you can create single LiveEvent to observe only one time as LiveData :
Create a class called Event as below that will provide our data once and acts as child of LiveData wrapper :
public class Event<T> {
private boolean hasBeenHandled = false;
private T content;
public Event(T content) {
this.content = content;
}
public T getContentIfNotHandled() {
if (hasBeenHandled) {
return null;
} else {
hasBeenHandled = true;
return content;
}
}
public boolean isHandled() {
return hasBeenHandled;
}
}
Then declare this EventObserver class like below so that we don't end up placing condition for checking about Event handled every time, everywhere :
public class EventObserver<T> implements Observer<Event<T>> {
private OnEventChanged onEventChanged;
public EventObserver(OnEventChanged onEventChanged) {
this.onEventChanged = onEventChanged;
}
#Override
public void onChanged(#Nullable Event<T> tEvent) {
if (tEvent != null && tEvent.getContentIfNotHandled() != null && onEventChanged != null)
onEventChanged.onUnhandledContent(tEvent.getContentIfNotHandled());
}
interface OnEventChanged<T> {
void onUnhandledContent(T data);
}
}
And How you can implement it :
MutableLiveData<Event<String>> data = new MutableLiveData<>();
// And observe like below
data.observe(lifecycleOwner, new EventObserver<String>(data -> {
// your unhandled data would be here for one time.
}));
// And this is how you add data as event to LiveData
data.setValue(new Event(""));
Refer here for details.
Edit for O.P.:
Yes, data.setValue(new Event("")); is meant for repository when you've got response from API (Remember to return same LiveData type you've taken in VM instead of SingleLiveEvent class though).
So, let's say you've created LiveData in ViewModel like below :
private MutableLiveData<Event<String>> snackbarStringSingleLiveEvent= new MutableLiveData<>();
You provide value to this livedata as Single Event from repository like below :
#Override
public void onResponse(Call<GenericResponse> call, Response<GenericResponse> response) {
mutableLiveData.setValue(new Event(response.body().getMessage())); // we set it as Event wrapper class.
}
And observe it on UI (Fragment) like below :
viewModel.getSnackbarStringSingleLiveEvent().observe(this, new EventObserver<String>(data -> {
// your unhandled data would be here for one time.
}));
Event.java
public class Event<T> {
private T content;
private boolean hasBeenHandled = false;
public Event(T content) {
this.content = content;
}
/**
* Returns the content and prevents its use again.
*/
public T getContentIfNotHandled() {
if (hasBeenHandled) {
return null;
} else {
hasBeenHandled = true;
return content;
}
}
/**
* Returns the content, even if it's already been handled.
*/
public T peekContent() {
return content;
}
}
EventObserver.java
public class EventObserver<T> implements Observer<Event<? extends T>> {
public interface EventUnhandledContent<T> {
void onEventUnhandledContent(T t);
}
private EventUnhandledContent<T> content;
public EventObserver(EventUnhandledContent<T> content) {
this.content = content;
}
#Override
public void onChanged(Event<? extends T> event) {
if (event != null) {
T result = event.getContentIfNotHandled();
if (result != null && content != null) {
content.onEventUnhandledContent(result);
}
}
}
}
Example, In ViewModel Class
public class LoginViewModel extends BaseViewModel {
private MutableLiveData<Event<Boolean>> _isProgressEnabled = new MutableLiveData<>();
LiveData<Event<Boolean>> isProgressEnabled = _isProgressEnabled;
private AppService appService;
private SchedulerProvider schedulerProvider;
private SharedPreferences preferences;
#Inject
LoginViewModel(
AppService appService,
SchedulerProvider schedulerProvider,
SharedPreferences preferences
) {
this.appService = appService;
this.schedulerProvider = schedulerProvider;
this.preferences = preferences;
}
public void login(){
appService.login("username", "password")
.subscribeOn(schedulerProvider.executorIo())
.observeOn(schedulerProvider.ui())
.subscribe(_userLoginDetails::setValue,
_userLoginDetailsError::setValue,
() -> _isProgressEnabled.setValue(new Event<>(false)),
d -> _isProgressEnabled.setValue(new Event<>(true))
)
}
}
In Login Fragment,
viewModel.isProgressEnabled.observe(this, new EventObserver<>(hasEnabled -> {
if (hasEnabled) {
// showProgress
} else {
// hideProgress
}
}));
Using Event and EventObserver class we can achieve the same like SingleLiveEvent class but if you are thinking a lot of boilerplate code just avoid this method. I hope it would help you and give some idea about why we are using SingleEvent in LiveData.
I understand that Google gives the guidelines to use LiveData between the ViewModel and UI but there are edge cases where using LiveData as a SingleLiveEvent is like reinventing the wheel. For single time messaging between the view model and user interface we can use the delegate design pattern. When initializing the view model in the activity we just have to set the activity as the implementer of the interface. Then throughout our view model we can call the delegate method.
Interface
public interface Snackable:
void showSnackbarMessage(String message);
UI
public class MyActivity extends AppCompatActivity implements Snackable {
private MyViewModel myViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
this.myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
this.myViewModel.setListener(this);
}
#Override
public void showSnackbarMessage(String message) {
Toast.makeText(this, "message", Toast.LENGTH_LONG).show();
}
}
View Model
public class MyViewModel extends AndroidViewModel {
private Snackable listener;
public MyViewModel(#NonNull Application application) {
super(application);
}
public void setListener(MyActivity activity){
this.listener = activity;
}
private void sendSnackbarMessage(String message){
if(listener != null){
listener.showSnackbarMessage(message);
}
}
private void anyFunctionInTheViewModel(){
sendSnackbarMessage("Hey I've got a message for the UI!");
}
}

Interfaces don't retrieve data from Last.fm Api

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

Android Callback method not fills the list

I'm working on an Android Project right now and I'm trying to parse from an URL. In my "ApiClient" I have no problem to parse. Here is my "ApiClient" class:
public class ApiClient implements Callback<Map<String, Channel>> {
static final String BASE_URL = "someURL";
public void start() {
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();
List<Channel> channels = new ArrayList<>(body.values());
}
...
}
I'm trying to get the response into a List from using callback in my "Radio" class. This the place where I'm having the problem. I tried this three too but it didn't solved my problem:
private List<Channel> listChannels = new ArrayList<Channel>();
private List<Channel> listChannels = new ArrayList<>();
private List<Channel> listChannels = new List<>();
Here is my "Radio" class:
public class Radio {
private static final String STORAGE = "radio";
private List<Channel> listChannels;
public static Radio get() {
return new Radio();
}
private SharedPreferences storage;
private Radio() {
storage = App.getInstance().getSharedPreferences(STORAGE, Context.MODE_PRIVATE);
}
public List<Channel> getData() {
RestInterface restInterface = SingletonClass.getService();
restInterface.getChannels().enqueue(new Callback<Map<String, Channel>>() {
#Override
public void onResponse(Call<Map<String, Channel>> call, Response<Map<String, Channel>> response) {
if(response.isSuccessful()){
Map<String, Channel> body = response.body();
List<Channel> channels = new ArrayList<>(body.values());
loadChannels(channels);
}
}
#Override
public void onFailure(Call<Map<String, Channel>> call, Throwable t) {
}
});
System.out.println(listChannels.get(1).getArtist());
return listChannels;
}
public boolean isRated(int itemId) {
return storage.getBoolean(String.valueOf(itemId), false);
}
public void setRated(int itemId, boolean isRated) {
storage.edit().putBoolean(String.valueOf(itemId), isRated).apply();
}
private void loadChannels(List<Channel> channels){
listChannels.clear();
listChannels.addAll(channels);
}
}
Here is my interface class:
public interface RestInterface {
#GET("someURL")
retrofit2.Call<Map<String, Channel>> getChannels();
}
and my SingletonClass:
public class SingletonClass{
private static final Retrofit RETROFIT = new Retrofit.Builder()
.baseUrl(someURL)
.addConverterFactory(GsonConverterFactory.create())
.build();
private static final RestInterface SERVICE = RETROFIT.create(RestInterface.class);
public static RestInterface getService(){
return SERVICE;
}
}
I don't know what should I do to fill the List in my Radio class now. I'm totally open to suggestions. Thanks for the help.
Are you getting an empty list? You're asynchronously setting in the channel data in getData(), so if you're trying to get the data by reading it in the next line, it may not be loaded yet.
This means that when you call System.out.println(listChannels.get(1).getArtist()), you won't see the result of loadChannels, because that call happens right after you call enqueue() while loadChannels() is running on a separate thread. If you moved that into onResponse() you might have more luck.
In Android, a fairly easy way to do things like this and interact with the UI is by using AsyncTask, which for you would look something like this:
private class loadChannelTask extends AsyncTask<Void, Void, List<Channel>> {
protected List<Channel> doInBackground() {
//get response
//pass to load channels
}
protected void onPostExecute() {
System.out.println(listChannels.get(1).getArtist()); //presumably the artist name
}
}

Categories