问题
I have a problem with RecyclerView. I implemented OnScrollListener to it and when user reach end of list it should load a new data depending on index (index 1 loading first 8 index 2 loading second 8 etc) But problem is as soon as adapter start loading new data it scroll me to top :(
This is my code from function where I'm calling server:
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();
}
});
}
This is my adapter:
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);
}
}
}
This is my scrolllsitener
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;
}
}
});
Also if it's meter this funciton is called every time when user scroll to this fragment via this:
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser && !areNewsLoaded) {
listNews = new ArrayList<>();
offset=0;
showlist();
restarting = true;
}
}
回答1:
I tried solutions posted above but none worked. Helpfully I manage to find some fix. Solution is in 3 magic lines :
private Parcelable recyclerViewState;
recyclerViewState = newsList.getLayoutManager().onSaveInstanceState();
newsList.getLayoutManager().onRestoreInstanceState(recyclerViewState);
So basically I added 2. line before adding new content to my list and I guess it remember current position and I added 3. line after adding content so I assume this piece of code remember position
回答2:
Try using notifyDataSetChanged()
instead of notifyItemInserted()
.
A new insert method:
public void insert(News data) {
newslist.add(data);
notifyDataSetChanged();
}
Also i suggest create method to append all news at one time and use addAll method of ArrayList
回答3:
try something like this ,
first you have to create interface
public interface Update{
public void OnDBUpdate();
}
then in Main Activity or somewhere add this
public class MainActivity extends AppCompatActivity implements DialogFragUpdateListener
and create method where you call the Recycler adapter
public void OnDBUpdate() {
dbList =helpher.getDataFromDB();
mAdapter = new RecyclerAdapter(this,dbList);
mRecyclerView.setAdapter(mAdapter);
}
and the last step ,, call the method where you need to update recycler
((Update) getActivity()).OnDBUpdate();
hope this help :)
来源:https://stackoverflow.com/questions/39819346/recyclerview-scrolling-top-when-loading-new-data