রিসাইক্লারভিউ.স্টেট ব্যবহার করে কীভাবে রিসাইক্লারভিউয়ের স্ক্রোল অবস্থানটি সংরক্ষণ করবেন?


107

অ্যান্ড্রয়েড সম্পর্কে আমার একটি প্রশ্ন আছে রিসাইক্লার ভিউ স্টেট

আমি একটি পুনর্ব্যবহারযোগ্য ভিউ ব্যবহার করছি, আমি কীভাবে এটি ব্যবহার করতে পারি এবং এটি পুনর্ব্যবহারযোগ্য.স্টেটের সাথে আবদ্ধ করতে পারি?

আমার উদ্দেশ্য পুনর্ব্যবহারযোগ্যের স্ক্রোল অবস্থানটি সংরক্ষণ করা

উত্তর:


37

আপনি কীভাবে সর্বশেষ সংরক্ষিত অবস্থানটি সংরক্ষণের পরিকল্পনা করছেন RecyclerView.State?

আপনি সর্বদা ওল 'ভাল সংরক্ষণের অবস্থার উপর নির্ভর করতে পারেন। RecyclerViewSaveInstanceState () এবং 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
এখন আমার আর একটি প্রশ্ন আছে, কীভাবে, না, রিসাইক্লার ভিউ.স্টেট কী করতে পারে?
陈文涛

4
এটি কি সত্যিই কাজ করে? আমি এটি চেষ্টা করেছি, তবে আমি এইভাবে একটি রানটাইম ব্যতিক্রম পেতে থাকি: মাইআরসিক্র্লারভিউ $ সেভডস্টেটটি Android.support.v7.widget.RecyclerView $ সেভডস্টেটে
ডেভিড

2
পুনরুদ্ধার উদাহরণস্বরূপ স্টেটে আমাদের সুপারস্টেটকে তার সুপার ক্লাসে (পুনর্ব্যবহারযোগ্য দৃশ্য) এ জাতীয় পাস করতে হবে: সুপার.অনরেস্টোরইনস্ট্যান্সস্টেট (((স্ক্রোলপজিশন সেভিংসাইক্লারভিউ।স্যাভেডস্টেট) রাজ্য) .getSuperState ()));
মিকনয়

5
আপনি পুনর্ব্যবহারযোগ্য ভিউ বাড়িয়ে দিলে এটি কাজ করে না, আপনি BadParcelException পাবেন।
এপিকপান্ডাফোরস

1
এর কোনওটির প্রয়োজন নেই: আপনি লিনিয়ারলআউটম্যানেজার / গ্রিডলআউটম্যানেজারের মতো যদি কিছু ব্যবহার করেন তবে "স্ক্রোল অবস্থান" ইতিমধ্যে আপনার জন্য স্বয়ংক্রিয়ভাবে সংরক্ষণ করা হয়েছে। (এটি লিনিয়ারলআউটআমনেজ.আরভেদস্টেটে এমএঙ্কর পজিশন)। আপনি যদি তা না দেখছেন, তবে আপনি কীভাবে ডেটা প্রয়োগ করছেন তা নিয়ে কিছু ভুল is
ব্রায়ান ইয়েনচো

229

হালনাগাদ

recyclerview:1.2.0-alpha02মুক্তি থেকে শুরু StateRestorationPolicyকরা হয়েছে। এটি প্রদত্ত সমস্যার আরও ভাল পদ্ধতির হতে পারে।

এই বিষয়টি অ্যান্ড্রয়েড বিকাশকারীদের মাঝারি নিবন্ধে আচ্ছাদিত করা হয়েছে ।

এছাড়াও, @ রুবন-ভিগুয়েরা নীচের উত্তরে আরও বিশদ ভাগ করেছেন। https://stackoverflow.com/a/61609823/892500

পুরানো উত্তর

আপনি যদি লিনিয়ারলআউটআমনেজারটি ব্যবহার করে থাকেন তবে এটি প্রাক-বিল্ট সেভ এপি লিনিয়ারলয়আউট ম্যানেজারআইন্সটেন্স.অনসেভআইন্সট্যান্সস্টেট () এবং এপিআই লিনিয়ারলআউটআউট ম্যানেজারআইন্সটেন্স.অনস্টোরআইনস্ট্যান্সস্টেটটি পুনরুদ্ধার করে (...)

