Когато приложението е преместено на заден план и създадено отново, RecyclerView не възстановява състоянието на LayoutManager

Първоначално следвах приетия отговор в този по-рано публикуван въпрос относно това как да спестявам и възстановете мениджъра на оформлението за RecyclerView.

Имам своя RecyclerView в Дейност Б. [Забележка: Дейност А ще стартира Дейност Б, прехвърляйки данни чрез намерение.]

Когато потребител щракне върху Viewholder в Дейност B, Дейност C се стартира. След като Дейност C бъде затворена и унищожена, Дейност B е видима и мога да видя всичките си данни възстановени в RecyclerView.

Проблемът: Въпреки това, ако навигирам далеч от моето приложение (т.е. натискам клавиша Home), то се измества на заден план. Когато приложението ми бъде възстановено, onCreate() се извиква отново. Състоянието на LayoutManager се запазва, но нито една от данните ми не се показва в RecyclerView.

Мога да кажа, че моето състояние на LayoutManager е запазено след известно отстраняване на грешки. Показва се така, когато onCreate() се извика отново след възстановяване на приложението от заден план:

Saved Instance State = Bundle[{ActivityB - Linear Layout State=android.support.v7.widget.LinearLayoutManager$SavedState@6358f8f, android:viewHierarchyState=Bundle[mParcelledData.dataSize=1296]}]

Не съм сигурен как да поправя това след часове опити.

Моят код:

public class ActivityB extends AppCompatActivity {

      private RecyclerView recyclerView;
      private LinearLayoutManager linearLayoutManager;
      private Parcelable linearLayoutState;
      private RecyclerAdapter adapter;
      private Button more;
      private String id;
      private List<VideoItem> list;
      private List<VideoItem> newList;
      private final String LINEARLAYOUT_STATE_KEY = "Activity B - Linear Layout State";

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

             // Retrieving data from Activity A
             Intent intent = getIntent();
             Bundle bundle = intent.getBundleExtra("bundle");
             someClass.innerClass class = bundle.getParcelable("data");
             id = class.getID();
             list = class.getList();
             newList = new ArrayList<>();

             // Instantiating Recycler View
             recyclerView = (RecyclerView)findViewById(R.id.activityb_recyclerview);
             recyclerView.setNestedScrollingEnabled(false);

             linearLayoutManager = new LinearLayoutManager(context);
             recyclerView.setLayoutManager(linearLayoutManager);

             adapter = new RecyclerAdapter();
             recyclerView.setAdapter(adapter);

             moreButton = (Button)findViewById(R.id.activityb_more);
             moreButton.setOnClickListener(new fetchMoreClickListener());
        }

        @Override
        public void onResume(){
              if (linearLayoutState != null) {
                 linearLayoutManager.onRestoreInstanceState(linearLayoutState);
              } else {
                 // If no layout state is found, I need to populate my
                 // adapter.
                 // Here I am simply cloning my list again, to keep the original
                 // list intact. generateSubset() removes items from the cloned list 
                 // to create a smaller subset that is added to the adapter.
                 for (ListItem item : list){
                        newList.add(new ListItemi(item));
                 }
                 adapter.addItems(generateSubset(0));
              }
              super.onResume();
        }

        @Override
        protected void onSaveInstanceState(Bundle outState) {
               linearLayoutState = linearLayoutManager.onSaveInstanceState();
               outState.putParcelable(LINEARLAYOUT_STATE_KEY, linearLayoutState);
               super.onSaveInstanceState(outState);
        }

        @Override
        protected void onRestoreInstanceState(Bundle savedInstanceState) {
               super.onRestoreInstanceState(savedInstanceState);
               linearLayoutState = savedInstanceState.getParcelable(LINEARLAYOUT_STATE_KEY);
        }

Другите методи на жизнения цикъл на дейността не са отменени. Не получавам никакви съобщения за грешка. Само моите данни, съхранявани в моите Viewholders, вече не се показват в RecyclerView.

Редактиране 1:

Ето моя код на RecyclerAdapter:

