آموزش جاوا و اندروید

یادداشت های یک برنامه نویس معمولی

آموزش جاوا و اندروید

یادداشت های یک برنامه نویس معمولی

طبقه بندی موضوعی

آپدیت ریسایکلر ویو با DiffUtil

چهارشنبه, ۶ اسفند ۱۳۹۹، ۰۴:۱۵ ق.ظ

DiffUtil یک کلاسی هست که برای ریسایکلر ویو تعریف شده و به کمک اون میشه ریسایکلر ویو رو آپدیت کرد. تا قبل از این برای آپدیت ریسایکلر ویو از notifydatasetchanged استفاده می کردیم که هزینه زیادی داره، چون به ازای هر آیتم متدهای onCreateViewHolder و onBindViewHolder فراخونی می شوند. اما DiffUtil پرفورمنس بهتره داشته و انیمیشن قشنگی به آیتم ها می دهد.

یک کلاس جدید ایجاد کرده و آن را از DiffUtil.Callback اکستند می کنیم. کلاس DiffUtil.Callback، کلاسی ابسترکت بوده که چهار متد ابسترکت دارد که می بایست پیاده سازی شود. اوور راید کردن متد getChangePayload اختیاری است که در ادامه توضیح داده می شود. 

public class NoteDiffUtil extends DiffUtil.Callback {

    private final List<Note> oldNoteList;
    private final List<Note> newNoteList;

    public NoteDiffUtil(List<Note> oldNoteList, List<Note> newNoteList) {
        this.oldNoteList = oldNoteList;
        this.newNoteList = newNoteList;
    }

    @Override
    public int getOldListSize() {
        return oldNoteList.size();
    }

    @Override
    public int getNewListSize() {
        return newNoteList.size();
    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return oldNoteList.get(oldItemPosition).getId() == newNoteList.get(newItemPosition).getId();
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        return oldNoteList.get(oldItemPosition).getTitle().equals(newNoteList.get(newItemPosition).getTitle())
                &&
                oldNoteList.get(oldItemPosition).getDescription().equals(newNoteList.get(newItemPosition).getDescription())
                &&
                oldNoteList.get(oldItemPosition).getPriority() == newNoteList.get(newItemPosition).getPriority();
    }

    @Nullable
    @Override
    public Object getChangePayload(int oldItemPosition, int newItemPosition) {
        return super.getChangePayload(oldItemPosition, newItemPosition);
    }
}

این کلاس دو لیست (لیست جدید که آپدیت شده و لیست قدیمی) را می گیرد و آنها را با یکدیگر مقایسه می کند. اگر هر دو آیتم از لیست جدید و قدیمی با هم یکی باشند (برای مقایسه حتما باید از آی دی استفاده شود) متد areItemsTheSame مقدار true برمی گرداند.

اگر محتویات آنها نیز یکسان باشد متد areContentsTheSame مقدار true برمیگرداند و در نتیجه لیست تغییری نمی کند. اما اگر محتویات یکسان نباشد، متد areContentsTheSame مقدار false برگردانده و متد getChangePayload فراخونی می شود.

دریافت

حالا اگر توی یه آیتم فقط یه گزینه تغییر کرده باشه اگر متد getChangePayload رو اوور راید نکرده باشیم، کل اون ویو با آیتم جدید rebind میشه (یعنی اگر تکست و عکس داشته باشه و فقط تکست تغییر کرده باشه هم عکس و هم تکست مجدد لود میشه) و این خوب نیست. برای حل این مشکل متد getChangePayload رو به صورت زیر اوور راید میکنیم و در اداپتر صداش می کنیم.

 

    @Override
    public Object getChangePayload(int oldItemPosition, int newItemPosition) {        postingDetails oldItem = mOldPostingDetailsList.get(oldItemPosition);
        postingDetails newItem = mNewPostingDetailsList.get(newItemPosition);        Bundle diff = new Bundle();
        if (!newItem.getName().equals(oldItem.getName())) {
            diff.putString("name", newItem.getName());
        }
        if (!newItem.getAddress().equals(oldItem.getAddress())) {
            diff.putString("address", newItem.getAddress());
        }
        if (diff.size() == 0) {
            return null;
        }
        return diff;   
   }

 

و توی اداپتر علاوه بر متد onBindViewHolder معمولی این متد هم اضافه می شود:

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, List<Object> payloads) {    int viewType = getItemViewType(position);
    String p = null, s = null;
    if (payloads.isEmpty()) {
        super.onBindViewHolder(holder, position, payloads);
        return;
    } else {
        Bundle o = (Bundle) payloads.get(0);
        for (String key : o.keySet()) {
            if (key.equals("name")) {
                p = o.getString(key);
            }
            if (key.equals("address")) {
                s = o.getString(key);
            }
        }
    }

 

نحوه فراخونی DiffUtil در اداپتر ریسایکلر ویو: همون اداپتر قبلی، به اضافه متد بالا و متد پایین

private List<Note> notes = new ArrayList<>();

کد بالا در قسمت فیلد تعریف میشه. یعنی اول لیست خالی به ریسایکلر ویو پاس داده و بعد لیست جدید رو به متد پایین پاس می دهیم.

public void updateNoteList(List<Note> newNoteList) {
    NoteDiffUtil noteDiffUtil = new NoteDiffUtil(notes, newNoteList);
    DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(noteDiffUtil);
    notes.clear();
    notes.addAll(newNoteList);
    diffResult.dispatchUpdatesTo(this);
}

 

مدیوم 1 همراه با پیاده سازی به صورت RxJava

مدیوم 2

استک اور فلو

این خیلی خوبه

مثال سایت journaldev

 

موافقین ۰ مخالفین ۰ ۹۹/۱۲/۰۶
میم دال

نظرات  (۱)

سلام، تشکر از شما 🙏❤️

ارسال نظر

ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی