Làm cách nào để lưu vị trí cuộn của RecyclerView bằng RecyclerView.State?


107

Tôi có câu hỏi về RecyclerView.State của Android .

Tôi đang sử dụng RecyclerView, làm cách nào tôi có thể sử dụng và liên kết nó với RecyclerView.State?

Mục đích của tôi là lưu vị trí cuộn của RecyclerView .

Câu trả lời:


37

Bạn dự định lưu vị trí đã lưu cuối cùng bằng cách RecyclerView.Statenào?

Bạn luôn có thể dựa vào trạng thái lưu tốt. Mở rộng RecyclerViewvà ghi đè onSaveInstanceState () và onRestoreInstanceState():

    @Override
    protected Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        LayoutManager layoutManager = getLayoutManager();
        if(layoutManager != null && layoutManager instanceof LinearLayoutManager){
            mScrollPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
        }
        SavedState newState = new SavedState(superState);
        newState.mScrollPosition = mScrollPosition;
        return newState;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        super.onRestoreInstanceState(state);
        if(state != null && state instanceof SavedState){
            mScrollPosition = ((SavedState) state).mScrollPosition;
            LayoutManager layoutManager = getLayoutManager();
            if(layoutManager != null){
              int count = layoutManager.getItemCount();
              if(mScrollPosition != RecyclerView.NO_POSITION && mScrollPosition < count){
                  layoutManager.scrollToPosition(mScrollPosition);
              }
            }
        }
    }

    static class SavedState extends android.view.View.BaseSavedState {
        public int mScrollPosition;
        SavedState(Parcel in) {
            super(in);
            mScrollPosition = in.readInt();
        }
        SavedState(Parcelable superState) {
            super(superState);
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            super.writeToParcel(dest, flags);
            dest.writeInt(mScrollPosition);
        }
        public static final Parcelable.Creator<SavedState> CREATOR
                = new Parcelable.Creator<SavedState>() {
            @Override
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            @Override
            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }

1
bây giờ tôi có một câu hỏi khác, làm thế nào, không, RecyclerView.State có thể làm gì?
陈文涛

4
điều này có thực sự hoạt động không? Tôi đã cố gắng này, nhưng tôi tiếp tục nhận được một ngoại lệ thời gian chạy như thế này: MyRecyclerView $ SavedState không thể được đúc để android.support.v7.widget.RecyclerView $ SavedState
Daivid

2
Ở trạng thái cá thể khôi phục, chúng ta cần truyền superState vào siêu lớp của nó (chế độ xem recytcler) như sau: super.onRestoreInstanceState (((ScrollPositionSavingRecyclerView.SavedState) trạng thái) .getSuperState ());
micnoy

5
Điều này không hiệu quả nếu bạn mở rộng RecyclerView, bạn sẽ nhận được BadParcelException.
EpicPandaForce

1
Điều này không cần thiết: nếu bạn sử dụng cái gì đó như LinearLayoutManager / GridLayoutManager, "vị trí cuộn" đã được lưu tự động cho bạn. (Đó là mAnchorPosition trong LinearLayoutManager.SavedState). Nếu bạn không thấy điều đó, thì có gì đó không ổn với cách bạn áp dụng lại dữ liệu.
Brian Yencho

229

Cập nhật

Bắt đầu từ recyclerview:1.2.0-alpha02phát hành StateRestorationPolicyđã được giới thiệu. Nó có thể là một cách tiếp cận tốt hơn cho vấn đề đã cho.

Chủ đề này đã được đề cập trong bài báo phương tiện dành cho nhà phát triển Android .

Ngoài ra, @ rubén-viguera đã chia sẻ chi tiết hơn trong câu trả lời bên dưới. https://stackoverflow.com/a/61609823/892500

Câu trả lời cũ

Nếu bạn đang sử dụng LinearLayoutManager, nó đi kèm với lưu trữ sẵn api linearLayoutManagerInstance.onSaveInstanceState () và khôi phục api linearLayoutManagerInstance.onRestoreInstanceState (...)

Cùng với đó, bạn có thể lưu bưu kiện đã trả lại vào outState của mình. ví dụ,

outState.putParcelable("KeyForLayoutManagerState", linearLayoutManagerInstance.onSaveInstanceState());

và khôi phục vị trí khôi phục với trạng thái bạn đã lưu. ví dụ,

Parcelable state = savedInstanceState.getParcelable("KeyForLayoutManagerState");
linearLayoutManagerInstance.onRestoreInstanceState(state);

Để tóm tắt tất cả, mã cuối cùng của bạn sẽ trông giống như

private static final String BUNDLE_RECYCLER_LAYOUT = "classname.recycler.layout";

/**
 * This is a method for Fragment. 
 * You can do the same in onCreate or onRestoreInstanceState
 */
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
    super.onViewStateRestored(savedInstanceState);

    if(savedInstanceState != null)
    {
        Parcelable savedRecyclerLayoutState = savedInstanceState.getParcelable(BUNDLE_RECYCLER_LAYOUT);
        recyclerView.getLayoutManager().onRestoreInstanceState(savedRecyclerLayoutState);
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putParcelable(BUNDLE_RECYCLER_LAYOUT, recyclerView.getLayoutManager().onSaveInstanceState());
}

Chỉnh sửa: Bạn cũng có thể sử dụng cùng một apis với GridLayoutManager, vì nó là một lớp con của LinearLayoutManager. Cảm ơn @wegsehen vì đề xuất.

Chỉnh sửa: Hãy nhớ rằng, nếu bạn cũng đang tải dữ liệu trong một chuỗi nền, bạn sẽ cần gọi đến onRestoreInstanceState trong phương thức onPostExecute / onLoadFinishing của mình để vị trí được khôi phục khi thay đổi hướng, ví dụ:

@Override
protected void onPostExecute(ArrayList<Movie> movies) {
    mLoadingIndicator.setVisibility(View.INVISIBLE);
    if (movies != null) {
        showMoviePosterDataView();
        mDataAdapter.setMovies(movies);
      mRecyclerView.getLayoutManager().onRestoreInstanceState(mSavedRecyclerLayoutState);
        } else {
            showErrorMessage();
        }
    }

21
Đây rõ ràng là câu trả lời tốt nhất, tại sao điều này lại không được chấp nhận? Lưu ý rằng bất kỳ LayoutManager nào cũng có điều đó, không chỉ LinearLayoutManager, GridLayoutManager, và nếu không phải là triển khai sai.
Paul Woitaschek

linearLayoutManager.onInstanceState () luôn trả về null -> kiểm tra mã nguồn. Thật không may là không hoạt động.
luckyhandler

1
RecyclerView không thực hiện lưu trạng thái của LayoutManager trong onSaveInstanceState của chính nó? Nhìn vào v24 của lib hỗ trợ ...
androidguy

3
Điều này hoạt động trên một trang duy nhất RecyclerViewnhưng không hoạt động nếu bạn có ViewPagervới RecycerViewtrên mỗi trang.
Kris B

1
@Ivan, tôi nghĩ nó hoạt động trong một phân đoạn (vừa được kiểm tra), nhưng không phải trong onCreateView, mà là sau khi tải dữ liệu. Xem câu trả lời của @Farmaker tại đây.
CoolMind

81

Cửa hàng

lastFirstVisiblePosition = ((LinearLayoutManager)rv.getLayoutManager()).findFirstCompletelyVisibleItemPosition();

Khôi phục

((LinearLayoutManager) rv.getLayoutManager()).scrollToPosition(lastFirstVisiblePosition);

và nếu điều đó không hiệu quả, hãy thử

((LinearLayoutManager) rv.getLayoutManager()).scrollToPositionWithOffset(lastFirstVisiblePosition,0)

Đặt cửa hàng vào onPause() và khôi phụconResume()


Công trình này, nhưng bạn có thể cần phải thiết lập lại lastFirstVisiblePositionđể 0sau khi khôi phục nó. Trường hợp này hữu ích khi bạn có một phân đoạn / hoạt động tải dữ liệu khác nhau trong một RecyclerView, chẳng hạn như ứng dụng trình khám phá tệp.
blueware,

Thông minh! Nó đáp ứng cả việc quay lại từ một hoạt động chi tiết vào danh sách và lưu trạng thái khi quay màn hình
Javi

phải làm gì nếu Chế độ xem tái chế của tôi ở trong SwipeRefreshLayout?
Morozov

2
Tại sao tùy chọn khôi phục đầu tiên không hoạt động, nhưng tùy chọn thứ hai sẽ?
lucidbrot

1
@MehranJalili có vẻ là mộtRecyclerView
Vlad

22

Tôi muốn lưu vị trí cuộn của Recycler View khi điều hướng khỏi hoạt động trong danh sách của mình và sau đó nhấp vào nút quay lại để điều hướng trở lại. Nhiều giải pháp được cung cấp cho vấn đề này phức tạp hơn nhiều so với mức cần thiết hoặc không hoạt động đối với cấu hình của tôi, vì vậy tôi nghĩ tôi sẽ chia sẻ giải pháp của mình.

Đầu tiên, lưu trạng thái phiên bản của bạn trong onPause như nhiều trạng thái đã hiển thị. Tôi nghĩ điều đáng nhấn mạnh ở đây là phiên bản onSaveInstanceState này là một phương thức từ lớp RecyclerView.LayoutManager.

private LinearLayoutManager mLayoutManager;
Parcelable state;

        @Override
        public void onPause() {
            super.onPause();
            state = mLayoutManager.onSaveInstanceState();
        }

Chìa khóa để làm cho điều này hoạt động bình thường là đảm bảo bạn gọi onRestoreInstanceState sau khi bạn gắn bộ điều hợp của mình, như một số đã chỉ ra trong các chuỗi khác. Tuy nhiên, cách gọi phương thức thực tế đơn giản hơn nhiều so với nhiều người đã chỉ ra.

private void someMethod() {
    mVenueRecyclerView.setAdapter(mVenueAdapter);
    mLayoutManager.onRestoreInstanceState(state);
}

1
Đó là giải pháp chính xác. : D
Afjalur Rahman Rana,

1
đối với tôi onSaveInstanceState không được gọi nên trạng thái lưu trong onPause có vẻ như là một lựa chọn tốt hơn. tôi cũng đang bật bao sau để quay trở lại mảnh vỡ.
filthy_wizard

cho tải ở trạng thái. mà tôi làm trong onViewCreate. nó dường như chỉ hoạt động khi tôi ở chế độ gỡ lỗi và sử dụng điểm ngắt? hoặc nếu tôi thêm thời gian trễ và đặt quá trình thực hiện trong một quy trình.
filthy_wizard

21

Tôi Đặt các biến trong onCreate (), lưu vị trí cuộn trong onPause () và đặt vị trí cuộn trong onResume ()

public static int index = -1;
public static int top = -1;
LinearLayoutManager mLayoutManager;

@Override
public void onCreate(Bundle savedInstanceState)
{
    //Set Variables
    super.onCreate(savedInstanceState);
    cRecyclerView = ( RecyclerView )findViewById(R.id.conv_recycler);
    mLayoutManager = new LinearLayoutManager(this);
    cRecyclerView.setHasFixedSize(true);
    cRecyclerView.setLayoutManager(mLayoutManager);

}

@Override
public void onPause()
{
    super.onPause();
    //read current recyclerview position
    index = mLayoutManager.findFirstVisibleItemPosition();
    View v = cRecyclerView.getChildAt(0);
    top = (v == null) ? 0 : (v.getTop() - cRecyclerView.getPaddingTop());
}

@Override
public void onResume()
{
    super.onResume();
    //set recyclerview position
    if(index != -1)
    {
        mLayoutManager.scrollToPositionWithOffset( index, top);
    }
}

Giữ bù đắp của mặt hàng quá. Đẹp. Cảm ơn!
t0m 17/07/17


14

Tất cả các trình quản lý bố cục có trong thư viện hỗ trợ đã biết cách lưu và khôi phục vị trí cuộn.

Vị trí cuộn được khôi phục trên lần vượt qua bố cục đầu tiên xảy ra khi các điều kiện sau được đáp ứng:

  • một trình quản lý bố trí được đính kèm với RecyclerView
  • một bộ điều hợp được gắn vào RecyclerView

Thông thường, bạn đặt trình quản lý bố cục trong XML, vì vậy tất cả những gì bạn phải làm bây giờ là

  1. Nạp dữ liệu vào bộ điều hợp
  2. Sau đó gắn bộ điều hợp vàoRecyclerView

Bạn có thể làm điều này bất cứ lúc nào, không bị hạn chế Fragment.onCreateViewhoặc Activity.onCreate.

Ví dụ: Đảm bảo bộ điều hợp được đính kèm mỗi khi dữ liệu được cập nhật.

viewModel.liveData.observe(this) {
    // Load adapter.
    adapter.data = it

    if (list.adapter != adapter) {
        // Only set the adapter if we didn't do it already.
        list.adapter = adapter
    }
}

Vị trí cuộn đã lưu được tính toán từ dữ liệu sau:

  • Vị trí bộ điều hợp của mục đầu tiên trên màn hình
  • Độ lệch pixel của đầu mục so với đầu danh sách (đối với bố cục dọc)

Do đó, bạn có thể mong đợi sự không khớp đôi chút, ví dụ nếu các mặt hàng của bạn có kích thước khác nhau theo hướng dọc và ngang.


Các RecyclerView/ ScrollView/ bất cứ điều gì cần phải có một android:idcho trạng thái của nó được cứu rỗi.


Đây là nó cho tôi. Tôi đã thiết lập bộ điều hợp ban đầu, sau đó cập nhật dữ liệu của nó khi có sẵn. Như đã giải thích ở trên, để nó cho đến khi có dữ liệu sẽ tự động cuộn trở lại vị trí cũ.
NeilS

Cảm ơn @Eugen. Có tài liệu nào về cách lưu và khôi phục vị trí cuộn của LayoutManager không?
Adam Hurwitz

@AdamHurwitz Bạn mong đợi loại tài liệu nào? Những gì tôi mô tả là chi tiết triển khai của LinearLayoutManager, vì vậy hãy đọc mã nguồn của nó.
Eugen Pechanec

1
Đây là một liên kết đến LinearLayoutManager.SavedState: cs.android.com/androidx/platform/frameworks/support/+/…
Eugen Pechanec

Cảm ơn, @EugenPechanec. Điều này đã làm việc cho tôi đối với việc xoay thiết bị. Tôi cũng đang sử dụng chế độ xem điều hướng dưới cùng và khi tôi chuyển sang một tab dưới cùng khác và quay lại, danh sách bắt đầu lại từ đầu. Bất kỳ ý tưởng về lý do tại sao điều này là?
schv09

4

Đây là Phương pháp tiếp cận của tôi để lưu chúng và duy trì trạng thái tái chế trong một mảnh. Đầu tiên, hãy thêm các thay đổi cấu hình trong hoạt động mẹ của bạn như mã bên dưới.

android:configChanges="orientation|screenSize"

Sau đó, trong Fragment của bạn, hãy khai báo phương thức instance này

private  Bundle mBundleRecyclerViewState;
private Parcelable mListState = null;
private LinearLayoutManager mLinearLayoutManager;

Thêm mã bên dưới vào phương thức @onPause của bạn

@Override
public void onPause() {
    super.onPause();
    //This used to store the state of recycler view
    mBundleRecyclerViewState = new Bundle();
    mListState =mTrailersRecyclerView.getLayoutManager().onSaveInstanceState();
    mBundleRecyclerViewState.putParcelable(getResources().getString(R.string.recycler_scroll_position_key), mListState);
}

Thêm phương thức onConfigartionChanged như bên dưới.

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    //When orientation is changed then grid column count is also changed so get every time
    Log.e(TAG, "onConfigurationChanged: " );
    if (mBundleRecyclerViewState != null) {
        new Handler().postDelayed(new Runnable() {

            @Override
            public void run() {
                mListState = mBundleRecyclerViewState.getParcelable(getResources().getString(R.string.recycler_scroll_position_key));
                mTrailersRecyclerView.getLayoutManager().onRestoreInstanceState(mListState);

            }
        }, 50);
    }
    mTrailersRecyclerView.setLayoutManager(mLinearLayoutManager);
}