публичен клас RecyclerAdapter разширява RecyclerView.Adapter{ private static Дата сега; частен списък списък;

public static class ItemHolder extends RecyclerView.ViewHolder
        implements View.OnClickListener {

    private Context context;
    private String key;
    private Bundle itemBundle;
    private SimpleDraweeView photo;
    private TextView title;

    public ItemHolder(Context context, View view){
        super(view);

        this.context = context;
        this.key = null;
        this.itemBundle = null;
        photo = (SimpleDraweeView)view.findViewById(R.id.itemholder_photo);
        title = (TextView)view.findViewById(R.id.itemholder_title);
        view.setOnClickListener(this);
    }

    public void bindData(Item item){
        if (key == null){ key = item.getID(); }
        if (itemBundle == null){
            itemBundle = new Bundle();
            itemBundle.setClassLoader(Item.class.getClassLoader());
            itemBundle.putParcelable("data", item);
        }

        photo.setImageURI(Uri.parse(item.getPhotoURL()));
    }

    @Override
    public void onClick(View view) {
        Intent intent = new Intent(context, ActivityB.class);
        intent.putExtra("bundle", itemBundle);
        context.startActivity(intent);
    }
}

public RecyclerAdapter(){
    this.list = new ArrayList<>();
    this.now = new Date();
}

public RecyclerAdapter(ArrayList<VideoItem> list){
    this.list = list;
    this.now = new Date();
    this.notifyItemRangeInserted(0, list.size());
}

@Override
public RecyclerAdapter.ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    Context context = parent.getContext();
    View recyclerItem = LayoutInflater.from(context)
            .inflate(R.layout.itemholder_item, parent, false);

    return new ItemHolder(context, recyclerItem);
}

@Override
public void onBindViewHolder(RecyclerAdapter.ItemHolder holder, int position) {
    Item item = list.get(position);
    holder.bindData(item);
}

private static Date getNow(){ return now; }

private static void updateNow(){ now = new Date(); }

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

public void addItem(Item item){
    list.add(item);
    this.notifyItemInserted(list.size() - 1);
}

public void addItems(ArrayList<Item> items){
    int oldSize = list.size();
    list.addAll(items);
    this.notifyItemRangeInserted(oldSize, items.size());
}

}


person ByteSized    schedule 25.10.2016    source източник
comment
Можете ли да публикувате вашия RecyclerAdapter?   -  person Benjamin Scharbau    schedule 25.10.2016
comment
По принцип, ако го виждам правилно, възстановявате само състоянието на LayoutManager, но не и данните на адаптера. Така че, когато отворите отново приложението, се създава адаптер с празен набор от данни и се свързва с вашия RecyclerView. Това, което трябва да направите, е да създадете конструктор за адаптера, който приема списък с данните за показване и да предава списъка, когато го инстанциирате (adapter = new RecyclerAdapter(list);).   -  person Benjamin Scharbau    schedule 25.10.2016
comment
@BenjaminScharbau RecyclerAdapter е добавен по-горе. Така че е най-добре да обединя и моя списък и ако (savedInstanceState == null) или да извикам adapter = new RecyclerAdapter(), ако е true, и adapter = new RecyclerAdapter(savedList), ако е false?   -  person ByteSized    schedule 25.10.2016
comment
Подобно, да. Но всъщност не разбирам защо го инстанциирате с new RecyclerAdapter() на първо място, вместо да го предадете списъка директно на потребителя. По принцип, това, което правя през повечето време, зареждам данните за адаптера в метода onResume() и създавам нов адаптер по време на този метод. Всъщност никога не съм го задавал по време на onCreate() разговора   -  person Benjamin Scharbau    schedule 25.10.2016
comment
Опитахте ли да коментирате напълно OnResume? Никога не проверявам изгледа на Recycler в автобиографията и той винаги работи правилно. @ByteSized   -  person Omid Heshmatinia    schedule 25.10.2016


Отговори (1)


Опитайте да промените своя onResume() метод така, че да изглежда по следния начин:

@Override
    public void onResume(){
          super.onResume(); 
          if (linearLayoutState != null) {
             linearLayoutManager.onRestoreInstanceState(linearLayoutState);
          } 
             // Here comes the code to populate your data. 
             // I'm not sure how you do this, so I just copy/paste your code
             for (ListItem item : list){
                    newList.add(new ListItemi(item));
             }
             // Now instatiate and add the adapter to the RecyclerView
             adapter = new RecyclerAdapter(newList);
             recyclerView.setAdapter(adapter);
          }
    }
person Benjamin Scharbau    schedule 25.10.2016
comment
Благодаря ви :) Също така открих, че не попълвам отново моя RecyclerView адаптер с никакви данни, когато приложението се връща от заден план. - person ByteSized; 04.11.2016