তালিকাআডাপ্টার রিসাইক্লারভিউতে আইটেম আপডেট করছে না


92

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

class ArtistsAdapter : ListAdapter<Artist, ArtistsAdapter.ViewHolder>(ArtistsDiff()) {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(parent.inflate(R.layout.item_artist))
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(getItem(position))
    }

    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        fun bind(artist: Artist) {
            itemView.artistDetails.text = artist.artistAlbums
                    .plus(" Albums")
                    .plus(" \u2022 ")
                    .plus(artist.artistTracks)
                    .plus(" Tracks")
            itemView.artistName.text = artist.artistCover
            itemView.artistCoverImage.loadURL(artist.artistCover)
        }
    }
}

আমি সাথে অ্যাডাপ্টার আপডেট করছি

musicViewModel.getAllArtists().observe(this, Observer {
            it?.let {
                artistAdapter.submitList(it)
            }
        })

আমার ডিফার ক্লাস

class ArtistsDiff : DiffUtil.ItemCallback<Artist>() {
    override fun areItemsTheSame(oldItem: Artist?, newItem: Artist?): Boolean {
        return oldItem?.artistId == newItem?.artistId
    }

    override fun areContentsTheSame(oldItem: Artist?, newItem: Artist?): Boolean {
        return oldItem == newItem
    }
}

সাবমিটলিস্টকে যখন প্রথমবার বলা হয় তখন অ্যাডাপ্টর সমস্ত আইটেমকে রেন্ডার করে, তবে সাবমিটলিস্টকে আবার আপডেট করা অবজেক্টের বৈশিষ্ট্য সহ কল ​​করা হয় যা পরিবর্তিত হয়েছে এমন দৃশ্যটি পুনরায় রেন্ডার করে না।

আমি তালিকাটি স্ক্রোল করার সাথে সাথে এটি ভিউটিকে পুনরায় রেন্ডার করে, যার ফলে কলগুলি ঘটে bindView()

এছাড়াও, আমি লক্ষ করেছি যে adapter.notifyDatasSetChanged()জমা দেওয়ার পরে কল করা আপডেটের সাথে মানকে রেন্ডার করে, তবে আমি কল করতে চাই না notifyDataSetChanged()কারণ তালিকা অ্যাডাপ্টারের অন্তর্নির্মিতের আলাদা আলাদা ব্যবহার রয়েছে

কেউ কি এখানে আমাকে সাহায্য করতে পারে?


সমস্যা সম্পর্কিত হতে পারে ArtistsDiffএবং এইভাবে এটি Artistনিজের প্রয়োগের ক্ষেত্রে ।
tynn

হ্যাঁ, আমিও এটি একই রকম মনে করি, তবে আমি এটি বিন্দু বলে মনে করতে পারি না
বীরেশ চরণতিমঠ

আপনি এটি ডিবাগ করতে পারেন বা লগের বিবৃতি যুক্ত করতে পারেন। এছাড়াও আপনি প্রশ্নের সাথে সম্পর্কিত কোড যুক্ত করতে পারেন।
tynn

এছাড়াও এই প্রশ্নের পরীক্ষা, আমি ভিন্নভাবে এটা মীমাংসিত stackoverflow.com/questions/58232606/...
MisterCat

উত্তর:


107

সম্পাদনা: আমি কেন বুঝতে পারি যে এটি কেন ঘটে তা আমার বক্তব্য নয়। আমার বক্তব্যটি হ'ল এটির পক্ষে কমপক্ষে একটি সতর্কতা দেওয়া বা notifyDataSetChanged()ফাংশনটি কল করা দরকার । কারণ স্পষ্টতই আমি submitList(...)একটি কারণে ফাংশন কল করছি । আমি নিশ্চিত যে লোকেরা ঘন্টাব্যাপী কী কী ভুল হয়েছে তা বের করার চেষ্টা করছে যতক্ষণ না তারা সাবমিটলিস্ট () নিঃশব্দভাবে কলটিকে উপেক্ষা করে।

এটি Googleঅদ্ভুত যুক্তির কারণে। সুতরাং আপনি যদি অ্যাডাপ্টারে একই তালিকাটি পাস করেন তবে এটি কলও করে না DiffUtil

public void submitList(final List<T> newList) {
    if (newList == mList) {
        // nothing to do
        return;
    }
....
}

