加载新数据时RecyclerView滚动顶部

Posted

技术标签:

【中文标题】加载新数据时RecyclerView滚动顶部【英文标题】:RecyclerView scrolling top when loading new data 【发布时间】:2017-02-10 16:11:12 【问题描述】:

我对 RecyclerView 有疑问。我对其实现了 OnScrollListener ,当用户到达列表末尾时,它应该根据索引加载新数据(索引 1 加载第一个 8 索引 2 加载第二个 8 等)但问题是一旦适配器开始加载新数据,它就会将我滚动到顶部:(

这是我调用服务器的函数中的代码:

  public void showlist() 
    progressBar = new ProgressDialog(getActivity());
    progressBar.setMessage("Please wait ...");
    progressBar.show();
    NetworkSDK.getInstance().getNews(size, offset, new Callback<List<News>>() 
        @Override
        public void onResponse(Call<List<News>> call, Response<List<News>> response) 
            if (response.code() == 401) 
                Intent intent = new Intent(getContext(), MainPreLogin.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
                progressBar.dismiss();
                startActivity(intent);
                SharedData.getInstance().removeString("token");


            
            if (response.isSuccess()) 
                newsAdapter = new NewsAdapterRecycler(listNews);

                if (response.body().size() == 0) 
                    progressBar.dismiss();
                    Toast.makeText(getActivity(), R.string.noMorenews, Toast.LENGTH_SHORT).show();



                 else 
                    for (int i = 0; i < response.body().size(); i++) 
                        newsAdapter.insert(newsAdapter.getItemCount() + 1, response.body().get(i));
                    
                    newsList.setAdapter(newsAdapter);
                    newsAdapter.notifyDataSetChanged();
                    progressBar.dismiss();



                

            
        

        @Override
        public void onFailure(Call<List<ba.project.models.News>> call, Throwable t) 
            Toast.makeText(getContext(), R.string.errorNoconnection, Toast.LENGTH_LONG).show();
            progressBar.dismiss();


        
    );


这是我的适配器:

public class NewsAdapterRecycler extends RecyclerView.Adapter<NewsAdapterRecycler.MyViewHolder> 

private static int selectedItem = -1;
ArrayList<News> newslist;
Context context;

public NewsAdapterRecycler(ArrayList<News> newslist) 

    this.newslist = newslist;



@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) 
    context = parent.getContext();
    View itemView = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.single_news_layout, parent, false);
    return new MyViewHolder(itemView);


@Override

public void onBindViewHolder(MyViewHolder holder, int position) 
    View view = null;
    Log.d("Pozicija News",String.valueOf(position));
    News news = newslist.get(position);
    holder.shortText.setText(news.getIntro());
    holder.name.setText(news.getSubject());
    if (news.getImagePath().equals(""))
        Picasso.with(context).load(R.drawable.logo_Def).fit().centerCrop().into(holder.picture);
    else
        Picasso.with(context).load(news.getImagePath()).fit().centerCrop().into(holder.picture);



    holder.date.setText(news.getShortDate());

    if (selectedItem == position)
        holder.itemView.setSelected(true);



@Override
public int getItemCount() 
    return newslist.size();



public void insert(int position, News data) 
    newslist.add(position - 1, data);
    notifyItemInserted(position);


public class MyViewHolder extends RecyclerView.ViewHolder 
    TextView name;
    TextView shortText;
    TextView date;
    ImageView picture;

    public MyViewHolder(View view) 
        super(view);
        this.name=(TextView)view.findViewById(R.id.news_title);
        this.shortText=(TextView)view.findViewById(R.id.news_desc);
        this.picture=(ImageView)view.findViewById(R.id.news_image);
        this.date=(TextView)view.findViewById(R.id.news_date);
    

这是我的滚动站点

  newsList.addOnScrollListener(new RecyclerView.OnScrollListener() 

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) 
            super.onScrolled(recyclerView, dx, dy);
            visibleItemCount = newsList.getChildCount();
            totalItemCount = mLayoutManager.getItemCount();
            firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
            Log.d("Visibleitem", String.valueOf(visibleItemCount));
            Log.d("totalItem", String.valueOf(totalItemCount));
            Log.d("firstvisibleitem", String.valueOf(firstVisibleItem));
            if (restarting) 
                previousTotal = 0;
                visibleThreshold = 5;

            
            if (loading) 
                if (totalItemCount > previousTotal) 
                    loading = false;

                    previousTotal = totalItemCount;
                
            
            if (!loading && (totalItemCount - visibleItemCount)
                    <= (firstVisibleItem + visibleThreshold)) 
                offset++;
                showlist();
                // Do something

                loading = true;
                restarting = false;
            
        
    );

此外,如果是仪表,则每次用户通过以下方式滚动到此片段时都会调用此函数:

  @Override
public void setUserVisibleHint(boolean isVisibleToUser) 
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser && !areNewsLoaded) 
        listNews = new ArrayList<>();
        offset=0;
        showlist();
        restarting = true;



    


【问题讨论】:

我猜你不需要重新设置适配器到列表,当响应成功时插入新数据然后通知适配器 【参考方案1】:

我尝试了上面发布的解决方案,但没有一个奏效。有帮助的是,我设法找到了一些解决方法。解决方案是 3 条魔法线:

 private Parcelable recyclerViewState; 
 recyclerViewState = newsList.getLayoutManager().onSaveInstanceState();
 newsList.getLayoutManager().onRestoreInstanceState(recyclerViewState);

所以基本上我在将新内容添加到列表之前添加了 2. 行,我想它会记住当前位置,我在添加内容之后添加了 3. 行,所以我假设这段代码记住位置

【讨论】:

【参考方案2】:

尝试使用notifyDataSetChanged() 而不是notifyItemInserted()

一种新的插入方法:

public void insert(News data) 
    newslist.add(data);
    notifyDataSetChanged();

另外我建议创建方法来一次性追加所有新闻并使用 ArrayList 的 addAll 方法

【讨论】:

【参考方案3】:

试试这样的,

首先你要创建接口

public interface Update
public void OnDBUpdate();
 

然后在 Main Activity 或其他地方添加这个

public class MainActivity extends AppCompatActivity implements  DialogFragUpdateListener

并创建调用 Recycler 适配器的方法

 public void OnDBUpdate() 
        dbList =helpher.getDataFromDB();
        mAdapter = new RecyclerAdapter(this,dbList);
        mRecyclerView.setAdapter(mAdapter);
    

最后一步,调用需要更新recycler的方法

        ((Update) getActivity()).OnDBUpdate();

希望得到帮助:)

【讨论】:

以上是关于加载新数据时RecyclerView滚动顶部的主要内容,如果未能解决你的问题,请参考以下文章

RecyclerView - 如何平滑滚动到嵌套滚动视图内某个位置的项目顶部?

RecyclerView 和 SwipeRefreshLayout

如何将 DiffUtil.Callback 与具有页眉和页脚的 RecyclerView 一起使用?

是否有可能当recyclerview加载项只加载一次而不重新加载滚动?

如何使用 JSON API 在滚动时在 recyclerview 中加载更多数据

RecyclerView clipToPadding = false