Sự tiếp cận này sẽ giải quyết vấn đề của bạn. nếu Bạn có trình quản lý bố cục khác thì chỉ cần thay thế trình quản lý bố trí trên.


Bạn có thể không cần một Trình xử lý cho dữ liệu liên tục. Các phương pháp vòng đời sẽ đủ để lưu / tải.
Mahi

@sayaMahi Bạn có thể mô tả một cách thích hợp. Tôi cũng đã thấy rằng onConfigurationChanged ngăn không cho gọi phương thức hủy. vì vậy nó không phải là một giải pháp thích hợp.
Pawan kumar sharma

3

Đây là cách tôi khôi phục vị trí RecyclerView với GridLayoutManager sau khi xoay khi bạn cần tải lại dữ liệu từ internet bằng AsyncTaskLoader.

Tạo một biến toàn cục của Parcelable và GridLayoutManager và một chuỗi cuối cùng tĩnh:

private Parcelable savedRecyclerLayoutState;
private GridLayoutManager mGridLayoutManager;
private static final String BUNDLE_RECYCLER_LAYOUT = "recycler_layout";

Lưu trạng thái của gridLayoutManager trong onSaveInstance ()

 @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putParcelable(BUNDLE_RECYCLER_LAYOUT, 
            mGridLayoutManager.onSaveInstanceState());
        }

Khôi phục trong onRestoreInstanceState

@Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);

        //restore recycler view at same position
        if (savedInstanceState != null) {
            savedRecyclerLayoutState = savedInstanceState.getParcelable(BUNDLE_RECYCLER_LAYOUT);
        }
    }

Sau đó, khi trình tải tìm nạp dữ liệu từ internet, bạn khôi phục vị trí tái chế trong onLoadFinishing ()

if(savedRecyclerLayoutState!=null){
                mGridLayoutManager.onRestoreInstanceState(savedRecyclerLayoutState);
            }

.. tất nhiên bạn phải khởi tạo gridLayoutManager bên trong onCreate. Chúc mừng


3

Tôi cũng có yêu cầu tương tự, nhưng các giải pháp ở đây không giúp tôi vượt qua được giới hạn, do nguồn dữ liệu cho Chế độ xem tái chế.

Tôi đang giải nén trạng thái LinearLayoutManager của RecyclerViews trong onPause ()

private Parcelable state;

Public void onPause() {
    state = mLinearLayoutManager.onSaveInstanceState();
}

Parcelable stateđược lưu vào onSaveInstanceState(Bundle outState)và được giải nén lại vào onCreate(Bundle savedInstanceState)khi nào savedInstanceState != null.

Tuy nhiên, bộ điều hợp RecyclerView được điền và cập nhật bởi một đối tượng ViewModel LiveData bằng lệnh gọi DAO đến cơ sở dữ liệu Phòng.