এটির সাহায্যে আপনি ফেরত পার্সলেবল আপনার আউটস্টেটে সংরক্ষণ করতে পারেন। যেমন,

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

সম্পাদনা করুন: আপনি গ্রিডলআউটআউট ম্যানেজারের সাথে একই অ্যাপসটিও ব্যবহার করতে পারেন, কারণ এটি লিনিয়ারলআউটআউট ম্যানেজারের একটি সাবক্লাস। পরামর্শের জন্য @ ওয়েগসহেনকে ধন্যবাদ

সম্পাদনা: মনে রাখবেন, আপনি যদি কোনও পটভূমির থ্রেডে ডেটাও লোড করে থাকেন তবে ওরিয়েন্টেশন পরিবর্তনের পরে অবস্থানটি পুনরুদ্ধার করার জন্য আপনাকে আপনার onPostExecute / onLoadFinished পদ্ধতিতে onRestoreInstanceState এ কল করতে হবে eg

@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
এটি পরিষ্কারভাবে সেরা উত্তর, কেন এটি গৃহীত হয় না? নোট করুন যে কোনও লেআউটম্যানেজারের এটি রয়েছে, কেবল লিনিয়ারলআউটআউট ম্যানেজারই নয়, গ্রিডলআউটআউট ম্যানেজারও রয়েছে এবং যদি এটি একটি মিথ্যা বাস্তবায়ন না হয়।
পল ওওয়েটশেখ

লিনিয়ারলআউটআমনেজ.আরআইনস্ট্যান্স স্টেট () সর্বদা নাল দেয় -> উত্স কোডটি পরীক্ষা করে। দুর্ভাগ্যক্রমে কাজ হচ্ছে না।
ভাগ্যবানদের

1
রিসাইক্লারভিউ কি তার নিজস্বআউটসেভস্ট্যান্টস্টেটে লেআউট ম্যানেজারটি সংরক্ষণ করে না? সমর্থন lib এর v24 তাকিয়ে ...
androidguy

3
এটি একক ক্ষেত্রে কাজ করে RecyclerViewতবে আপনার প্রতিটি পৃষ্ঠায় ViewPagerএকটি RecycerViewদিয়ে থাকে না।
ক্রিস বি

1
@ ইভান, আমি মনে করি এটি একটি খণ্ডে কাজ করে (কেবলমাত্র পরীক্ষা করা হয়েছে), তবে এতে নয় onCreateView, তবে ডেটা লোড হওয়ার পরে। এখানে @ ফার্মার উত্তরটি দেখুন।
কুলমাইন্ড

81

দোকান

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

প্রত্যর্পণ করা

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

এবং যদি এটি কাজ করে না, চেষ্টা করুন

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

স্টোর রাখুন onPause() এবং পুনরুদ্ধার করুনonResume()


এটি কাজ করে তবে এটি পুনরুদ্ধার lastFirstVisiblePositionকরার 0পরে আপনার পুনরায় সেট করতে হবে to এই ক্ষেত্রেটি কার্যকর যখন আপনার কোনও খণ্ড / ক্রিয়াকলাপ থাকে যা একটিতে বিভিন্ন ডেটা লোড করে RecyclerView, উদাহরণস্বরূপ, একটি ফাইল এক্সপ্লোরার অ্যাপ্লিকেশন।
ব্লুওয়্যার

অসাধারণ! এটি তালিকাতে বিশদ ক্রিয়াকলাপ থেকে ফিরে আসা এবং স্ক্রিন রোটেশনে রাষ্ট্র সংরক্ষণের উভয়কে সন্তুষ্ট করে
জাভি

আমার রিসাইক্লারভিউতে থাকলে কী করব SwipeRefreshLayout?
মরোজভ

2
প্রথম পুনরুদ্ধার বিকল্পটি কেন কাজ করবে না, তবে দ্বিতীয়টি করবে?
লুসিডব্রট

1
@ মেহরানজালীলি এটি দেখে মনে হচ্ছেRecyclerView
ভ্লাদ

22

