简体   繁体   中英

Why RecyclerView items disappear with scrolling

I am using a RecyclerView in my app but when I scroll on my RecyclerView my items will disappear! I used this code for a lot of RecyclerView but this time I don't know what is happening. there is my code for my Activity:

public class ActivityStartup extends AppCompatActivity {

  Toolbar toolbar;
  DrawerLayout drawerLayout;
  NavigationView navigationView;
  RecyclerView menuListRecycler;
  RecyclerView schedualRecycler;

  private List<ReminderModel> tempSchedualArray = new ArrayList<>();

  /**
   * ATTENTION: This was auto-generated to implement the App Indexing API.
   * See https://g.co/AppIndexing/AndroidStudio for more information.
   */
  private GoogleApiClient client;
  LinearLayoutManager mSchedualLayoutManager = new LinearLayoutManager(ActivityStartup.this);
  private FloatingActionButton mAddReminderButton;
  RecyclerView.Adapter mSchedualAdapter;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    toolbar = (Toolbar) findViewById(R.id.toolBar);
    drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
    navigationView = (NavigationView) findViewById(R.id.navigationView);
    menuListRecycler = (RecyclerView) findViewById(R.id.menuList);
    schedualRecycler = (RecyclerView) findViewById(R.id.acitvityStartup_recycler_scheduals);

    //Setting Customized toolbar for application
    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    LinearLayoutManager mEventsLayoutManager = new LinearLayoutManager(ActivityStartup.this);
    menuListRecycler.setLayoutManager(mEventsLayoutManager);
    RecyclerView.Adapter mEventsAdapter = new MenuAdapter(G.menuItems, ActivityStartup.this);
    menuListRecycler.setAdapter(mEventsAdapter);
    mAddReminderButton = (FloatingActionButton) findViewById(R.id.add_reminder);

    //Setting up recyclerView of events
    populateSchedualArray();

    schedualRecycler.setLayoutManager(mSchedualLayoutManager);
    mSchedualAdapter = new SchedualAdapter(populateSchedualArray(), ActivityStartup.this);
    schedualRecycler.setAdapter(mSchedualAdapter);

