RecyclerView onScrolled 方法总是或从不调用

Posted

技术标签:

【中文标题】RecyclerView onScrolled 方法总是或从不调用【英文标题】:RecyclerView onScrolled method always or never called 【发布时间】:2020-09-25 13:16:50 【问题描述】:

背景: 我通过添加 addOnScrollListener 函数使用 RecyclerView 实现分页逻辑。我正在使用 MVVM 模式 (https://developer.android.com/jetpack/docs/guide)。我的目标是使用 GridLayoutManager 在 GridLayout 中显示通过 API 调用 TheMovieDB 产生的电影。

面临的问题: 滚动方法总是或从不被调用:

1) 我什至不需要滚动来触发它。

2)当我启动应用程序时它会触发,但是当我滚动它时它根本不会触发

这是我的代码

public void getMoviesLL(String categoria, int pagina, MutableLiveData < Resource < List < Movie >>> moviesData) 
    Service apiService = Client.getClient().create(Service.class);
    Call < MoviesResponse > call;

    Log.d(TAG, "CHIAMATA " + pagina);
    call = apiService.getTMDB(categoria, Constants.API_KEY, Constants.LINGUA, pagina);

    call.enqueue(new Callback < MoviesResponse > () 

        @Override
        public void onResponse(@NonNull Call < MoviesResponse > call, @NonNull Response < MoviesResponse > response) 
            if (response.isSuccessful() && response.body() != null) 

                Resource < List < Movie >> resource = new Resource < >();

                if (moviesData.getValue() != null && moviesData.getValue().getData() != null) 
                    List < Movie > currentMovieList = moviesData.getValue().getData();

                    currentMovieList.remove(currentMovieList.size() - 1);
                    currentMovieList.addAll(response.body().getResults());
                    resource.setData(currentMovieList);
                 else 
                    resource.setData(response.body().getResults());
                

                resource.setTotalResults(response.body().getTotalResults());
                resource.setStatusCode(response.code());
                resource.setStatusMessage(response.message());
                resource.setLoading(false);
                Log.d(TAG, "LOADING FALSE");
                moviesData.postValue(resource);
             else if (response.errorBody() != null) 
                Resource < List < Movie >> resource = new Resource < >();
                resource.setStatusCode(response.code());
                try 
                    resource.setStatusMessage(response.errorBody().string() + "- " + response.message());
                 catch(IOException e) 
                    e.printStackTrace();
                
                moviesData.postValue(resource);
            
        

        @Override
        public void onFailure(@NonNull Call < MoviesResponse > call, @NonNull Throwable t) 
            Resource < List < Movie >> resource = new Resource < >();
            resource.setStatusMessage(t.getMessage());
            moviesData.postValue(resource);
        
    );


这是模型

 public class Resource<T> 
        private T data;
        private int totalResults;
        private int statusCode;
        private String statusMessage;
        private boolean isLoading;

        public Resource() 

        public Resource(T data, int totalResults, int statusCode, String statusMessage, boolean isLoading) 
            this.data = data;
            this.totalResults = totalResults;
            this.statusCode = statusCode;
            this.statusMessage = statusMessage;
            this.isLoading = isLoading;
        

        public T getData() 
            return data;
        

        public void setData(T data) 
            this.data = data;
        

        public int getTotalResults() 
            return totalResults;
        

        public void setTotalResults(int totalResults) 
            this.totalResults = totalResults;
        

        public int getStatusCode() 
            return statusCode;
        

        public void setStatusCode(int statusCode) 
            this.statusCode = statusCode;
        

        public String getStatusMessage() 
            return statusMessage;
        

        public void setStatusMessage(String statusMessage) 
            this.statusMessage = statusMessage;
        

        public boolean isLoading() 
            return isLoading;
        

        public void setLoading(boolean loading) 
            isLoading = loading;
        

        @Override
        public String toString() 
            return "Resource" +
                    "data=" + data +
                    ", totalResults=" + totalResults +
                    ", statusCode=" + statusCode +
                    ", statusMessage='" + statusMessage + '\'' +
                    ", isLoading=" + isLoading +
                    '';
        
     

查看模型类

public class NuoviArriviViewModel extends ViewModel 
        private static final String TAG = "NuoviArriviViewModel";
        private MutableLiveData<Resource<List<Movie>>> film;
        int page = 1;
        private int currentResults;
        private boolean isLoading = false;

        public MutableLiveData<Resource<List<Movie>>> getProssimeUscite() 
            if(film == null) 
                film = new MutableLiveData<>();
                MoviesRepository.getInstance().getMoviesLL("now_playing", page, film);
            
            return film;
        

        public MutableLiveData<Resource<List<Movie>>> getMoreProssimeUscite() 
            MoviesRepository.getInstance().getMoviesLL("now_playing", page, film);
            return film;
        

        public MutableLiveData<Resource<List<Movie>>> getMoviesLiveData() 
            return film;
        

        public int getPage() 
            return page;
        

        public void setPage(int page) 
            this.page = page;
        

        public int getCurrentResults() 
            return currentResults;
        

        public void setCurrentResults(int currentResults) 
            this.currentResults = currentResults;
        

        public boolean isLoading() 
            return isLoading;
        

        public void setLoading(boolean loading) 
            isLoading = loading;
        
    

OnScroll 监听器

prossimeUsciteRV.addOnScrollListener(new RecyclerView.OnScrollListener() 

    @Override
    public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) 
        super.onScrolled(recyclerView, dx, dy);

        Log.d(TAG, "entro in onScrolled");

        totalItemCount = layoutManager.getItemCount();
        lastVisibleItem = layoutManager.findLastVisibleItemPosition();
        visibleItemCount = layoutManager.getChildCount();

        // Condition to enable the loading of other news while the user scrolls the list
        if (totalItemCount == visibleItemCount || (totalItemCount <= (lastVisibleItem + threshold) && dy > 0 && !nuoviArriviViewModel.isLoading()) && nuoviArriviViewModel.getMoviesLiveData().getValue() != null && nuoviArriviViewModel.getCurrentResults() != nuoviArriviViewModel.getMoviesLiveData().getValue().getTotalResults()) 
            Resource < List < Movie >> movieListResource = new Resource < >();

            MutableLiveData < Resource < List < Movie >>> movieListMutableLiveData = nuoviArriviViewModel.getMoviesLiveData();

            if (movieListMutableLiveData.getValue() != null) 

                nuoviArriviViewModel.setLoading(true);

                List < Movie > currentMovieList = movieListMutableLiveData.getValue().getData();

                // It adds a null element to enable the visualization of the loading item (it is managed by the class nuoviArriviAdapter)
                currentMovieList.add(null);
                movieListResource.setData(currentMovieList);
                movieListResource.setStatusMessage(movieListMutableLiveData.getValue().getStatusMessage());
                movieListResource.setTotalResults(movieListMutableLiveData.getValue().getTotalResults());
                movieListResource.setStatusCode(movieListMutableLiveData.getValue().getStatusCode());
                movieListResource.setLoading(true);
                movieListMutableLiveData.postValue(movieListResource);

                int page = nuoviArriviViewModel.getPage() + 1;
                nuoviArriviViewModel.setPage(page);

                nuoviArriviViewModel.loadMore();
            
        
    
);

XML 文件

 <?xml version="1.0" encoding="utf-8"?>

        <GridLayout
            android:layout_
            xmlns:tools="http://schemas.android.com/tools"
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/nuovi_arrivi_fragment"
            android:layout_
            android:background="@color/colorPrimary"
            android:orientation="vertical"
            tools:context=".ui.nuovi_arrivi.NuoviArriviFragment">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recycler_view_nuovi_arrivi"
                android:layout_
                android:layout_
                android:orientation="vertical" />

        </GridLayout>

【问题讨论】:

【参考方案1】:

问题是我将布局包裹在 NestedScrollView 中,因此无法正确触发 onScrolled 事件

【讨论】:

以上是关于RecyclerView onScrolled 方法总是或从不调用的主要内容,如果未能解决你的问题,请参考以下文章

在 RecyclerView/ListView onScroll 上隐藏 ActionBar

Android Recyclerview 监听滑动状态和滑动距离

Android Recyclerview 监听滑动状态和滑动距离

如何监听RecyclerView划到最后一条数据

获取 RecyclerView 中的可见项目

获取 RecyclerView 中的可见项目