RecyclerView.State का उपयोग करके RecyclerView के स्क्रॉल स्थिति को कैसे बचाएं?


107

मेरे पास Android के RecyclerView.State के बारे में एक प्रश्न है ।

मैं एक RecyclerView का उपयोग कर रहा हूं, मैं इसे कैसे उपयोग कर सकता हूं और इसे RecyclerView.State के साथ बांध सकता हूं?

मेरा उद्देश्य RecyclerView के स्क्रॉल स्थिति को सहेजना है

जवाबों:


37

आप के साथ अंतिम बचाया स्थिति को बचाने के लिए कैसे योजना है RecyclerView.State?

आप हमेशा ओल की अच्छी बचत स्थिति पर भरोसा कर सकते हैं। विस्तार RecyclerViewऔर आगे बढ़ना onSaveInstanceState () और 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
अब मेरे पास एक और सवाल है, कैसे, नहीं, क्या है RecyclerView.State?
陈文涛

4
क्या यह वास्तव में काम करता है? मैं इस की कोशिश की है, लेकिन मैं इस तरह की एक क्रम अपवाद बार आ रही है: MyRecyclerView $ SavedState android.support.v7.widget.RecyclerView $ SavedState में ढाला नहीं जा सकता है
Daivid

2
पुनर्स्थापना आवृत्ति स्थिति पर हमें सुपरस्टैट को इसके सुपर क्लास (recytcler view) को इस तरह से पास करने की आवश्यकता है: super.onRestoreInstanceState ((ScrollPositionSavingRecyclerView.Savedorate) राज्य) .getSuperState ());
micnoy

5
यह काम नहीं करता है यदि आप RecyclerView का विस्तार करते हैं, तो आपको BadParcelException मिलेगी।
एपिकपांडाफॉर्स

1
इनमें से कोई भी आवश्यक नहीं है: यदि आप LinearLayoutManager / GridLayoutManager जैसी किसी चीज़ का उपयोग करते हैं, तो आपके लिए "स्क्रॉल स्थिति" पहले से ही स्वचालित रूप से सहेज ली गई है। (यह LinearLayoutManager.SavedState में mAnchorPosition है)। यदि आप उसे नहीं देख रहे हैं, तो कुछ गलत है कि आप डेटा को कैसे पुनः प्राप्त कर रहे हैं।
ब्रायन येनचो

229

अपडेट करें

recyclerview:1.2.0-alpha02रिलीज से शुरू StateRestorationPolicyकिया गया है। यह दी गई समस्या का एक बेहतर तरीका हो सकता है।

यह विषय Android डेवलपर्स मध्यम लेख पर कवर किया गया है ।

इसके अलावा, @ rubén-viguera ने नीचे दिए गए उत्तर में अधिक जानकारी साझा की। https://stackoverflow.com/a/61609823/892500

पुराना उत्तर

यदि आप LinearLayoutManager का उपयोग कर रहे हैं, तो यह प्री-बिल्ट सेव एपी रेखीयलैयूटमैनेजरइन्स्टेंस.ऑनसैव इनस्टांसटेस्ट () के साथ आता है और एपी रेखीय लयआउट मैनजमेंट इनस्टेंस.ऑनस्टॉर इनस्टोरेंस (...) को पुनर्स्थापित करता है।

उस के साथ, आप लौटे पार्सल को अपने आउटस्टेट में सहेज सकते हैं। जैसे,

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

, और आपके द्वारा सहेजे गए राज्य के साथ स्थिति बहाल करें। जैसे,

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

सभी को लपेटने के लिए, आपका अंतिम कोड कुछ इस तरह दिखाई देगा

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());
}

संपादित करें: आप GridLayoutManager के साथ उसी एप का उपयोग कर सकते हैं, क्योंकि यह LinearLayoutManager का उपवर्ग है। सुझाव के लिए धन्यवाद @wegsehen

संपादित करें: याद रखें, यदि आप एक बैकग्राउंड थ्रेड में डेटा लोड कर रहे हैं, तो आपको ओरिएंटेशन चेंज पर बहाल किए जाने की स्थिति के लिए अपने onPostExecute / onLoadFinished विधि के भीतर onRestoreInstanceState पर कॉल करने की आवश्यकता होगी।