    // On clicking the floating action button
    mAddReminderButton.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        Intent intent = new Intent(v.getContext(), ReminderAddActivity.class);
        startActivity(intent);
      }
    });

  }

  @Override
  protected void onResume() {
    super.onResume();

    mSchedualAdapter = new SchedualAdapter(populateSchedualArray(), ActivityStartup.this);
    schedualRecycler.setAdapter(mSchedualAdapter);
  }



  private ArrayList<ReminderModel> populateSchedualArray() {

    ArrayList<ReminderModel> schedualArray = new ArrayList<>();

    Database rb = new Database(ActivityStartup.this);
    tempSchedualArray = rb.getAllReminders();

    ArrayList<ReminderModel> monthOne = new ArrayList<>();
    ArrayList<ReminderModel> monthTwo = new ArrayList<>();
    ArrayList<ReminderModel> monthThree = new ArrayList<>();
    ArrayList<ReminderModel> monthFour = new ArrayList<>();
    ArrayList<ReminderModel> monthFive = new ArrayList<>();
    ArrayList<ReminderModel> monthSix = new ArrayList<>();
    ArrayList<ReminderModel> monthSeven = new ArrayList<>();
    ArrayList<ReminderModel> monthEight = new ArrayList<>();
    ArrayList<ReminderModel> monthNine = new ArrayList<>();
    ArrayList<ReminderModel> monthTen = new ArrayList<>();
    ArrayList<ReminderModel> monthEleven = new ArrayList<>();
    ArrayList<ReminderModel> monthTwelve = new ArrayList<>();

    for (ReminderModel rm : tempSchedualArray) {

      String[] split = rm.getDate().split("/");
      switch (split[1]) {
        case "1":
          rm.setDate(convertDateToGregorian(split[2], split[1], split[0]));
          monthOne.add(rm);
          break;
        case "2":
          rm.setDate(convertDateToGregorian(split[2], split[1], split[0]));
          monthTwo.add(rm);
          break;
        case "3":
          rm.setDate(convertDateToGregorian(split[2], split[1], split[0]));
          monthThree.add(rm);
          break;
        case "4":
          rm.setDate(convertDateToGregorian(split[2], split[1], split[0]));
          monthFour.add(rm);
          break;
        case "5":
          rm.setDate(convertDateToGregorian(split[2], split[1], split[0]));
          monthFive.add(rm);
          break;
        case "6":
          rm.setDate(convertDateToGregorian(split[2], split[1], split[0]));
          monthSix.add(rm);
          break;
        case "7":
          rm.setDate(convertDateToGregorian(split[2], split[1], split[0]));
          monthSeven.add(rm);
          break;
        case "8":
          rm.setDate(convertDateToGregorian(split[2], split[1], split[0]));
          monthEight.add(rm);
          break;
        case "9":
          rm.setDate(convertDateToGregorian(split[2], split[1], split[0]));
          monthNine.add(rm);
          break;
        case "10":
          rm.setDate(convertDateToGregorian(split[2], split[1], split[0]));
          monthTen.add(rm);
          break;
        case "11":
          rm.setDate(convertDateToGregorian(split[2], split[1], split[0]));
          monthEleven.add(rm);
          break;
        case "12":
          rm.setDate(convertDateToGregorian(split[2], split[1], split[0]));
          monthTwelve.add(rm);
          break;
      }


    }

    schedualArray.add(new ReminderModel(100000001, "start_spring", "", "", "", "", "", ""));
    schedualArray.addAll(monthOne);
    schedualArray.addAll(monthTwo);
    schedualArray.addAll(monthThree);
    schedualArray.add(new ReminderModel(100000004, "start_summer", "", "", "", "", "", ""));
    schedualArray.addAll(monthFour);
    schedualArray.addAll(monthFive);
    schedualArray.addAll(monthSix);
    schedualArray.add(new ReminderModel(100000007, "start_fall", "", "", "", "", "", ""));
    schedualArray.addAll(monthSeven);
    schedualArray.addAll(monthEight);
    schedualArray.addAll(monthNine);
    schedualArray.add(new ReminderModel(1000000010, "start_winter", "", "", "", "", "", ""));
    schedualArray.addAll(monthTen);
    schedualArray.addAll(monthEleven);
    schedualArray.addAll(monthTwelve);

    return schedualArray;
  }

  private String convertDateToGregorian(String year, String month, String day) {

    CalendarTool calendarTool = new CalendarTool();
    calendarTool.setIranianDate(Integer.parseInt(year), Integer.parseInt(month), Integer.parseInt(day));

    return calendarTool.getGregorianYear() + "/" + calendarTool.getGregorianMonth() + "/" + calendarTool.getGregorianDay();
  }


  @Override
  public boolean onCreateOptionsMenu(Menu menu) {

    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {

    int id = item.getItemId();

    if (id == android.R.id.home) {
      Toast.makeText(this, "دکمه خانه کلیک شد !", Toast.LENGTH_SHORT).show();
    }
    if (id == R.id.action_settings) {
      drawerLayout.openDrawer(Gravity.RIGHT);
      return true;
    }
    return super.onOptionsItemSelected(item);
  }

  /**
   * ATTENTION: This was auto-generated to implement the App Indexing API.
   * See https://g.co/AppIndexing/AndroidStudio for more information.
   */
  public Action getIndexApiAction() {
    Thing object = new Thing.Builder()
      .setName("Main Page") // TODO: Define a title for the content shown.
      // TODO: Make sure this auto-generated URL is correct.
      .setUrl(Uri.parse("http://[ENTER-YOUR-URL-HERE]"))
      .build();
    return new Action.Builder(Action.TYPE_VIEW)
      .setObject(object)
      .setActionStatus(Action.STATUS_TYPE_COMPLETED)
      .build();
  }

  @Override
  public void onStart() {
    super.onStart();
  }

  @Override
  public void onStop() {
    super.onStop();
  }


}