mViewModel.getAllDataToDisplay(mSelectedData).observe(this, new Observer<List<String>>() {
    @Override
    public void onChanged(@Nullable final List<String> displayStrings) {
        mAdapter.swapData(displayStrings);
        mLinearLayoutManager.onRestoreInstanceState(state);
    }
});

Cuối cùng tôi nhận thấy rằng việc khôi phục trạng thái phiên bản trực tiếp sau khi dữ liệu được đặt trong bộ điều hợp sẽ giữ trạng thái cuộn qua các lần xoay.

Tôi nghi ngờ điều này là do LinearLayoutManagertrạng thái mà tôi đã khôi phục bị ghi đè khi dữ liệu được trả về bởi lệnh gọi cơ sở dữ liệu hoặc trạng thái được khôi phục là vô nghĩa đối với một LinearLayoutManager 'trống'.

Nếu dữ liệu bộ điều hợp có sẵn trực tiếp (nghĩa là không liên quan đến lệnh gọi cơ sở dữ liệu), thì việc khôi phục trạng thái phiên bản trên LinearLayoutManager có thể được thực hiện sau khi bộ điều hợp được đặt trên RecyclerView.

Sự khác biệt giữa hai kịch bản đã khiến tôi cảm thấy khó chịu.


3

Trên Android API Cấp 28, tôi chỉ cần đảm bảo rằng tôi đã thiết lập phương pháp của mình LinearLayoutManagerRecyclerView.Adaptertrong Fragment#onCreateViewphương pháp của mình cũng như mọi thứ Just Worked ™ ️. Tôi không cần phải làm bất cứ onSaveInstanceStatehay onRestoreInstanceStatelàm việc.

Câu trả lời của Eugen Pechanec giải thích tại sao điều này lại hiệu quả.


2

Bắt đầu từ phiên bản 1.2.0-alpha02 của thư viện androidx remlerView, giờ đây nó được quản lý tự động. Chỉ cần thêm nó với:

implementation "androidx.recyclerview:recyclerview:1.2.0-alpha02"

Và sử dụng:

adapter.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY

Enum StateRestorationPolicy có 3 tùy chọn:

  • CHO PHÉP - trạng thái mặc định, khôi phục trạng thái RecyclerView ngay lập tức, trong lần vượt qua bố cục tiếp theo
  • PREVENT_WHEN_EMPTY - chỉ khôi phục trạng thái RecyclerView khi bộ điều hợp không trống (adapter.getItemCount ()> 0). Nếu dữ liệu của bạn được tải không đồng bộ, RecyclerView sẽ đợi cho đến khi dữ liệu được tải và chỉ khi đó trạng thái mới được khôi phục. Nếu bạn có các mục mặc định, như tiêu đề hoặc chỉ báo tiến trình tải như một phần của Bộ điều hợp, thì bạn nên sử dụng tùy chọn PREVENT, trừ khi các mục mặc định được thêm bằng MergeAdapter . MergeAdapter đợi tất cả các bộ điều hợp của nó sẵn sàng và chỉ khi đó nó mới khôi phục trạng thái.
  • PREVENT - tất cả khôi phục trạng thái được hoãn lại cho đến khi bạn đặt ALLOW hoặc PREVENT_WHEN_EMPTY.

Lưu ý rằng tại thời điểm câu trả lời này, thư viện RecyclerView vẫn ở alpha03, nhưng giai đoạn alpha không phù hợp cho mục đích sản xuất .


Vì vậy, rất nhiều công việc quá sức được tiết kiệm. Nếu không, chúng tôi đã phải lưu chỉ mục nhấp chuột của danh sách, khôi phục các phần tử, ngăn việc vẽ lại trong onCreateView, áp dụng scrollToPosition (hoặc làm như các câu trả lời khác) nhưng người dùng có thể nhận thấy sự khác biệt sau khi quay lại
Rahul Kahale

Ngoài ra, nếu tôi muốn lưu vị trí RecyclerView sau khi điều hướng thông qua ứng dụng ... thì có một số công cụ cho nó không?
StayCool

@RubenViguera Tại sao alpha không dành cho mục đích sản xuất? Ý tôi là điều đó thực sự tồi tệ?
StayCool

1

Đối với tôi, vấn đề là tôi thiết lập một trình quản lý bố cục mới mỗi khi tôi thay đổi bộ điều hợp của mình, làm mất vị trí cuộn của hàng đợi trên RecyclerView.


1

Tôi chỉ muốn chia sẻ tình trạng khó khăn gần đây mà tôi gặp phải với RecyclerView. Tôi hy vọng rằng bất cứ ai gặp phải vấn đề tương tự sẽ được hưởng lợi.

Yêu cầu dự án của tôi: Vì vậy, tôi có RecyclerView liệt kê một số mục có thể nhấp trong Hoạt động chính của tôi (Hoạt động-A). Khi Mục được nhấp vào, một Hoạt động mới được hiển thị với Chi tiết Mục (Hoạt động-B).

Tôi đã triển khai trong Tệp kê khai tệp rằng Activity-A là cha của Activity-B, theo cách đó, tôi có nút quay lại hoặc nút trang chủ trên ActionBar của Activity-B

Sự cố: Mỗi khi tôi nhấn nút Quay lại hoặc Trang chủ trong Thanh tác vụ Activity-B, Activity-A sẽ đi vào toàn bộ Vòng đời hoạt động bắt đầu từ onCreate ()

Mặc dù tôi đã triển khai onSaveInstanceState () lưu Danh sách Bộ điều hợp của RecyclerView, khi Activity-A bắt đầu vòng đời của nó, thì saveInstanceState luôn là null trong phương thức onCreate ().

Tìm hiểu sâu hơn trên internet, tôi gặp vấn đề tương tự nhưng người đó nhận thấy rằng nút Quay lại hoặc Trang chủ bên dưới thiết bị Anroid (nút Quay lại / Trang chủ mặc định), Activity-A không đi vào Vòng đời hoạt động.

Giải pháp:

  1. Tôi đã xóa Thẻ cho Hoạt động của cha mẹ trong tệp kê khai cho Hoạt động-B
  2. Tôi đã bật nút trang chủ hoặc nút quay lại trên Activity-B

    Trong phương thức onCreate (), thêm dòng này supportActionBar? .SetDisplayHomeAsUpEnabled (true)

  3. Trong phương thức onOptionsItemSelected () vui nhộn ghi đè, tôi đã kiểm tra item.ItemId mà item được nhấp dựa trên id. Id cho nút quay lại là

    android.R.id.home

    Sau đó, thực hiện một lệnh gọi hàm finish () bên trong android.R.id.home

    Điều này sẽ kết thúc Activity-B và mang lại Acitivy-A mà không cần trải qua toàn bộ vòng đời.

Đối với yêu cầu của tôi, đây là giải pháp tốt nhất cho đến nay.

     override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_show_project)

    supportActionBar?.title = projectName
    supportActionBar?.setDisplayHomeAsUpEnabled(true)

}


 override fun onOptionsItemSelected(item: MenuItem?): Boolean {

    when(item?.itemId){

        android.R.id.home -> {
            finish()
        }
    }

    return super.onOptionsItemSelected(item)
}

1

Tôi đã gặp vấn đề tương tự với một sự khác biệt nhỏ, tôi đang sử dụng Databinding và tôi đang đặt bộ điều hợp RecyclerView và layoutManager trong các phương thức liên kết.

Vấn đề là ràng buộc dữ liệu đã xảy ra sau onResume, vì vậy nó đang đặt lại layoutManager của tôi sau onResume và điều đó có nghĩa là nó luôn cuộn lại vị trí ban đầu. Vì vậy, khi tôi ngừng thiết lập layoutManager trong các phương thức bộ điều hợp Databinding, nó hoạt động tốt trở lại.


làm thế nào bạn đạt được nó?
Kedar Sukerkar

0

Trong trường hợp của tôi, tôi đã thiết lập RecyclerView layoutManagercả trong XML và trong onViewCreated. Xóa bài tập đã onViewCreatedsửa nó.

with(_binding.list) {
//  layoutManager =  LinearLayoutManager(context)
    adapter = MyAdapter().apply {
        listViewModel.data.observe(viewLifecycleOwner,
            Observer {
                it?.let { setItems(it) }
            })
    }
}

-1

Activity.java:

public RecyclerView.LayoutManager mLayoutManager;

Parcelable state;

    mLayoutManager = new LinearLayoutManager(this);


// Inside `onCreate()` lifecycle method, put the below code :

    if(state != null) {
    mLayoutManager.onRestoreInstanceState(state);

    } 

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

        if (state != null) {
            mLayoutManager.onRestoreInstanceState(state);
        }
    }   

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

        state = mLayoutManager.onSaveInstanceState();

    }   

Tại sao tôi đang sử dụng OnSaveInstanceState()trong onPause()phương tiện, khi chuyển sang hoạt động khác onPause sẽ called.It sẽ tiết kiệm được rằng vị trí cuộn và khôi phục lại vị trí khi chúng tôi trở về từ hoạt động khác.


2
Trường tĩnh Công cộng không tốt. Dữ liệu toàn cầu và các ổ đĩa đơn không tốt.
weston

@weston Bây giờ tôi đã hiểu. Tôi đã thay đổi trạng thái lưu thành tạm dừng để xóa toàn cầu.
Steve
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.