@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
यह स्पष्ट रूप से सबसे अच्छा जवाब है, यह क्यों नहीं स्वीकार किया जाता है? ध्यान दें कि किसी भी LayoutManager के पास केवल LinearLayoutManager ही नहीं, GridLayoutManager भी है, और यदि इसका गलत कार्यान्वयन नहीं है।
पॉल वोइत्सेक

linearLayoutManager.onInstanceState () हमेशा शून्य -> ​​स्रोत कोड की जाँच करता है। दुर्भाग्य से काम नहीं कर रहा है।
भाग्यशाली 19

1
क्या RecyclerView अपने राज्य के लेआउटमैनेजर को अपने onSaveInstanceState में सेव नहीं करता है? समर्थन के v24 को देख रहा है lib ...
androidguy

3
यह एकल पर काम करता है, RecyclerViewलेकिन यदि आपके पास प्रत्येक पृष्ठ पर एक ViewPagerसाथ नहीं है RecycerView
क्रिश बी

1
@ इवान, मुझे लगता है कि यह एक टुकड़े (सिर्फ जाँच) में काम करता है onCreateView, लेकिन डेटा लोडिंग के बाद नहीं । @Farmaker का उत्तर यहाँ देखें।
कूलमाइंड

81

दुकान

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

पुनर्स्थापित

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

और अगर वह काम नहीं करता है, तो कोशिश करें

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

में स्टोर करें onPause() और पुनर्स्थापित करेंonResume()


यह काम करता है, लेकिन आपको इसे पुनर्स्थापित lastFirstVisiblePositionकरने के 0बाद रीसेट करने की आवश्यकता हो सकती है। यह मामला तब उपयोगी होता है जब आपके पास एक टुकड़ा / गतिविधि होती है जो एक में अलग-अलग डेटा लोड करती है RecyclerView, उदाहरण के लिए, एक फ़ाइल एक्सप्लोरर ऐप।
जुलाब

अति उत्कृष्ट! यह एक विस्तृत गतिविधि से सूची में वापस आने, और स्क्रीन रोटेशन पर राज्य की बचत दोनों को संतुष्ट करता है
जावी

यदि मेरा पुनर्नवीनीकरण दृश्य अंदर हो तो क्या करें SwipeRefreshLayout?
मोरोज़ोव

2
पहला पुनर्स्थापना विकल्प काम क्यों नहीं करेगा, लेकिन दूसरा होगा?
ल्यूसिडब्रोट

1
@MehranJalili ऐसा प्रतीत होता हैRecyclerView
व्लाद

22

मैं अपनी सूची गतिविधि से दूर नेविगेट करने और फिर वापस नेविगेट करने के लिए वापस बटन पर क्लिक करने पर रिसाइक्लर व्यू की स्क्रॉल स्थिति को बचाना चाहता था। इस समस्या के लिए प्रदान किए गए कई समाधान या तो ज़रूरत से ज़्यादा जटिल थे या मेरे कॉन्फ़िगरेशन के लिए काम नहीं करते थे, इसलिए मैंने सोचा कि मैं अपना समाधान साझा करूँगा।

सबसे पहले अपने इंस्टेंस स्टेट को ऑनपॉज में सेव करें जैसा कि कई ने दिखाया है। मुझे लगता है कि यह यहाँ जोर देने लायक है कि onSaveInstanceState का यह संस्करण RecyclerView.LayoutManager वर्ग की एक विधि है।

private LinearLayoutManager mLayoutManager;
Parcelable state;

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

इसे ठीक से काम करने की कुंजी यह सुनिश्चित करना है कि आप अपने एडॉप्टर को संलग्न करने के बाद onRestoreInstanceState पर कॉल करें, जैसा कि कुछ ने अन्य थ्रेड्स में इंगित किया है। हालाँकि वास्तविक विधि कॉल बहुत सरल है जितना कि कई ने संकेत दिया है।

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

1
यही सटीक उपाय है। : डी
अफजलुर रहमान राणा

1
मेरे लिए onSaveInstanceState isnt को onPause में इतना बचत वाला राज्य कहा जाता है जो एक बेहतर विकल्प की तरह लगता है। im भी टुकड़ा करने के लिए वापस मंच poping।
गंदी_विद्या

