Реализация бесконечной прокрутки с помощью ViewModel и Retrofit в утилите - PullRequest
0 голосов
/ 23 октября 2018

Перед добавлением viewmodel & aliveata я успешно реализовал бесконечную прокрутку с модернизацией.Но после добавления viewmodel & aliveata с помощью Retrofit My не может обновить recyclerview новым вызовом данных, или наблюдатель viewmodel не обновляет список.

Я просто хочу бесконечной прокрутки, как мой код раньше.Я добавляю глобальную переменную для повторного использования токена следующей страницы.Потеряю ли я что-нибудь или какой-либо образец для реализации бесконечного повторного просмотра с помощью viewmodel & retrofit, это будет здорово.

public static String NEXT_PAGE_URL = null;

Я закодировал вот так.

Моя активность -> PlaceListActivity

placeRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            LogMe.d(tag, "onScrollStateChanged:: " + "called");
            // check scrolling started or not
            if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
                isScrolling = true;
            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            LogMe.d(tag, "onScrolled:: " + "called");
            super.onScrolled(recyclerView, dx, dy);

            currentItem = layoutManager.getChildCount();
            totalItems = layoutManager.getItemCount();
            scrolledOutItems = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();

            LogMe.d(tag, "currentItem:: " + currentItem);
            LogMe.d(tag, "totalItems:: " + totalItems);
            LogMe.d(tag, "scrolledOutItems:: " + scrolledOutItems);

            if (isScrolling && (currentItem + scrolledOutItems == totalItems)) {
                LogMe.d(tag, "view:: " + "finished");
                isScrolling = false;
                if (ApplicationData.NEXT_PAGE_URL != null) {
                    LogMe.d(tag, "place adding:: " + " onScrolled called");
                    ll_loading_more.setVisibility(View.VISIBLE);

                    // todo: call web api here
                    callDataFromLocationAPi(type, ApplicationData.NEXT_PAGE_URL, currentLatLng);

                } else {
                    LogMe.d(tag, "next_page_url:: " + " is null");
                }


            }
        }
    });

private void callDataFromLocationAPi(String type, String next_page_url, LatLng latLng) {

    if (Connectivity.isConnected(activity)) {
        showProgressDialog();
        model.getNearestPlaces(type, next_page_url, latLng).
                observe(activity, new Observer<List<PlaceDetails>>() {
                    @Override
                    public void onChanged(@Nullable List<PlaceDetails> placeDetails) {

                        ll_loading_more.setVisibility(View.GONE);

                        LogMe.i(tag, "callDataFromLocationAPi: onChanged called !");

                        hideProgressDialog();
                        if (placeDetails != null) {
                            placeDetailsList = placeDetails;
                            placeListAdapter.setPlaceList(placeDetails);
                        }

                    }
                });
    } else {
        showAlertForInternet(activity);
    }

}

В PlaceViewModel

    public class PlaceViewModel extends AndroidViewModel {

    //this is the data that we will fetch asynchronously
    private MutableLiveData<List<PlaceDetails>> placeList;
    private PlaceRepository placeRepository;
    private String tag = getClass().getName();


    public PlaceViewModel(Application application) {

        super(application);
        placeRepository = new PlaceRepository(application);
    }


    //we will call this method to get the data
    public MutableLiveData<List<PlaceDetails>> getNearestPlaces(String type,
                                                         String next_page_token,
                                                         LatLng latLng) {
        //if the list is null
        if (placeList == null) {
            placeList = new MutableLiveData<>();

            //we will load it asynchronously from server in this method
            //loadPlaces(type, next_page_token, latLng);

            placeList = placeRepository.getNearestPlacesFromAPI(type, next_page_token, latLng);
        }

        //finally we will return the list
        return placeList;
    }
}