I had the same issue ( https://github.com/square/picasso/issues/845 ) but in github found this and worked for me. Thaks to @raj9686

rv.getRecycledViewPool().setMaxRecycledViews(0, 0);

For using muntiple views in a recyclerView it is not appropriate to set VISIBLE or GONE for them and the best way is to use multiple viewHolder for recyclerView something like this:

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;

import free.calendar.app.codenevisha.com.hamrahcalendar.R;
import model.ReminderModel;
import utils.G;

import static utils.G.SEASON_WINTER;


public class SchedualAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

  private ArrayList<ReminderModel> items;
  private Context mContext;


  public SchedualAdapter(ArrayList<ReminderModel> items, Context mContext) {
    this.items = items;
    this.mContext = mContext;
  }

  public static class ViewHolderDefault extends RecyclerView.ViewHolder {

    TextView txt_eventTitle;
    TextView txt_dateNumber;
    TextView txt_dateName;

    public ViewHolderDefault(View v) {
      super(v);

      txt_eventTitle = (TextView) v.findViewById(R.id.txt_eventTitle);
      txt_dateName = (TextView) v.findViewById(R.id.txt_dateName);
      txt_dateNumber = (TextView) v.findViewById(R.id.txt_dateNumber);

    }
  }

  public static class ViewHolderSeason extends RecyclerView.ViewHolder {

    ImageView img_monthPic;

    public ViewHolderSeason(View v) {
      super(v);
      img_monthPic = (ImageView) v.findViewById(R.id.img_monthPic);
    }
  }

  @Override
  public int getItemViewType(int position) {

    /*
    * 0 default
    * 1 spring
    * 2 Summer
    * 3 fall
    * 4 winter
    */

    int state;
    String title = G.COMMON_DAY;
    if (items.get(position).getTitle().equals(G.SEASON_SPRING)) {
      return 1;
    } else if (items.get(position).getTitle().equals(G.SEASON_SUMMER)) {
      return 2;
    } else if (items.get(position).getTitle().equals(G.SEASON_FALL)) {
      return 3;
    } else if (items.get(position).getTitle().equals(SEASON_WINTER)) {
      return 4;
    }
    return 0;
  }

  @Override
  public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    // Create a new View
    final View v1 = LayoutInflater.from(mContext).inflate(R.layout.schedual_recycler_default_viewgroup, parent, false);

    final View v2 = LayoutInflater.from(mContext).inflate(R.layout.schedual_recycler_seasion_viewgroup, parent, false);


    if (viewType == 0) {
      return new ViewHolderDefault(v1);
    } else {
      return new ViewHolderSeason(v2);
    }
  }

  @Override
  public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {


    switch (holder.getItemViewType()) {
      case 0:
        ViewHolderDefault viewHolderDefault = (ViewHolderDefault) holder;
        viewHolderDefault.txt_dateNumber.setText(items.get(position).getDate());
        viewHolderDefault.txt_dateNumber.setText(items.get(position).getDate());
        break;

      case 1:
        ViewHolderSeason viewHolderSeason1 = (ViewHolderSeason) holder;
        viewHolderSeason1.img_monthPic.setImageResource(R.drawable.spring);
        break;

      case 2:
        ViewHolderSeason viewHolderSeason2 = (ViewHolderSeason) holder;
        viewHolderSeason2.img_monthPic.setImageResource(R.drawable.summer);
        break;

      case 3:
        ViewHolderSeason viewHolderSeason3 = (ViewHolderSeason) holder;
        viewHolderSeason3.img_monthPic.setImageResource(R.drawable.fall);
        break;

      case 4:
        ViewHolderSeason viewHolderSeason4 = (ViewHolderSeason) holder;
        viewHolderSeason4.img_monthPic.setImageResource(R.drawable.winter);
        break;
    }
  }


  @Override
  public int getItemCount() {
    return items.size();
  }
}

Like the name implies, the recycler view reuses views types from existing items on the same type that have been drawn already in places that it to avoid drawing new ones which is resource intensive.

That being said this line here is your culprit holder.layoutTop.setVisibility(View.VISIBLE); Rather than use an if-else in onBindViewHolder explore the use of viewtypes . That is the correct way to implement different layouts in on recycler view items. This stackoverflow question should provide some insight How to create RecyclerView with multiple view type?

Instead of using simple position (which is actually adapterPosition AFAIK) you should try using getAdapterPosition/getLayoutPosition. Read about difference between them. This might help. If it not you cat try to use different ViewTypes of items. Good luck

检查回收站项目的布局

android:layout_height="wrap_content"

To hide certain views with multiple items, it is better to hide the base layout by,

1. Give an id to the base layout of the view in XML. 
2. Define the view inside your "RecyclerViewAdapter class"
LinearLayout mItems_timelineId;
mItems_timelineId = itemView.findViewById(R.id.items_timelineId);
3. Then remove the view wherever you wish to by,
mItems_timelineId.removeAllViews();

This is worked for me. Thank you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM