2

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);
Johans Bormman
  • 855
  • 2
  • 11
  • 23
  • https://codingbat.com/doc/java-if-boolean-logic.html or https://www.tutorialspoint.com/design_pattern/strategy_pattern.htm – Zun Nov 20 '18 at 09:25
  • Can you please be more specific regarding my use-case? Thanks! – Johans Bormman Nov 20 '18 at 09:26
  • What do you mean dynamically use one or the other? Like, having a method that receives for example a `@QueryMap` and you just call it with an arbitrary number of query parameters? – Fred Nov 20 '18 at 09:27
  • You say you dynamically want to switch between either `getMovies()` right? There are multiple ways of doings this, one of them being using a boolean flag. Example: `if (true) { api.getMovies(a,b,c) } else { api.getMovies(a,b) }`. The issue with this is an if-statement mess. This can be solved by implementing a strategy pattern. – Zun Nov 20 '18 at 09:28
  • https://www.jetbrains.com/help/idea/replace-conditional-logic-with-strategy-pattern.html "_When you have a method with lots of conditional logic (i.e., if statements), you're asking for trouble. Conditional logic is notoriously difficult to manage, and may cause you to create an entire state machine inside a single method._" – Zun Nov 20 '18 at 09:29
  • @Fred You're almost right. As you see in my `MainActivity` I'm using those four lines to display the data, but the data that is displayed is from the first query. How can I change those lines to be able to display data that is coming from the second query? By passing a parameter or? Thanks! – Johans Bormman Nov 20 '18 at 09:31
  • @ZUNJAE Ok, I'll use an if statement but how can I control this from the `MainActivity`? Let's say trigger those four lines of code to get the data from the first query and trigger other four lines to get the data from the second query. – Johans Bormman Nov 20 '18 at 09:32
  • `"How can I change those lines to be able to display data that is coming from the second query?"` - what second query do you mean? – pskink Nov 20 '18 at 09:37
  • @pskink I mean, I want to be able to get data from the database using the method with two arguments inseatd of one argument, that is happening right now. – Johans Bormman Nov 20 '18 at 09:43
  • This is the vaguest question I've ever read on StackOverflow. Are you asking me how if-statements work? – Zun Nov 20 '18 at 09:44
  • @ZUNJAE No, I'm asking you how can I call one or the other `getMovies()` method from within the `MainActivity`? – Johans Bormman Nov 20 '18 at 09:44
  • so you have to add a constructor to your `MovieDataSourceFactory` with some `String` parameter and use that value when returning from `create` method – pskink Nov 20 '18 at 11:05
  • @pskink So you basically say that I need to transfer that String from the `MainActivity` to the `MovieDataSource` via three constructors, `MovieViewModel`, `MovieDataSourceFactory` and `MovieDataSource`? – Johans Bormman Nov 20 '18 at 11:16
  • pass it to `MovieDataSourceFactory` constructor where you will store it in some `String` field, and when `create` method is called use it when creating `MovieDataSource` – pskink Nov 20 '18 at 11:30
  • @pskink Thanks, I'll try this. I also have added another [question](https://stackoverflow.com/questions/53392327/how-to-initialize-a-class-and-pass-an-object-to-the-constructor-in-android). Maybe you can take a look. – Johans Bormman Nov 20 '18 at 11:46

1 Answers1

0
boolean globalVariableShouldUseGetMoviesCallWithOnlyOneArgument = true

private void doNetworkCallAndCheckBooleanStatus(){ 
    if (globalVariableShouldUseGetMoviesCallWithOnlyOneArgument) {
        getMovies(thisIsOneArgumentAsYouCanSee);
    } else {
        getMovies(thisIsUsingTwoArguments, asYouCanSee);
    }
}

private void someOtherMethodInTheApp() {
    globalVariableShouldUseGetMoviesCallWithOnlyOneArgument = false
    doNetworkCallAndCheckBooleanStatus()
}
Zun
  • 1,553
  • 3
  • 15
  • 26
  • Thanks for your answer but I it doesn't work. I need this in realtime. Using those 4 lines it is displaying by default the result from the first query. Once I press a button, I want to display the result of the second query, ok? Cand you help me achieve this? – Johans Bormman Nov 20 '18 at 10:45
  • I need the first argument of the `getMovies()` method from the else part to be dynamically. – Johans Bormman Nov 20 '18 at 10:47
  • Do you know what if-statements are? – Zun Nov 20 '18 at 10:50
  • No, this not what I want. Let me explain again. I need that data in real-time. For example, now, in my `MainActivity` I use those 4 lines of code to display data in a `RecyclerView`, which works fine because is calling the method with one argument. Now I want at button click, to send a String to the `api.getMovies("MyStringFromMaiNQActivity", page).enqueue(call);` in order to use the second method. Am I clear now? – Johans Bormman Nov 20 '18 at 10:55
  • Let's see if I understand you correctly. Sometimes you want to call getMovies with 1 argument and on button click 2 arguments, right? – Zun Nov 20 '18 at 10:57
  • What I want. When the app starts, to have the actual behaviour. On button click, I get a literal String and what to use in the second method. In the first one is not necessary. Ok, I'll use an if statement in the `MovieDataSource` class when calling `.enqueue(call)` to know which call to produce but how to send that string in there? Via the orher 3 constructors? – Johans Bormman Nov 20 '18 at 11:01