राज्य के भार के लिए। जो मैं onViewCreated में करता हूं। यह केवल तब काम करता है जब डिबग मोड में im और ब्रेक पॉइंट का उपयोग करें? या अगर मैं एक देरी जोड़ते हैं और निष्पादन को एक कोरटाइन में डालते हैं।
गंदी_विद्या

21

मैं onCreate () में चर सेट करता हूं, ऑनपॉज़ में स्क्रॉल स्थिति बचा सकता हूं () और ऑनस्क्यूम में स्क्रॉल स्थिति सेट करता हूं।)

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);
    }
}

आइटम की भरपाई भी करते रहें। अच्छा लगा। धन्यवाद!
t0m

14

आपको अब अपने आप से राज्य को बचाने और पुनर्स्थापित करने की आवश्यकता नहीं है। यदि आप xml और recyclerView.setSaveEnabled (ट्रू) (डिफॉल्ट बाय ट्रू) सिस्टम में यूनिक आईडी सेट करते हैं तो यह अपने आप आ जाएगा। यहाँ इस बारे में अधिक है: http://trickyandroid.com/saving-android-view-state-correctly/


14

समर्थन पुस्तकालय में बंडल किए गए सभी लेआउट प्रबंधक पहले से ही जानते हैं कि स्क्रॉल स्थिति को कैसे सहेजना और पुनर्स्थापित करना है।

स्क्रॉल स्थिति को पहले लेआउट पास पर बहाल किया जाता है जो निम्न स्थितियों के पूरा होने पर होता है:

  • एक लेआउट प्रबंधक से जुड़ा हुआ है RecyclerView
  • एक एडाप्टर से जुड़ा हुआ है RecyclerView

आमतौर पर आप XML में लेआउट प्रबंधक सेट करते हैं, इसलिए अब आपको बस इतना करना है

  1. एडॉप्टर को डेटा के साथ लोड करें
  2. फिर एडेप्टर को संलग्न करेंRecyclerView

आप किसी भी समय ऐसा कर सकते हैं, यह विवश नहीं है Fragment.onCreateViewया Activity.onCreate

उदाहरण: सुनिश्चित करें कि एडेप्टर हर बार डेटा अपडेट होने से जुड़ा हुआ है।

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
    }
}

सहेजे गए स्क्रॉल स्थिति की गणना निम्न डेटा से की जाती है:

  • स्क्रीन पर पहले आइटम का एडाप्टर स्थिति
  • सूची के शीर्ष से आइटम के शीर्ष के पिक्सेल ऑफसेट (ऊर्ध्वाधर लेआउट के लिए)

इसलिए आप मामूली बेमेल की उम्मीद कर सकते हैं जैसे अगर आपके आइटम में चित्र और परिदृश्य अभिविन्यास में विभिन्न आयाम हैं।


RecyclerView/ ScrollView/ जो कुछ भी एक की जरूरत है android:idअपने राज्य के लिए बचाया जा।


यह मेरे लिए था। मैं शुरू में तब अपना डेटा अपडेट करते हुए एडॉप्टर सेट कर रहा था। जैसा कि ऊपर बताया गया है, जब तक डेटा उपलब्ध नहीं होता तब तक इसे छोड़ना स्वचालित रूप से उस स्थान पर वापस स्क्रॉल कर देगा जहां यह था।
१०:४६ पर नील

धन्यवाद @ यूजेन क्या LayoutManager की बचत और स्क्रॉल स्थिति को पुनर्स्थापित करने पर कोई दस्तावेज़ है?
एडम हर्विट्ज

@AdamHurwitz आप किस तरह के प्रलेखन की उम्मीद करेंगे? मैंने जो वर्णन किया है वह LinearLayoutManager का कार्यान्वयन विवरण है, इसलिए इसके स्रोत कोड को पढ़ें।
यूजेन पिंचेक

1
यहाँ एक लिंक है LinearLayoutManager.SavedState: cs.android.com/androidx/platform/frameworks/support/+/…
Eugen Pechanec

धन्यवाद, @EugenPechanec यह मेरे लिए डिवाइस के रोटेशन के लिए काम करता है। मैं नीचे नेविगेशन दृश्य का भी उपयोग कर रहा हूं और जब मैं दूसरे निचले टैब पर स्विच करता हूं और वापस आता हूं, तो सूची फिर से शुरू होती है। यह क्यों है पर कोई विचार?
schv09

4

यहाँ उन्हें बचाने और एक टुकड़े में recyclerview की स्थिति बनाए रखने के लिए मेरा दृष्टिकोण है। सबसे पहले, कोड के नीचे अपनी मूल गतिविधि में कॉन्फ़िगर परिवर्तन जोड़ें।

android:configChanges="orientation|screenSize"

फिर अपने फ्रैगमेंट में इन इंस्टेंस मेथड को घोषित करें

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

अपने @onPause विधि में नीचे कोड जोड़ें

@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);
}

नीचे की तरह onConfigartionChanged Method जोड़ें।

@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);
}

यह दृष्टिकोण आपकी समस्या का समाधान करेगा। यदि आपके पास अलग लेआउट प्रबंधक है तो बस ऊपरी लेआउट प्रबंधक को बदलें।


डेटा को बनाए रखने के लिए आपको हैंडलर की आवश्यकता नहीं हो सकती है। बचत / लोडिंग के लिए जीवनचक्र विधियाँ पर्याप्त पर्याप्त होंगी।
माही

@sayaMahi क्या आप उचित तरीके से वर्णन कर सकते हैं। मैंने यह भी देखा है कि onConfigurationChanged नष्ट विधि पर कॉल करने से रोकता है। तो यह एक उचित समाधान नहीं है।
पवन कुमार शर्मा

3

जब आप AsyncTaskLoader के साथ इंटरनेट से डेटा पुनः लोड करने की आवश्यकता होती है, तो मैं रोटेशन के बाद GridLayoutManager के साथ RecyclerView की स्थिति को पुनर्स्थापित करता हूं।

Parcelable और GridLayoutManager का वैश्विक चर और एक स्थिर अंतिम स्ट्रिंग बनाएं:

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

OnSaveInstance () में ग्रिडलाइउट मैनजर की स्थिति सहेजें

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

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);
        }
    }

फिर जब लोडर इंटरनेट से डेटा प्राप्त करता है, तो आप onLoadFinished में recyclerview स्थिति को पुनर्स्थापित करते हैं ()

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

.. बेशक आप onCreate के अंदर gridLayoutManager को पलटना है। चियर्स


3

मेरे पास समान आवश्यकता है, लेकिन यहाँ समाधान मुझे रिसाइकलर के लिए डेटा के स्रोत के कारण लाइन के पार नहीं मिला।

मैं ऑनपॉज़ () में RecyclerViews 'LinearLayoutManager राज्य निकाल रहा था

private Parcelable state;

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

Parcelable stateमें सहेजा जाता है onSaveInstanceState(Bundle outState), और फिर से निकाला जाता है onCreate(Bundle savedInstanceState), जब savedInstanceState != null

हालाँकि, recyclerView एडॉप्टर पॉपुलेटेड है और एक ViewModel LiveData ऑब्जेक्ट द्वारा अद्यतन किया गया है जो DAO कॉल द्वारा एक कक्ष डेटाबेस में लौटाया गया है।

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

मैंने अंततः पाया कि एडेप्टर में डेटा सेट होने के बाद सीधे इंस्टेंस स्टेट को रिस्टोर करने से रोटेशन के दौरान स्क्रॉल-स्टेट बना रहेगा।

मुझे संदेह है कि या तो यह है कि जिस LinearLayoutManagerराज्य को मैंने बहाल किया था उसे तब अधिलेखित किया जा रहा था जब डेटा को डेटाबेस कॉल द्वारा वापस कर दिया गया था, या एक 'खाली' लिनियर लाईटमैनेगर के खिलाफ बहाल राज्य व्यर्थ था।

यदि एडॉप्टर डेटा सीधे उपलब्ध है (अर्थात एक डेटाबेस कॉल पर सन्निहित नहीं है), तो अडैप्टर स्टेट को फिर से इंस्टॉल किया जा सकता है क्योंकि अडैप्टर व्यू पर अडैप्टर सेट होने के बाद LinearLayoutManager पर किया जा सकता है।