ListAdapterযদি এটি একই তালিকায় পরিবর্তনগুলি পরিচালনা করতে না পারে তবে আমি পুরো বিষয়টি বুঝতে পারি না । আপনি যে তালিকায় পাস করেছেন সেই আইটেমগুলি যদি আপনি পরিবর্তন করতে চান এবং পরিবর্তনগুলি ListAdapterদেখতে চান তবে হয় আপনাকে তালিকার একটি গভীর অনুলিপি তৈরি করতে হবে অথবা RecyclerViewআপনার নিজের DiffUtillশ্রেণীর সাথে নিয়মিত ব্যবহারের প্রয়োজন ।


4
কারণ এটি পূর্ববর্তী রাষ্ট্রটির পার্থক্য সম্পাদনের প্রয়োজন। আপনি যদি পূর্বের অবস্থাটি ওভাররাইট করে তবে অবশ্যই এটি পরিচালনা করতে পারে না। O_o
EpicPandaForce

34
হ্যাঁ তবে এই মুহুর্তে, আমি কল করার কারণ আছে কেন submitList? এটি notifyDataSetChanged()নিঃশব্দে কলটিকে উপেক্ষা করার পরিবর্তে কল করা উচিত । আমি নিশ্চিত যে লোকে submitList()চুপচাপ কলটিকে উপেক্ষা না করে লোকেরা কয়েক ঘন্টার জন্য কী ভুল হয়েছে তা বের করার চেষ্টা করছে am
insa_c

6
তাই আমি ফিরে আছি RecyclerView.Adapter<VH>এবং notifyDataSetChanged()। LIfe এখন ভাল। বেশ কয়েক ঘন্টা সময় নষ্ট
উদয়াদিত্য বড়ুয়া

4
@insa_c আপনি আপনার গণনায় 3 ঘন্টা যোগ করতে পারেন, আমার লিডভিউটি কেন কিছু প্রান্তের ক্ষেত্রে আপডেট হচ্ছে না তা বোঝার চেষ্টা করে কতটা নষ্ট করেছি ...
বেনক্রি

4
notifyDataSetChanged()ব্যয়বহুল এবং এটি একটি ডিফুটিল ভিত্তিক প্রয়োগকরণের পয়েন্টটিকে পুরোপুরি পরাভূত করবে। আপনি submitListকেবলমাত্র নতুন ডেটা দিয়ে কল করতে সাবধান এবং লক্ষ্যবান হতে পারেন , তবে সত্যই এটি কেবল একটি পারফরম্যান্স ফাঁদে।
ডেভিড লিউ

62

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

গৃহীত উত্তর সঠিক, এটি ব্যাখ্যা সরবরাহ করে তবে সমাধান নয় not

আপনি যদি এরকম কোনও লাইব্রেরি ব্যবহার না করেন তবে আপনি যা করতে পারেন তা হ'ল:

submitList(null);
submitList(myList);

আর একটি সমাধান হ'ল সাবমিস্টলিস্ট (যা দ্রুত পলকের কারণ হয় না) ওভাররাইড করা হবে:

@Override
public void submitList(final List<Author> list) {
    super.submitList(list != null ? new ArrayList<>(list) : null);
}

বা কোটলিন কোড সহ:

override fun submitList(list: List<CatItem>?) {
    super.submitList(list?.let { ArrayList(it) })
}

প্রশ্নযুক্ত যুক্তি কিন্তু পুরোপুরি কাজ করে। আমার পছন্দের পদ্ধতিটি দ্বিতীয়টি কারণ এটি প্রতিটি সারিটিকে অনবিন্দ কল পাওয়ার কারণ করে না।


7
এটি একটি হ্যাক। কেবল তালিকার একটি অনুলিপি পাস করুন। .submitList(new ArrayList(list))
পল ওউইটাসেকেক

4
আমি আমার যুক্তি দিয়ে সমস্যাটি কী তা বোঝার চেষ্টা করতে শেষ ঘন্টাটি ব্যয় করেছি। এমন এক অদ্ভুত যুক্তি।
জেরি ওকাফোর