В моем PlaceRepository.java выглядит

    public class PlaceRepository {

    private static final Migration MIGRATION_1_2 = new Migration(1, 2) {
        @Override
        public void migrate(SupportSQLiteDatabase database) {
            // Since we didn't alter the table, there's nothing else to do here.
        }
    };
    private PlaceDatabase placeDatabase;
    private CurrentLocation currentLocation = null;
    private String tag = getClass().getName();
    //this is the data that we will fetch asynchronously
    private MutableLiveData<List<PlaceDetails>> placeList;


    public PlaceRepository(Context context) {
        placeDatabase = PlaceDatabase.getDatabase(context);
        //addMigrations(MIGRATION_1_2)
        placeList =
                new MutableLiveData<>();
    }


    public MutableLiveData<List<PlaceDetails>> getNearestPlacesFromAPI(String type, final String next_page_token, LatLng latLng) {

        List<PlaceDetails> placeDetailsList = new ArrayList<>();

        try {


            ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
            Call<Example> call = apiService.getNearbyPlaces(type,
                    latLng.latitude + "," +
                            latLng.longitude, ApplicationData.PROXIMITY_RADIUS,
                    ApplicationData.PLACE_API_KEY, next_page_token);

            call.enqueue(new Callback<Example>() {
                @Override
                public void onResponse(Call<Example> call, Response<Example> response) {

                    try {

                        Example example = response.body();

                        ApplicationData.NEXT_PAGE_URL = example.getNextPageToken();
                        //     next_page_url = example.getNextPageToken();
                        LogMe.i(tag, "next_page_url:" + ApplicationData.NEXT_PAGE_URL);

                        if (example.getStatus().equals("OK")) {

                            LogMe.i("getNearbyPlaces::", " --- " + response.toString() +
                                    response.message() + response.body().toString());

                            // This loop will go through all the results and add marker on each location.
                            for (int i = 0; i < example.getResults().size(); i++) {
                                Double lat = example.getResults().get(i).getGeometry().getLocation().getLat();
                                Double lng = example.getResults().get(i).getGeometry().getLocation().getLng();

                                String placeName = example.getResults().get(i).getName();
                                String vicinity = example.getResults().get(i).getVicinity();
                                String icon = example.getResults().get(i).getIcon();
                                String place_id = example.getResults().get(i).getPlaceId();

                                PlaceDetails placeDetails = new PlaceDetails();

                                if (example.getResults().get(i).getRating() != null) {
                                    Double rating = example.getResults().get(i).getRating();
                                    placeDetails.setRating(rating);
                                }

                                //List<Photo> photoReference = example.getResults().
                                //       get(i).getPhotos();
                                placeDetails.setName(placeName);
                                placeDetails.setAddress(vicinity);
                                placeDetails.setLatitude(lat);
                                placeDetails.setLongitude(lng);
                                placeDetails.setIcon(icon);
                                placeDetails.setPlace_id(place_id);
                                //placeDetails.setPlace_type(place_type_title);

                                double value = ApplicationData.
                                        DISTANCE_OF_TWO_LOCATION_IN_KM(latLng.latitude, latLng.longitude, lat, lng);

                                //new DecimalFormat("##.##").format(value);

                                placeDetails.setDistance(new DecimalFormat("##.##").format(value));

                                String ph = "";
                                if (example.getResults().
                                        get(i).getPhotos() != null) {

                                    try {
                                        List<Photo> photos = example.getResults().
                                                get(i).getPhotos();

                                        //JSONArray array = new JSONArray(example.getResults().
                                        //get(i).getPhotos());
                                        //JSONObject jsonObj = new JSONObject(array.toString());

                                        //ph = jsonObj.getString("photo_reference");
                                        ph = photos.get(0).getPhotoReference();
                                        //LogMe.i(tag, "\n" + ph);

                                    } catch (Exception e) {
                                        e.printStackTrace();
                                        //placeDetails.setPicture_reference(ph);
                                        //PLACE_DETAILS_LIST.add(placeDetails);

                                        //LogMe.i(tag, "@@@@ Exception Occureed @@@@");

                                        ph = "";
                                        //continue;
                                    }
                                }

                                placeDetails.setPicture_reference(ph);
                                placeDetailsList.add(placeDetails);
                                placeList.postValue(placeDetailsList);

                            }


                        } else {


                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }


                }

                @Override
                public void onFailure(Call<Example> call, Throwable t) {

                    Log.e("onFailure", t.toString());

                }
            });


        } catch (RuntimeException e) {
            //hideProgressDialog();
            Log.d("onResponse", "RuntimeException is an error");
            e.printStackTrace();

        } catch (Exception e) {

            Log.d("onResponse", "Exception is an error");
        }

        return placeList;

    }
}

Я точный код из-за простоты вопроса.

1 Ответ

0 голосов
/ 24 октября 2018

Хотя вы уже используете android-jetpack, взгляните на Библиотека подкачки .Он специально разработан для построения бесконечных списков с использованием RecyclerView.

Исходя из вашего исходного кода, я бы сказал, что вам нужно PageKeyedDataSource , вот несколько примеров, которые включают информацию о том, как реализоватьPageKeyedDataSource - 7 шагов по реализации библиотеки подкачки в Android

Если говорить о минусах этого подхода:

  • Вам больше не нужночтобы наблюдать за прокруткой списка (библиотека делает это за вас), вам просто нужно указать размер страницы следующим образом:

    PagedList.Config myPagingConfig = new PagedList.Config.Builder()
            .setPageSize(50)
            .build(); 
    

    Из документации:

    Размер страницы:количество элементов на каждой странице.

  • Ваш код будет более понятным, вы избавитесь от своих RecyclerView.OnScrollListener

  • Код ViewModel будет короче, он будет предоставлять только PagedList:

    @NonNull
    LiveData<PagedList<ReviewSection>> getReviewsLiveData() {
        return reviewsLiveData;
    }
    
...