दो परिदृश्यों के बीच अंतर ने मुझे युगों तक संभाला।


3

एंड्रॉइड एपीआई लेवल 28 पर, मैं बस यह सुनिश्चित करता हूं कि मैंने अपना LinearLayoutManagerऔर RecyclerView.Adapterअपने Fragment#onCreateViewतरीके का, और सब कुछ बस काम किया ️। मुझे कोई काम करने onSaveInstanceStateया onRestoreInstanceStateकाम करने की ज़रूरत नहीं थी ।

यूजेन पिंचेक का उत्तर बताता है कि यह क्यों काम करता है।


2

Androidx recyclerView लाइब्रेरी के संस्करण 1.2.0-Alpha02 से शुरू होकर अब यह स्वचालित रूप से प्रबंधित हो गया है। बस इसके साथ जोड़ें:

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

और उपयोग करें:

adapter.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY

StateRestorationPolicy Enum में 3 विकल्प हैं:

  • ALLOW - डिफ़ॉल्ट लेआउट राज्य, अगले लेआउट पास में, RecyclerView राज्य को तुरंत पुनर्स्थापित करता है
  • PREVENT_WHEN_EMPTY - केवल अडैप्टर खाली न होने पर ही RecyclerView स्थिति को पुनर्स्थापित करता है (adapter.getItemCount ()> 0)। यदि आपका डेटा async लोड किया गया है, तो RecyclerView डेटा लोड होने तक प्रतीक्षा करता है और उसके बाद ही राज्य को पुनर्स्थापित किया जाता है। यदि आपके पास एडेप्टर के भाग के रूप में डिफ़ॉल्ट आइटम हैं, जैसे हेडर या लोड प्रगति संकेतक, तो आपको PREVENT विकल्प का उपयोग करना चाहिए, जब तक कि डिफ़ॉल्ट आइटम MergeAdapter का उपयोग करके नहीं जोड़े जाते हैं । MergeAdapter अपने सभी एडेप्टर के तैयार होने का इंतजार करता है और उसके बाद ही यह राज्य को पुनर्स्थापित करता है।
  • PREVENT - जब तक आप ALLOW या PREVENT_WHEN_EMPTY सेट नहीं करते, तब तक सभी राज्य बहाली स्थगित कर दी जाती है।

ध्यान दें कि इस उत्तर के समय में, recyclerView पुस्तकालय अभी भी अल्फा 03 में है, लेकिन उत्पादन के उद्देश्य के लिए अल्फा चरण उपयुक्त नहीं है


इतना ओवरवर्क बचा। इसके अलावा हमें सूची क्लिक इंडेक्स को सहेजना था, तत्वों को पुनर्स्थापित करना था,
ऑनक्रिएट व्यू में रिड्राऊजिंग को रोकना था, स्क्रॉलटापिशन

इसके अलावा, अगर मैं ऐप के माध्यम से नेविगेशन के बाद RecyclerView स्थिति को बचाना चाहता हूं ... क्या इसके लिए कुछ उपकरण है?
स्टे जूल

@RubenViguera अल्फा उत्पादन के उद्देश्य से क्यों नहीं है? मेरा मतलब है कि वास्तव में बुरा है?
स्टे जूल

1

मेरे लिए, समस्या यह थी कि मैंने अपने एडेप्टर को बदलने के लिए हर बार एक नया लेआउटमैन स्थापित किया, जो कि रीसायकलर पर क्यू स्क्रॉल स्थिति खो रहा था।


1

मैं हाल ही में रीसायकलर व्यू के साथ मेरे द्वारा किए गए पूर्वानुमान को साझा करना चाहूंगा। मुझे उम्मीद है कि किसी को भी इस समस्या का सामना करने से लाभ होगा।

मेरी परियोजना की आवश्यकता: इसलिए मेरे पास एक पुनर्नवीनीकरण दृश्य है जो मेरी मुख्य गतिविधि (गतिविधि-ए) में कुछ क्लिक करने योग्य वस्तुओं को सूचीबद्ध करता है। जब आइटम पर क्लिक किया जाता है तो आइटम विवरण (गतिविधि-बी) के साथ एक नई गतिविधि दिखाई जाती है।