7
@ পোলওয়েটাসচেখ এটি কোনও হ্যাক নয়, এটি জাভা ব্যবহার করছে :) এটি এমন লাইব্রেরিগুলিতে অনেক সমস্যা সমাধানের জন্য ব্যবহৃত হয় যেখানে বিকাশকারী "ঘুমাচ্ছেন"। আপনি কেন সাবমিটলিস্ট (নতুন অ্যারেলিস্ট (তালিকা)) পাস করার পরিবর্তে এটি বেছে নেওয়ার কারণ হ'ল আপনি আপনার কোডে একাধিক স্থানে তালিকা জমা দিতে পারেন। আপনি প্রতিবার একটি নতুন অ্যারে তৈরি করতে ভুলে যেতে পারেন, এজন্য আপনি ওভাররাইড করে।
আরজেফারেস

4
এমনকি রুম ব্যবহার করার পরেও আমি একই ধরণের সমস্যায় পড়ছি।
বিনচ

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

23

কোটলিনের সাথে আপনার নিজের তালিকা অনুসারে আপনার তালিকাটিকে নতুন মিউটেবললিস্টে রূপান্তর করতে হবে বা আপনার ব্যবহার অনুযায়ী তালিকার অন্য ধরণের

.observe(this, Observer {
            adapter.submitList(it?.toMutableList())
        })

এটি অদ্ভুত তবে তালিকাকে পরিবর্তনযোগ্য তালিকায় রূপান্তর করা আমার পক্ষে কাজ করে। ধন্যবাদ!
থানহ-নহন এনগুইন

4
কেন জাহান্নামে এই কাজ করছে? এটি কাজ করে তবে খুব কৌতূহল কেন এটি ঘটে।
March3April4

আমার মতে, লিস্টএডাপ্টার অবশ্যই আপনার তালিকা রেফারেন্স সম্পর্কে না করে, তাই এটি বুদ্ধিমান?? পরিবর্তনযোগ্য তালিকা () আপনি অ্যাডাপ্টারে একটি নতুন উদাহরণ তালিকা জমা দিন। আমি আশা করি এটি আপনার পক্ষে যথেষ্ট পরিস্কার। @
মিনা সমীর

ধন্যবাদ আপনার মন্তব্য অনুসারে, আমি অনুমান করেছি যে তালিকাআডাপ্টার এটি তালিকা <T> এর ফর্ম হিসাবে এটি ডেটাসেট গ্রহণ করে, যা একটি পরিবর্তনীয় তালিকা, এমনকি একটি অপরিবর্তনীয় তালিকা হতে পারে। যদি আমি একটি অপরিবর্তনীয় তালিকা পাস করি তবে আমি যে পরিবর্তনগুলি করেছি তা ডেটাসেট নিজেই ব্লক করে দিচ্ছে, তালিকাডাডাপ্টার দ্বারা নয়।
March3April4

আমি মনে করি আপনি এটি @ মার্চ 3 এপ্রিল 4 পেয়েছেন, এছাড়াও, আপনি বিভিন্ন ব্যবহারের সাথে যে পদ্ধতিটি ব্যবহার করেন সে সম্পর্কে যত্নশীল কারণ এটিরও দায়বদ্ধতা রয়েছে তালিকার আইটেমগুলি পরিবর্তন করা উচিত কিনা তা গণনা করবে;)
মিনা সমীর

10

আমার অনুরূপ সমস্যা ছিল তবে ভুল রেন্ডারিংটি setHasFixedSize(true)এবং এর সংমিশ্রণের কারণে হয়েছিল android:layout_height="wrap_content"। প্রথমবারের মতো অ্যাডাপ্টারের একটি খালি তালিকা সরবরাহ করা হয়েছিল যাতে উচ্চতা কখনই আপডেট হয় না এবং হয় 0। যাইহোক, এটি আমার সমস্যাটিকে পুনঃস্থাপন করেছে। অন্য কারওরও একই সমস্যা হতে পারে এবং এটি অ্যাডাপ্টারে সমস্যা বলে মনে করবে।


4
হ্যাঁ, রিসাইক্যভিউটি মোড়কে সেট করুন তালিকাটি আপডেট করবে, আপনি যদি এটি ম্যাচ-প্যারেন্টে সেট করেন তবে এটি অ্যাডাপ্টারের কল করবে না
এক্সেল স্ট্যাডারলিন

5

আজ আমি এই "সমস্যা" নিয়ে হোঁচট খেয়েছি। সাহায্যে insa_c এর উত্তর এবং RJFares এর সমাধান আমি নিজেই একটি Kotlin এক্সটেনশন ফাংশন তৈরি করেছেন:

