PDA

View Full Version : اعمال نشدن هر گونه تغییری در هر آیتم از RecyclerView هنگام اسکرول به پایین و بالا



mahmood.m
یک شنبه 14 آبان 1396, 00:06 صبح
با سلام و خسته نباشید خدمت دوستان

یه برنامه ای دارم که داده هارو از سرور میگیرم و در ریسایکلرویو نمایش میدم و این ریسایکلر ویوم چندین سطر داره و هر سطر از این ریسایکلر ویو دارای یه TextView و یه ImageView هست و برای این ImageView یه رویداد کلیک گذاشتم که وقتی کلیک شد مقدار داخل TextView آپدیت بشه و تصویر ImageView هم تغییر کند و حالا مشکلی که هست زمانی که روی ImageView کلیک میکنم همه چی اوکیه و تغییرات اعمال میشه ولی وقتی اسکرول میکنم به سمت پایین و بعد اسکرول میکنم به سمت بالا و برمیگردم به آیتم یا آیتم های مورد نظر انگاری هیچ تغییری انجام نشده و هر کدوم از آیتم ها برمیگردن به مقادیر اولیه که قبلا به هر آیتم از ریسایکلر ویو اختصاص دادم و زمانی که صفحه رو رفرش میکنم و دوباره اطلاعات رو میگرم و نمایش میدم تغییرات برای آیتم های مورد نظر اعمال میشه ولی میخوام آیتمی که مقدارشو تغییر میدم همون لحظه تغییرات اعمال بشه و با اسکرول به پایین و بالا هم مشکلی پیش نیاد.

ان شاء الله که درست منظورمو رسونده باشم
منتظر جواباتون هستم
منو زیاد منتظر نذارید چون واقعا خیلی وقته درگیر این موضوع شدم هر کی هر چی میدونه بگه
پیشاپیش ممنون

mz6488
یک شنبه 14 آبان 1396, 07:29 صبح
سلام.تو کلاس اصلی تون بعد هر تغییر کد زیر رو قرار بدید.اگه باز مشکل تون حل نشد کل های این قسمت رو اینجا بذارید

adapter.notifyDataSetChanged();

mahmood.m
یک شنبه 14 آبان 1396, 10:22 صبح
سلام خیلی ممنون
تغییرات رو داخل کلاس اصلی انجام نمیدم داخل کلاس آداپتر این کارو میکنم و کدی که قرار دادید رو با کمی تغییر داخل کلاس آداپر بعد از این که ImageView کلیک شد گذاشتم به این صورت:

adapter.this.notifyDataSetChanged();

اما مشکل جدیدی که به وجود اومده نه مقدار TextView تغییر میکنه و نه تصویر ImageView خلاصه هیچ کاری انجام نمیشه ولی صفحه رو که رفرش میکنم تغییرات اعمال شده اما این اون چیزی نیست که میخواستم

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

mz6488
یک شنبه 14 آبان 1396, 14:24 عصر
کلاس آداپتور رو به صورت public تعریف کنید ببینید چی میشه.خودم واس عملیات از لیست ویو سفارشی استفاده میکنم فقط واس نمایش های خاص از ریسایکل.تو آداپتر لیست ویو اومدم آبجکت آداپتر رو به صورت پابلیک تعریف کردم و همیشه جواب میده.

mahmood.m
یک شنبه 14 آبان 1396, 22:12 عصر
با سلام

خیلی ممنون از پاسخگویی
منظورتونو از این جمله که گفتید کلاس آداپتور رو به صورت public تعریف کنید رو متوجه نشدم
شاید بنده خیلی واضح و روشن منظورمو نرسوندم که دقیقا چی میخوام مثال میزنم مثلا:
برنامه های اجتماعی زیادی رو حتما دیدید که آیتم لیستشون از چندین View تشکیل شده که من به بقیه کاری ندارم وحالا یه آیکون ستاره و یا قلب هم داره که وقتی روش کلیک میکینم تعداد پسندیده شده ها یه شماره میره بالا و آیکون ستاره و یا قلب هم به یه رنگ دیگه و یا تو پر میشه و با اسکرول به پایین و بالا هم تغییرات انجام شده از بین نمیره و منم دقیقا همینو میخوام.

ان شاء الله که ایندفه دیگه درست منظورمو رسونده باشم
اگه شما و یا دوستان اگه اطلاعی در این خصوص دارین ممنون میشم خیلی سریع جواب بدید چون واقعا این موضوع دیگه خستم کرده هر جایی سر زدم و هر کاری کردم اما نشد

