برای اینکه متوجه بشید که چرا اصلن این اتفاق می افته، باید با ساز و کار 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);
}
});