/**
 * Update the [RecyclerView]'s [ListAdapter] with the provided list of items.
 *
 * Originally, [ListAdapter] will not update the view if the provided list is the same as
 * currently loaded one. This is by design as otherwise the provided DiffUtil.ItemCallback<T>
 * could never work - the [ListAdapter] must have the previous list if items to compare new
 * ones to using provided diff callback.
 * However, it's very convenient to call [ListAdapter.submitList] with the same list and expect
 * the view to be updated. This extension function handles this case by making a copy of the
 * list if the provided list is the same instance as currently loaded one.
 *
 * For more info see 'RJFares' and 'insa_c' answers on
 * /programming/49726385/listadapter-not-updating-item-in-reyclerview
 */
fun <T, VH : RecyclerView.ViewHolder> ListAdapter<T, VH>.updateList(list: List<T>?) {
    // ListAdapter<>.submitList() contains (stripped):
    //  if (newList == mList) {
    //      // nothing to do
    //      return;
    //  }
    this.submitList(if (list == this.currentList) list.toList() else list)
}

যা এর পরে যে কোনও জায়গায় ব্যবহার করা যেতে পারে, যেমন:

viewModel.foundDevices.observe(this, Observer {
    binding.recyclerViewDevices.adapter.updateList(it)
})

এবং এটি কেবলমাত্র (এবং সর্বদা) তালিকাটি অনুলিপি করে যদি এটি বর্তমানে লোড হওয়া হিসাবে একই থাকে।


5

ব্যবহার করার সময় যদি কিছু সমস্যার মুখোমুখি হন

recycler_view.setHasFixedSize(true)

আপনার অবশ্যই এই মন্তব্যটি অবশ্যই পরীক্ষা করা উচিত: https://github.com/thoughtbot/expandable-recycler-view/issues/53#issuecomment-362991531

এটি আমার পক্ষে বিষয়টি সমাধান করেছে।

(অনুরোধ অনুযায়ী মন্তব্যটির স্ক্রিনশট এখানে দেওয়া হয়েছে)

এখানে চিত্র বর্ণনা লিখুন


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

3

সরকারী দস্তাবেজ অনুসারে :

আপনি যখনই সাবমিটলিস্টকে কল করবেন তখন এটি আলাদা এবং প্রদর্শিত হওয়ার জন্য একটি নতুন তালিকা জমা দেয় ।

এ কারণেই আপনি যখনই পূর্ববর্তীটিতে (ইতিমধ্যে জমা দেওয়া তালিকা) সাবমিস্টলিস্ট কল করবেন তখন এটি ডিফটি গণনা করে না এবং ডেটাসেটে পরিবর্তনের জন্য অ্যাডাপ্টারকে অবহিত করে না


3

আমার ক্ষেত্রে আমি সেট করতে ভুলে গেছি LayoutManagerজন্য RecyclerView। তার প্রভাব উপরে বর্ণিত হিসাবে একই।


2

আমার জন্য, আমি যদি ব্যবহার করছিলেন এই সমস্যা হাজির RecyclerViewভেতরে ScrollViewসঙ্গে nestedScrollingEnabled="false"এবং আরভি উচ্চতাকে এতে সেট wrap_content
অ্যাডাপ্টারটি সঠিকভাবে আপডেট হয়েছে এবং বাইন্ড ফাংশনটি কল করা হয়েছিল, তবে আইটেমগুলি প্রদর্শিত হয়নি - এটি RecyclerViewতার 'মূল আকারে আটকে গিয়েছিল।

পরিবর্তন ScrollViewকরা হচ্ছেNestedScrollViewইস্যু স্থির করতে ।


2

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

    override fun areContentsTheSame(oldItem: Artist?, newItem: Artist?): Boolean {
    return oldItem == newItem
}

এই ফাংশনটি (সম্ভাব্য) লেবেলে যা বলা আছে তা করে না: এটি দুটি আইটেমের সামগ্রীর সাথে তুলনা করে না - যদি না আপনি ক্লাসে equals()ফাংশনটি ওভাররাইড না করে থাকেন Artist। আমার ক্ষেত্রে, আমার ছিল না, এবং এটি areContentsTheSameপ্রয়োগ করার সময় আমার তদারকির কারণে শুধুমাত্র প্রয়োজনীয় ক্ষেত্রগুলির মধ্যে একটির সংজ্ঞা ছিল । এটি কাঠামোগত সাম্যতা বনাম রেফারেনশিয়াল সমতা, আপনি এটি সম্পর্কে এখানে আরও জানতে পারেন


1

যার দৃশ্যপট আমার মত একই, আমি আমার সমাধানটি রেখে চলেছি, যা আমি জানি না কেন এটি কাজ করছে, এখানে।

আমার পক্ষে যে সমাধানটি কাজ করেছিল তা হ'ল @ মিনা সমীরের থেকে, যা তালিকাকে পরিবর্তনীয় তালিকা হিসাবে জমা দিচ্ছে।

আমার ইস্যু দৃশ্য:

-খণ্ডার ভিতরে একটি বন্ধু তালিকা লোড হচ্ছে।

  1. অ্যাক্টিভিটি মেইন ফ্র্যাগমেন্টফ্রেন্ডলিস্ট সংযুক্ত করে (ফ্রেন্ড ডিবি আইটেমগুলির লাইভেটাকে পর্যবেক্ষণ করে) এবং একই সাথে আমার সমস্ত বন্ধুর তালিকা পেতে সার্ভারে একটি http অনুরোধ জানায়।

  2. HTTP সার্ভার থেকে আইটেমগুলি আপডেট বা সন্নিবেশ করান।

  3. প্রতিটি পরিবর্তন লাইভাতার অন-চেঞ্জড কলব্যাককে জ্বলিত করে। তবে, যখন আমার প্রথমবার অ্যাপ্লিকেশনটি চালু করা হচ্ছে, যার অর্থ আমার টেবিলে কিছুই ছিল না, সাবমিটলিস্ট কোনও ধরণের ত্রুটি ছাড়াই সফল হয়, তবে স্ক্রিনে কিছুই উপস্থিত হয় না।

  4. যাইহোক, আমার দ্বিতীয়বার অ্যাপ্লিকেশনটি চালু করার সময়, স্ক্রিনে ডেটা লোড হচ্ছে।

সমাধানটি হ'ল, উপরে বর্ণিত হিসাবে, মিউটেবললিস্ট হিসাবে তালিকাটি জমা দেওয়া।


1

আপনার লিস্টএডাপ্টার। সাবমিস্টলিস্ট না বলা কারণ হ'ল আপনি আপডেট করা অবজেক্টটি মেমরিতে এখনও একই ঠিকানা রাখে।

আপনি যখন কোনও অবজেক্টের সাথে আপডেট করেন তখন .setText বলতে দেয় এটি আসল বস্তুর মান পরিবর্তন করে।

যাতে আপনি যখন যাচাই করেন তখন .জেক্ট.আইড == অবজেক্ট 2.id এটি একই হিসাবে ফিরে আসবে কারণ মেমরিতে একই স্থানের জন্য উভয়েরই একটি উল্লেখ রয়েছে।

সমাধানটি হ'ল আপডেট হওয়া ডেটা দিয়ে একটি নতুন অবজেক্ট তৈরি করা এবং এটি আপনার তালিকায় .োকানো। তারপরে সাবমিস্টলিস্ট ডাকা হবে এবং এটি সঠিকভাবে কাজ করবে


0

আমার আমার ডিফুটিলগুলি সংশোধন করা দরকার

override fun areContentsTheSame(oldItem: Vehicle, newItem: Vehicle): Boolean {

বিষয়বস্তুগুলি নতুন কিনা তা আসলে ফিরে আসার জন্য, কেবলমাত্র মডেলের আইডি তুলনা করুন।


0

@ আরজেফারেস ব্যবহার করে প্রথম উত্তর সফলভাবে তালিকাকে আপডেট করে তবে স্ক্রোলের স্থিতি বজায় রাখে না। সম্পূর্ণ RecyclerView0 তম অবস্থান থেকে শুরু হয়। কার্যকারণ হিসাবে, আমি এটিই করেছি:

   fun updateDataList(newList:List<String>){ //new list from DB or Network

     val tempList = dataList.toMutableList() // dataList is the old list
     tempList.addAll(newList)
     listAdapter.submitList(tempList) // Recyclerview Adapter Instance
     dataList = tempList

   }

এইভাবে, আমি RecyclerViewপরিবর্তিত ডেটা সহ স্ক্রোলের অবস্থা বজায় রাখতে সক্ষম ।

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