mz6488
دوشنبه 15 آبان 1396, 11:22 صبح
منظورتون رو موجه شده بودم.یه نمونه کوچیک میذارم ولی واس لیست ویو که فکر نکنم فرقی با ریسایکل داشته باشه
فرض کنید یه کلاس داریم که کارش نمایش آیتم ها باشه.داخل همین کلاس میام کلاس آداپتورم رو درست میکنم.حالا تنها کاری که باید انجام بدم این که نمونه کلاس آداپتور تو کلاس بالایی و خارج متد عملیات باشه

public class show_list{

adapter ad;

void ops{
//code
.
.
.
ad.notifyDataSetChanged();
}

private class ad extends ArrayAdapter<String> {
//codes

}

}

Nevercom
دوشنبه 15 آبان 1396, 16:33 عصر
برای اینکه متوجه بشید که چرا اصلن این اتفاق می افته، باید با ساز و کار ListView و RecyclerView آشنا بشید.

لیست ها برای اینکه عملکرد بهتری در نمایش آیتم ها داشته باشن، همه‌ی آیتم ها رو در حافظه نگهداری نمیکنن، درعوض فقط تعدادی که در صفحه دیده میشه رو نگهداری می کنن. مثلن اگه شما ۱۰۰ آیتم برای نمایش داشته باشی و فقط ۱۰ تاشون در هر لحظه قابل دیدن هستن، Adapter شاید ۱۳ تاشون رو در حافظه نگهداری کنه.

علاوه بر این چون عملیات رندر کردن زمان زیادی می‌بره، هربار که متد getView (یا onBindViewHolder در RecyclerView) صدا زده میشه، Viewی که در مرحله‌ی قبل تولید شده رو برای شما پس میفرسته تا اگر لایه تغییری نکرده، از همون استفاده کنی و دوباره لازم نباشه Inflate کنی و سایر چیزای مرتبط بهش.

حالا با این تفاسیر، اگه شما تا آیتم ۳۰ام رفته باشی و بخوای بیای آیتم ۵ام رو ببینی چه اتفاقی می افته ؟

می‌دونیم که اون Viewای قبلن ۵ رو نمایش می‌داده که دیگه تو حافظه نیست، پس ادپتر میاد و متد getView رو اجرا می‌کنه تا دوبار رسمش کنی، و برای اینکه دوباره کاری نشه، آخرین Viewی که رندر کرده هم واست میفرسته.
شما هم تو اون متد بر اساس position میای و اطلاعات رو می‌خونی و View رو رسم می کنی. باید واضح باشه که چون از ابتدا داری رسم می کنی، تغییراتی که قبلن دادی دیگه لحاظ نمیشه و نتیجه این هست که وقتی اسکرول می کنی میا ی بالا میبینی که متن، همون قبلیه هست.

برای حل این مشکل شما باید تغییراتی که در وضعیت آیتم می‌دی رو توی داده هایی که ادپتر ازش تغذیه می کنه هم لحاظ کنی.

فرض کنیم در موردی که شما مطرح کردین، دیتای ادپتر از جنس <List<Item هست.


private List<Item> list;

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



public class Item {
private String imageUrl;
private String text;

public String getImageUrl() {
return imageUrl;
}

public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}

public String getText() {
return text;
}

public void setText(String text) {
this.text = text;
}
}

در این حالت، برای نمایش هر آیتم اول دیتای اون رو از لیست استخراج می کنید:


Item item = list.get(position);

و بعد عکس و متن رو نمایش می‌دید. حالا با کلیک روی عکس متن در TextView تغییر می کنه، اما این تغییر در list منعکس نشده، پس اگر بار دیگه متد getView اجرا بشه تا اون ایتم خاص دوباره رسم بشه، تغییرات قبلی از دست میره.

در این مرحله تنها کاری که لازمه انجام بدید این هست که تغییرات رو در list هم منعکس کنید:



final Item item = list.get(position);
img.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {

String text = "New Text";
// Change the text of the TextView
textView.setText(text);
// Change the Item Accordingly
item.setText(text);
// Update the List
list.set(position, item);
}
});

mahmood.m
دوشنبه 15 آبان 1396, 20:14 عصر
با سلام

ممنون از دوستان واقعا ممنونم
خدا خیرتون بده