मैंने मेनिफेस्ट में लागू किया फ़ाइल कि एक्टिविटी-ए, एक्टिविटी-बी का जनक है, इस तरह, एक्टिविटी-बी के एक्शनबार पर मेरा बैक या होम बटन है

समस्या: हर बार जब मैंने एक्टिविटी-बी एक्शनबार में बैक या होम बटन दबाया, तो एक्टिविटी-ए पूरी गतिविधि लाइफ साइकल से शुरू होती है जो ऑनक्रिएट () से शुरू होती है।

भले ही मैं एक onSaveInstanceState () को RecyclerView के एडॉप्टर की सूची को सहेजते हुए कार्यान्वित करता हूं, जब गतिविधि-ए शुरू होता है यह जीवनचक्र होता है, फिर भी onInreatanceState onCreate () विधि में शून्य है।

इंटरनेट में आगे की खुदाई, मैं एक ही समस्या में आया था, लेकिन उस व्यक्ति ने देखा कि एनोइड डिवाइस (डिफ़ॉल्ट बैक / होम बटन) के नीचे बैक या होम बटन, एक्टिविटी-ए, एक्टिविटी लाइफ-साइकल में नहीं जाता है।

उपाय:

  1. मैंने गतिविधि-बी के लिए अभिभावक गतिविधि में टैग को हटा दिया
  2. मैंने गतिविधि-बी पर घर या बैक बटन को सक्षम किया

    OnCreate () विधि के तहत इस लाइन को जोड़ें ।ActionBar? ?SetDisplayHomeAsUpEnn की विश्वसनीय ()

  3. ओवरऑल फन ऑनऑन्यूज इटसेलेक्टेड () मेथड में, मैंने आइटम के लिए जांच की। इटिम आईड पर आइडी के आधार पर किस आइटम पर क्लिक किया गया है। बैक बटन के लिए Id है

    android.R.id.home

    फिर android.R.id.home के अंदर एक फिनिश () फ़ंक्शन कॉल लागू करें

    यह गतिविधि-बी को समाप्त कर देगा और पूरे जीवन-चक्र से गुजरे बिना एसिटिवी-ए लाएगा।

मेरी आवश्यकता के लिए यह अब तक का सबसे अच्छा समाधान है।

     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

मुझे मामूली अंतर के साथ एक ही समस्या थी, मैं डेटाबाइंडिंग का उपयोग कर रहा था , और मैं बाइंडिंग विधियों में recyclerView एडेप्टर और लेआउट मैनेजर को सेट कर रहा था।

समस्या यह थी कि डेटा-बाइंडिंग onResume के बाद हो रही थी, इसलिए यह onResume के बाद मेरे लेआउट मैनेजर को रीसेट कर रहा था और इसका मतलब है कि यह हर बार मूल स्थान पर वापस स्क्रॉल कर रहा था। इसलिए जब मैंने डेटाबाइंडिंग एडॉप्टर विधियों में लेआउटमैनेजर को सेट करना बंद कर दिया, तो यह फिर से ठीक काम करता है।


आपने इसे कैसे प्राप्त किया?
केदार सूकरकर

0

मेरे मामले में मैं layoutManagerXML में और दोनों में RecyclerView की स्थापना कर रहा था onViewCreated। नियत में onViewCreatedइसे हटाकर।

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();

    }   

मैं क्यों साधनों OnSaveInstanceState()में उपयोग कर रहा हूं onPause(), जबकि ऑनपॉज़ में किसी अन्य गतिविधि पर स्विच किया जाएगा। यह उस स्क्रॉल स्थिति को बचाएगा और उस स्थिति को पुनर्स्थापित करेगा जब हम किसी अन्य गतिविधि से वापस आ रहे हैं।


2
सार्वजनिक स्थैतिक क्षेत्र अच्छा नहीं है। वैश्विक डेटा और सिंगलटन अच्छे नहीं हैं।
पश्चिम

@ वेस्टन मुझे अब समझ आ गया था। मैंने ग्लोबल को हटाने के लिए बचत को बदल दिया।
स्टीव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.