আমার তালিকা ক্রিয়াকলাপ থেকে দূরে নেভিগেট করার সময় এবং পুনরায় নেভিগেট করতে ব্যাক বোতামটি ক্লিক করার সময় আমি রিসাইক্লার ভিউয়ের স্ক্রোল অবস্থানটি সংরক্ষণ করতে চেয়েছিলাম। এই সমস্যার জন্য সরবরাহ করা সমাধানগুলির মধ্যে অনেকগুলি প্রয়োজনের চেয়ে জটিল ছিল বা আমার কনফিগারেশনের জন্য কাজ করেনি, তাই আমি ভেবেছিলাম যে আমি আমার সমাধানটি ভাগ করব।

সবার আগে অনপস-এ আপনার উদাহরণের অবস্থাটি সংরক্ষণ করুন। আমি মনে করি এটি এখানে জোর দেওয়া উচিত যে onSaveInstanceState এর এই সংস্করণটি রিসাইক্লার ভিউ.লাইআউটম্যানেজার শ্রেণীর একটি পদ্ধতি।

private LinearLayoutManager mLayoutManager;
Parcelable state;

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

এটি সঠিকভাবে কাজ করার মূল চাবিকাঠিটি আপনার অ্যাডাপ্টার সংযুক্ত করার পরে আপনি রিস্টোরইনস্ট্যান্সস্টেটে কল করেছেন তা নিশ্চিত করা, যেমনটি অন্য থ্রেডে কিছু ইঙ্গিত করেছে। তবে প্রকৃত পদ্ধতি কলটি অনেকের ইঙ্গিতের চেয়ে সহজ।

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

1
এটাই সঠিক সমাধান। : ডি
আফজালুর রহমান রানা 15'19

1
আমার জন্য onSaveInstanceState বলা হয় না তাই অনপজ এ স্টিভিং স্টেট বলা ভাল বিকল্প হিসাবে মনে হয়। আমি খণ্ডটিতে ফিরে আসার জন্য ব্যাকস্ট্যাকটি পপিং করছি।
ফিলিটি_উইজার্ড

রাষ্ট্রের লোড জন্য। যা আমি ভিউক্রিয়েটেডে করি। এটি কেবলমাত্র ডিবাগ মোডে থাকা এবং ব্রেক পয়েন্টগুলি ব্যবহার করার সময় কাজ করবে বলে মনে হচ্ছে? বা যদি আমি একটি বিলম্ব যোগ করি এবং কার্যকর কর্টিনে রাখি।
ফিলিটি_উইজার্ড

21

আমি অনক্রিয়েট () এ ভেরিয়েবল সেট করি, অনপজ () এ স্ক্রোল অবস্থান সংরক্ষণ করি এবং অনারিউম () এ স্ক্রোল অবস্থান নির্ধারণ করি

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

আপনাকে আর নিজের দ্বারা রাষ্ট্র সংরক্ষণ এবং পুনরুদ্ধার করতে হবে না। আপনি যদি এক্সএমএল এবং পুনর্ব্যবহারযোগ্য ভিউ.সেটসেভ এনেবল (সত্য) (ডিফল্টরূপে সত্য) সিস্টেমে অনন্য আইডি সেট করেন তবে এটি স্বয়ংক্রিয়ভাবে এটি করবে। এখানে এটি সম্পর্কে আরও বিস্তারিত: http://trickyandroid.com/saving-android-view-state-correctly/


14

সমর্থন লাইব্রেরিতে বান্ডিল করা সমস্ত লেআউট পরিচালকরা স্ক্রোল অবস্থানটি কীভাবে সংরক্ষণ এবং পুনরুদ্ধার করবেন তা ইতিমধ্যে জানে।

নিম্নলিখিত শর্তগুলি পূরণ করার পরে ঘটে যাওয়া প্রথম লেআউট পাসে স্ক্রোল অবস্থানটি পুনরুদ্ধার করা হয়:

  • একটি লেআউট ম্যানেজার এর সাথে সংযুক্ত থাকে RecyclerView
  • একটি অ্যাডাপ্টার সংযুক্ত করা হয় RecyclerView

সাধারণত আপনি এক্সএমএলে লেআউট ম্যানেজারটি সেট করেন তাই এখন আপনাকে যা করতে হবে তা হ'ল

  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তার রাষ্ট্রের জন্য সংরক্ষিত করা।


এটা আমার জন্য ছিল। আমি অ্যাডাপ্টারটি প্রাথমিকভাবে সেট করে দিচ্ছিলাম তখন যখন পাওয়া যায় তখন তার ডেটা আপডেট করে। উপরে বর্ণিত হিসাবে, ডেটা উপলব্ধ না হওয়া অবধি এটিকে রেখে দেওয়া এটি স্বয়ংক্রিয়ভাবে যেখানে ছিল সেখানে স্ক্রোল করে।
নীলস

ধন্যবাদ ইউজেন লেআউটম্যানেজারের সংরক্ষণ এবং পুনরুদ্ধারের স্ক্রোল অবস্থান সম্পর্কিত কোনও ডকুমেন্টেশন আছে কি?
অ্যাডাম হুরউইটজ

@ অ্যাডামহুরউইজস আপনি কী ধরনের ডকুমেন্টেশন আশা করবেন? আমি যা বর্ণনা করেছি তা লিনিয়ারলআউটআউট ম্যানেজারের একটি বাস্তবায়ন বিশদ, সুতরাং এর উত্স কোডটি পড়ুন।
ইউজেন পেচানেক

1
এখানে লিঙ্কটি রয়েছে LinearLayoutManager.SavedState: cs.android.com/androidx/platform/frameworks/support/+/…
ইউজেন পেচানেক

ধন্যবাদ, @ ইউজেনপ্যাচেনেক এটি আমার জন্য ডিভাইস ঘোরানোর জন্য কাজ করেছিল। আমি নীচে নেভিগেশন ভিউটিও ব্যবহার করছি এবং আমি যখন অন্য নীচের ট্যাবে স্যুইচ করি এবং ফিরে আসি, তালিকাটি আবার শুরু থেকে শুরু হয়। কেন এটি সম্পর্কে কোনও ধারণা?
schv09

4

এগুলিকে বাঁচাতে এবং একটি খণ্ডে পুনর্ব্যবহারের অবস্থাটি বজায় রাখার জন্য আমার এই পদ্ধতিটি। প্রথমে নীচের কোড হিসাবে আপনার পিতামাতার ক্রিয়াকলাপে কনফিগার পরিবর্তনগুলি যুক্ত করুন।

android:configChanges="orientation|screenSize"

তারপরে আপনার খণ্ডে এই উদাহরণ পদ্ধতিটি ঘোষণা করুন

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

আপনার @ অনপেজ পদ্ধতিতে কোড নীচে যুক্ত করুন

@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 পদ্ধতি যুক্ত করুন।

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

এই অ্যাপ্রোচ আপনার সমস্যা পুনরায় শুরু করবে। আপনার যদি ভিন্ন লেআউট ম্যানেজার থাকে তবে কেবল উপরের লেআউট ম্যানেজারটি প্রতিস্থাপন করুন।


অবিরাম ডেটা রাখতে আপনার কোনও হ্যান্ডলারের প্রয়োজন নাও হতে পারে। লাইফাইকেল পদ্ধতিগুলি সংরক্ষণ / লোড করার জন্য পর্যাপ্ত পর্যাপ্ত হবে।
মাহি

@ সায়ামাহী আপনি কি সঠিক উপায়ে বর্ণনা করতে পারবেন? আমি এটিও দেখেছি যে অন-কনফিগারেশন পরিবর্তনটি ধ্বংস পদ্ধতিতে কল করতে বাধা দেয়। সুতরাং এটি কোনও সঠিক সমাধান নয়।
পবন কুমার শর্মার

3

ঘূর্ণনের পরে গ্রিডলাউটম্যানেজারের সাথে আমি যখন রিসাইক্লার ভিউ অবস্থানটি পুনরুদ্ধার করি তখন অ্যাসিঙ্কটাস্কলোডার দিয়ে আপনার যখন ইন্টারনেট থেকে ডেটা পুনরায় লোড করতে হয়।

পার্সেবল এবং গ্রিডলআউটআউট ম্যানেজার এবং একটি স্থির চূড়ান্ত স্ট্রিংয়ের একটি বিশ্বব্যাপী পরিবর্তনীয় করুন:

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

তারপরে লোডার যখন ইন্টারনেট থেকে ডেটা আনবে আপনি অন-এলএডফিনিশড () এ পুনর্ব্যবহারযোগ্য অবস্থানটি পুনরুদ্ধার করবেন

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

.. অবশ্যই আপনাকে onCreate এর মধ্যে গ্রিডলআউটআউট ম্যানেজার ইনস্ট্যান্ট করতে হবে। চিয়ার্স


3

আমার একই প্রয়োজনীয়তা ছিল, তবে পুনর্ব্যবহারযোগ্য ভিউর জন্য ডেটা উত্সের কারণে, সমাধানগুলি এখানে পুরোপুরি আমাকে পাইনি।

আমি রিপ্লেয়ারভিউ'স লিনিয়ারালআউটআউট ম্যানেজারের স্থিতির অনটিপস () এ বের করছি

private Parcelable state;

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

পার্সলেবল stateসংরক্ষণ করা হয় onSaveInstanceState(Bundle outState), এবং আবার onCreate(Bundle savedInstanceState)কখন এনে নেওয়া হয় savedInstanceState != null

তবে, রিসাইক্লারভিউ অ্যাডাপ্টারটি ভিউমোডেল লাইভ ডেটা অবজেক্টটি একটি ডেটাবেসে একটি ডিএও কল দিয়ে ফিরে আসা দ্বারা পপুলেটেড এবং আপডেট করা হয়।

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ডেটাবেস কল দ্বারা ডেটা ফিরিয়ে দেওয়া হলে আমি পুনরুদ্ধার করেছিলাম এমন রাষ্ট্রটি ওভাররাইট করা হয়েছিল, বা পুনরুদ্ধার করা রাষ্ট্রটি 'খালি' লিনিয়ারলআউটম্যানেজারের তুলনায় অর্থহীন ছিল।

যদি অ্যাডাপ্টারের ডেটা সরাসরি পাওয়া যায় (অর্থাত্ একটি ডাটাবেস কলের জন্য সন্তুষ্ট নয়), তবে লিনিয়ারলআউটম্যানেজারে উদাহরণস্বরূপ অবস্থার পুনরুদ্ধার করা পুনর্ব্যবহারযোগ্য ভিউতে অ্যাডাপ্টার সেট করার পরে করা যেতে পারে।

দুটি পরিস্থিতির মধ্যে পার্থক্য আমাকে যুগ যুগ ধরে ধরে রেখেছে।


3

অ্যান্ড্রয়েড এপিআই লেভেল ২৮ এ, আমি কেবলমাত্র আমার LinearLayoutManagerএবং RecyclerView.Adapterআমার Fragment#onCreateViewপদ্ধতিতে এবং কেবলমাত্র কাজ করা সমস্ত কিছুই সেটআপ করে তা নিশ্চিত করি ️ আমার কোনও কাজ onSaveInstanceStateবা onRestoreInstanceStateকাজ করার দরকার নেই ।

ইউজেন পেচানেকের উত্তর ব্যাখ্যা করে যে এটি কেন কাজ করে।


2

অ্যান্ড্রয়েডেক্স রিসাইক্লারভিউ লাইব্রেরির 1.2.0-alpha02 সংস্করণ থেকে শুরু করে, এটি এখন স্বয়ংক্রিয়ভাবে পরিচালিত হবে। কেবল এটির সাথে যুক্ত করুন:

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

আর ব্যবহার করুন:

adapter.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY

স্টেটরিস্টেরেশনপলিস এনামের 3 টি বিকল্প রয়েছে:

  • ALLOW - ডিফল্ট রাষ্ট্র, যা পরের লেআউটে পাসের সাথে সাথে রিসাইক্লারভিউ রাষ্ট্রটিকে তত্ক্ষণাত পুনরুদ্ধার করে
  • PREVENT_WHEN_EMPTY - অ্যাডাপ্টার ফাঁকা না থাকলে কেবল পুনর্ব্যক্তিকালীন অবস্থাটি পুনরুদ্ধার করে (অ্যাডাপ্টার.জেট আইটেমকাউন্ট ()> 0)। যদি আপনার ডেটা অ্যাসিঙ্ক লোড হয়, তবে রিসাইক্লারভিউ ডেটা লোড না হওয়া পর্যন্ত অপেক্ষা করে এবং কেবল তখনই রাষ্ট্রটি পুনরুদ্ধার করা হয়। আপনার অ্যাডাপ্টারের অংশ হিসাবে যদি আপনার ডিফল্ট আইটেমগুলি থাকে, যেমন শিরোনাম বা লোড অগ্রগতি সূচকগুলি থাকে তবে আপনার পূর্ববর্তী বিকল্পটি ব্যবহার করা উচিত, যদি না মার্জএডাপ্টার ব্যবহার করে ডিফল্ট আইটেমগুলি যুক্ত না করা হয় । MergeAdapter এর সমস্ত অ্যাডাপ্টার প্রস্তুত হওয়ার জন্য অপেক্ষা করে এবং কেবল তখনই এটি রাষ্ট্রটিকে পুনরুদ্ধার করে।
  • প্রতিরোধ - আপনি সমস্ত বা PREVENT_WHEN_EMPTY সেট না করা পর্যন্ত সমস্ত রাজ্য পুনরুদ্ধার স্থগিত করা হয়।

মনে রাখবেন যে এই উত্তরের সময়, রিসাইক্লারভিউ লাইব্রেরিটি এখনও আলফা 03 এ রয়েছে তবে আলফা ফেজ উত্পাদন উদ্দেশ্যে উপযুক্ত নয়


এত বেশি কাজের কাজ সাশ্রয় হয়েছে। অন্যথায় আমাদের তালিকার ক্লিক সূচি সংরক্ষণ করতে হবে, উপাদানগুলি পুনরুদ্ধার করতে হবে, অনক্রিটভিউতে পুনরায় আঁকানো রোধ করতে হবে, স্ক্রোলটোপজিশন প্রয়োগ করুন (বা অন্য উত্তর হিসাবে করুন) এবং তবুও ব্যবহারকারী ফিরে আসার পরে পার্থক্যটি লক্ষ্য করতে পারে
রাহুল কাহলে

এছাড়াও, আমি যদি অ্যাপের মাধ্যমে নেভিগেশনের পরে রিসাইক্লার ভিউ অবস্থানটি সংরক্ষণ করতে চাই ... তবে এর কোনও সরঞ্জাম আছে কি?
স্টিপুল

@ রুবেনভিগুয়েরা আলফা কেন উত্পাদনের উদ্দেশ্যে নয়? মানে আসলেই কি খারাপ?
স্টেইকুল

1

আমার জন্য সমস্যাটি হ'ল আমি যখনই আমার অ্যাডাপ্টারটি পরিবর্তন করেছি তখন রিসাইক্লারভিউতে কুই স্ক্রোল অবস্থানটি হারিয়ে আমি একটি নতুন লেআউট ম্যানেজার সেট করি।


1

আমি কেবল সাম্প্রতিক দুর্দশাগুলি পুনরায় ব্যবহারকারীর সাথে ভাগ করে নিতে চাই। আমি আশা করি একই সমস্যা যে কেউ উপকৃত হবে।

আমার প্রকল্পের প্রয়োজনীয়তা: সুতরাং আমার একটি পুনর্ব্যবহারযোগ্য ভিউ রয়েছে যা আমার মূল ক্রিয়াকলাপে (ক্রিয়াকলাপ-এ) কিছু ক্লিকযোগ্য আইটেমের তালিকা করে। আইটেমটি ক্লিক করা হলে আইটেমের বিশদ (ক্রিয়াকলাপ-বি) সহ একটি নতুন ক্রিয়াকলাপ দেখানো হয়।

আমি ম্যানিফেস্টে বাস্তবায়ন করেছি ফাইলে এটি যে ক্রিয়াকলাপ-এ ক্রিয়াকলাপ-বি এর পিতা-মাতা, সেইভাবে, অ্যাক্টিভিটি-বি এর অ্যাকশনবারে আমার একটি পিছনে বা হোম বোতাম আছে

সমস্যা: অ্যাক্টিভিটি-বি অ্যাকশনবারে যতবার আমি পিছনে বা হোম বোতাম টিপতাম ততবারই ক্রিয়াকলাপ-এ সম্পূর্ণ ক্রিয়াকলাপের লাইফ চক্রটিতে চলে যায় অনক্রিট () থেকে শুরু করে

যদিও আমি রিসাইক্লার ভিউ অ্যাডাপ্টারের তালিকা সংরক্ষণ করে একটি onSaveInstanceState () প্রয়োগ করেছি, যখন ক্রিয়াকলাপ-এ এটির জীবনচক্র শুরু করে, সেভইনস্ট্যান্সস্টেট সর্বদা অনক্রিট () পদ্ধতিতে বাতিল হয়।

ইন্টারনেটে আরও খনন করার পরে, আমি একই সমস্যাটি দেখতে পেয়েছি তবে ব্যক্তিটি লক্ষ্য করেছে যে অ্যানড্রয়েড ডিভাইসের নীচে পিছনে বা হোম বোতামটি (ডিফল্ট ব্যাক / হোম বোতাম) ক্রিয়াকলাপ-এ ক্রিয়াকলাপের জীবন চক্রের মধ্যে যায় না।

সমাধান:

  1. ক্রিয়াকলাপ-বিয়ের জন্য আমি ম্যানিফেস্টে পিতামাতার কার্যকলাপের জন্য ট্যাগ সরিয়েছি
  2. আমি ক্রিয়াকলাপ-বি তে হোম বা পিছনের বোতামটি সক্ষম করেছি

    অনক্রিয়েট () পদ্ধতির অধীনে এই লাইন সমর্থনঅ্যাকশনবার? .SetDisplayHomeAsUpEn सक्षम (সত্য) যোগ করুন

  3. ওপশনস আইটেমসিলিগ্রেটেড () পদ্ধতিতে ওভারাইড মজাদার ক্ষেত্রে আমি আইটেমটি যাচাই করেছি tem পিছনের বোতামটির আইডি হ'ল

    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

একটি সামান্য পার্থক্য নিয়ে আমার একই সমস্যা ছিল, আমি ডেটাবাইন্ডিং ব্যবহার করছিলাম এবং আমি বাধ্যতামূলক পদ্ধতিতে পুনর্ব্যবহারযোগ্য অ্যাডাপ্টার এবং লেআউট ম্যানেজারটি সেট করছিলাম।

সমস্যা হয়েছে যে ডেটা-বাঁধাই পর ঘটছে onResume তাই এটি onResume পর এবং তার মানে এটা মূল জায়গা প্রত্যেক সময় স্ক্রলিং ছিল আমার layoutManager রিসেট করা হয়। সুতরাং যখন আমি ডেটাবাইন্ডিং অ্যাডাপ্টার পদ্ধতিতে লেআউট ম্যানেজার সেট করা বন্ধ করে দিয়েছিলাম, এটি আবার ঠিকঠাক হয়ে যায়।


আপনি এটি কীভাবে অর্জন করেছেন?
কেদার সুকারকর

0

আমার ক্ষেত্রে আমি layoutManagerএক্সএমএল এবং ইন উভয়ই রিসাইক্লারভিউ সেট করেছিলাম onViewCreatedonViewCreatedনির্ধারিতভাবে অ্যাসাইনমেন্ট সরানো ।

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()মানে, অন্য কার্যকলাপ সুইচ onPause called.It যে স্ক্রোল অবস্থানে সংরক্ষণ করুন এবং অবস্থান যখন আমরা অন্য কার্যকলাপ থেকে ফিরে আসছে পুনরুদ্ধার করতে হবে হবে যদিও।


2
পাবলিক স্ট্যাটিক ক্ষেত্রটি ভাল নয়। গ্লোবাল ডেটা এবং সিলেটলেটগুলি ভাল নয়।
ওয়েস্টন

@ ওয়েস্টন আমি এখনই বুঝতে পেরেছি I বিশ্বব্যাপী অপসারণের জন্য আমি সেভস্টেটকে অনপজ এ পরিবর্তন করেছি।
স্টিভ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.