วิธีรีเฟรชมุมมองรายการ Android?


436

จะรีเฟรช Android ListViewหลังจากเพิ่ม / ลบข้อมูลไดนามิกได้อย่างไร


3
หากวิธีการอื่นไม่ได้ผลให้ลอง refreshDrawableState Props ถึงstackoverflow.com/questions/5186359/…
Edwin Evans

อาจช่วยคุณstackoverflow.com/a/17333384/596555
boiledwater

ตัวอย่างที่นี่tutorialkart.com/kotlin-android/…อาจช่วยคุณได้
Mallikarjun M

คำตอบ:


530

โทรหาวัตถุnotifyDataSetChanged()ของคุณAdapterเมื่อคุณแก้ไขข้อมูลในอะแดปเตอร์นั้น

ข้อมูลจำเพาะเพิ่มเติมบางประการเกี่ยวกับวิธีการ / เวลาในการโทรnotifyDataSetChanged()สามารถดูได้ในวิดีโอ Google I / Oนี้


24
คุณควรรันบนเธรด UI สร้างตัวจัดการภายในเธรด UI จากนั้นโพสต์ Runable ไปได้
Kirill Kulakov

11
อีกครั้ง: alertDataSetChanged () ไม่ทำงานอย่างน้อยไม่ใช่สำหรับการใช้งานที่ได้รับการแนะนำอีกครั้ง (อ่านไม่คัดค้าน) หากใช้ listview, เคอร์เซอร์อะแดปเตอร์และผู้ให้บริการเนื้อหาคุณอาจลองบางสิ่งตามบรรทัด: gettLoaderManager (). restartLoader () ดู: stackoverflow.com/a/19657500/1087411ฉันต้องการดูเอกสารบางอย่างเกี่ยวกับ alertDataSetChanged () มากใน Android ถูกทิ้งให้ทดสอบกล่องดำ
Anderson

หาก AlertDataSetChanged ใช้งานไม่ได้แสดงว่าคุณเป็นคนที่ทำผิด
zdarsky.peter

4
NotificationDataSetChanged อาจไม่ทำงานเสมอไป ฉันไม่แน่ใจว่าทำไมการโต้แย้งนี้ถึงเกิดขึ้น บางครั้งคุณต้องเรียก listView.setAdapter (อะแดปเตอร์) เพื่อล้างมุมมองเก่า ดูเพิ่มเติมที่: stackoverflow.com/a/16261588/153275

1
ฉันไม่สามารถรับการแจ้งเตือน DataSetChanged ได้ ฉันสามารถเห็นได้อย่างชัดเจนว่าคอลเลกชันที่ฉันป้อนไปยังอะแดปเตอร์มีการเปลี่ยนแปลง (องค์ประกอบถูกลบ) แต่แจ้งเตือน DataSetChanged ไม่เคยทำอะไรเลย ไม่แน่ใจว่าวิธีนี้ใช้งานไม่ได้หรือไม่
byemute

204

นอกจากนี้คุณสามารถใช้สิ่งนี้:

myListView.invalidateViews();

22
นี่คือคำตอบที่ถูกต้องหากต้องการเรียกดูอีกครั้ง ตัวอย่างเช่นหลังจากการล็อกอินของผู้ใช้เกิดขึ้นซึ่งจำเป็นต้องเปิดเผยข้อมูลเพิ่มเติมหรือตัวเลือกเพิ่มเติมภายในแต่ละมุมมองของ listView นั่นคือสิ่งที่ฉันต้องทำดังนั้นให้ขึ้นคะแนน หากการเปลี่ยนแปลงข้อมูลพื้นฐานอาจเป็นความคิดที่ดีกว่าถ้าจะใช้ alertDataSetChanged ()
SBerg413

อันที่จริงinvalidateViews()ในชุดรหัสที่มาmDataChanged = true;ดังนั้นผมไม่แน่ใจว่าถ้าผลในประสิทธิภาพที่ดีขึ้นเมื่อเทียบกับnotifyDataSetChanged()
vovahost

คุณบันทึกวันของฉันเพื่อน!
oskarko

คุณสามารถใช้ประเภทของรายการซึ่งเป็น "รายการที่สามารถสังเกตได้" ไม่จำเป็นต้องแจ้งเปลี่ยนชุดข้อมูล
Priya

153

โปรดละเว้นทั้งหมดinvalidate(), invalidateViews(), requestLayout()... คำตอบของคำถามนี้

สิ่งที่ถูกต้องที่จะทำ (และโชคดีที่ยังมีการทำเครื่องหมายเป็นคำตอบที่เหมาะสม) เป็นที่จะเรียกnotifyDataSetChanged()ในอะแดปเตอร์ของคุณ

การแก้ไขปัญหา

หากการโทรnotifyDataSetChanged()ไม่ทำงานวิธีการจัดวางทั้งหมดจะไม่ช่วยได้เช่นกัน เชื่อฉันListViewได้รับการปรับปรุงอย่างถูกต้อง หากคุณไม่พบความแตกต่างคุณต้องตรวจสอบว่าข้อมูลในอะแดปเตอร์ของคุณมาจากที่ใด

ถ้านี่เป็นเพียงการเก็บรวบรวมรักษาคุณกำลังในการตรวจสอบหน่วยความจำที่คุณลบจริงหรือเพิ่มรายการ (s) notifyDataSetChanged()เพื่อการเก็บรวบรวมก่อนที่จะเรียก

หากคุณกำลังทำงานกับฐานข้อมูลหรือบริการแบ็กเอนด์ที่คุณจะต้องโทรหาวิธีการที่จะดึงข้อมูลใหม่อีกครั้ง (หรือจัดการในข้อมูลหน่วยความจำ) notifyDataSetChanged()ก่อนที่จะเรียก

สิ่งนี้notifyDataSetChangedใช้งานได้ก็ต่อเมื่อชุดข้อมูลมีการเปลี่ยนแปลง นั่นคือสถานที่ที่จะดูว่าคุณไม่พบการเปลี่ยนแปลงที่กำลังเกิดขึ้น แก้ไขข้อบกพร่องหากจำเป็น

ArrayAdapter เทียบกับ BaseAdapter

ฉันพบว่าการทำงานกับอะแดปเตอร์ที่ช่วยให้คุณจัดการคอลเลกชันเช่น BaseAdapter ทำงานได้ดีขึ้น อะแดปเตอร์บางตัวเช่น ArrayAdapter นั้นจัดการคอลเลกชันของตัวเองอยู่แล้วทำให้ยากที่จะไปที่คอลเลกชันที่เหมาะสมสำหรับการอัพเดต จริงๆแล้วมันเป็นเพียงแค่เลเยอร์พิเศษที่ไม่มีความจำเป็นในกรณีส่วนใหญ่

ด้าย UI

เป็นความจริงที่ต้องเรียกใช้จากเธรด UI คำตอบอื่น ๆ มีตัวอย่างเกี่ยวกับวิธีการบรรลุเป้าหมาย อย่างไรก็ตามสิ่งนี้จำเป็นเฉพาะเมื่อคุณกำลังทำงานกับข้อมูลนี้จากนอกเธรด UI นั่นคือจากบริการหรือเธรด UI ที่ไม่ใช่ ในกรณีง่ายๆคุณจะอัปเดตข้อมูลของคุณจากการคลิกปุ่มหรือกิจกรรม / ส่วนอื่น ดังนั้นจึงยังคงอยู่ภายในเธรด UI ไม่จำเป็นต้องป๊อปที่ runOnUiTrhead อยู่เสมอ

ตัวอย่างโครงการด่วน

สามารถพบได้ที่https://github.com/hanscappelle/so-2250770.git เพียงโคลนและเปิดโครงการใน Android Studio (gradle) โครงการนี้มีอาคารหลักที่ListViewมีข้อมูลสุ่มทั้งหมด รายการนี้สามารถรีเฟรชได้โดยใช้เมนูการกระทำ

การปรับใช้อะแด็ปเตอร์ที่ฉันสร้างขึ้นสำหรับตัวอย่างนี้ ModelObject จะเปิดเผยการรวบรวมข้อมูล

public class MyListAdapter extends BaseAdapter {

    /**
     * this is our own collection of data, can be anything we 
     * want it to be as long as we get the abstract methods 
     * implemented using this data and work on this data 
     * (see getter) you should be fine
     */
    private List<ModelObject> mData;

    /**
     * our ctor for this adapter, we'll accept all the things 
     * we need here
     *
     * @param mData
     */
    public MyListAdapter(final Context context, final List<ModelObject> mData) {
        this.mData = mData;
        this.mContext = context;
    }

    public List<ModelObject> getData() {
        return mData;
    }

    // implement all abstract methods here
}

รหัสจาก MainActivity

public class MainActivity extends Activity {

    private MyListAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ListView list = (ListView) findViewById(R.id.list);

        // create some dummy data here
        List<ModelObject> objects = getRandomData();
        // and put it into an adapter for the list
        mAdapter = new MyListAdapter(this, objects);
        list.setAdapter(mAdapter);

        // mAdapter is available in the helper methods below and the 
        // data will be updated based on action menu interactions

        // you could also keep the reference to the android ListView 
        // object instead and use the {@link ListView#getAdapter()} 
        // method instead. However you would have to cast that adapter 
        // to your own instance every time
    }

    /**
     * helper to show what happens when all data is new
     */
    private void reloadAllData(){
        // get new modified random data
        List<ModelObject> objects = getRandomData();
        // update data in our adapter
        mAdapter.getData().clear();
        mAdapter.getData().addAll(objects);
        // fire the event
        mAdapter.notifyDataSetChanged();
    }

    /**
     * helper to show how only changing properties of data 
     * elements also works
     */
    private void scrambleChecked(){
        Random random = new Random();
        // update data in our adapter, iterate all objects and 
        // resetting the checked option
        for( ModelObject mo : mAdapter.getData()) {
            mo.setChecked(random.nextBoolean());
        }
        // fire the event
        mAdapter.notifyDataSetChanged();
    }
}

ข้อมูลมากกว่านี้

อีกโพสต์ที่ดีเกี่ยวกับพลังของ listViews อยู่ที่นี่: http://www.vogella.com/articles/AndroidListView/article.html


16
คุณผิด. INFORMDataSetChanged () ไม่ได้ผลสำหรับฉัน แต่ invalidateViews () ไม่ถูกต้อง
babay

6
ฉันมีปัญหาที่องค์ประกอบจริงในรายการไม่เปลี่ยนแปลงเช่นจำนวนองค์ประกอบเดียวกัน แต่ปัญหาคือวิธีที่พวกเขานำเสนอต้องเปลี่ยน นั่นหมายถึงรหัสของอะแดปเตอร์ของฉันในการสร้าง UI จำเป็นต้องเรียกใช้อีกครั้งจากนั้นซ่อนองค์ประกอบบางอย่างในแถวรายการอย่างถูกต้อง INFORMDataSetChanged () ใช้งานไม่ได้ ...
Sven Haiges

9
คำตอบนี้ช่วยฉันได้จริงๆ ฉันเก็บอาร์เรย์ไว้ในหน่วยความจำด้วยเหตุผลบางประการ เพื่อแก้ไขฉันตอนนี้โทรadapter.clear()และadapter.addAll(Array<T>)ก่อนที่จะโทรnotifyDataSetChanged()
Michael DePhillips

2
@hcpl ฉันจะเรียก informDataSetChanged ได้อย่างไรถ้าฉันอยู่ในกล่องกาเครื่องหมายของ OnClickListener ของอะแดปเตอร์ invalidateViews กำลังทำให้งานเสร็จในขณะนี้ เหตุใดจึงไม่ถูกต้องตรวจสอบวิธีการโทรที่ไม่ถูกต้อง
craned

1
ฉันไม่สามารถรับการแจ้งเตือน DataSetChanged ได้ ฉันสามารถเห็นได้อย่างชัดเจนว่าคอลเลกชันที่ฉันป้อนไปยังอะแดปเตอร์มีการเปลี่ยนแปลง (องค์ประกอบถูกลบ) แต่แจ้งเตือน DataSetChanged ไม่เคยทำอะไรเลย ไม่แน่ใจว่าวิธีนี้ใช้งานไม่ได้หรือไม่
byemute

42

โทรหา runnable ได้ทุกเมื่อที่คุณต้องการ:

runOnUiThread(run);

OnCreate()คุณตั้งค่าเธรดที่รันได้ของคุณ:

run = new Runnable() {
    public void run() {
        //reload content
        arraylist.clear();
        arraylist.addAll(db.readAll());
        adapter.notifyDataSetChanged();
        listview.invalidateViews();
        listview.refreshDrawableState();
    }
};

1
ทำงานในกรณีของฉันที่ฉันต้องอัปเดตมุมมองตามข้อมูลที่มาจากการเชื่อมต่อ TCP (จากเธรด "nonUI") วิธีเดียวที่จะมีการวาดรายการใหม่คือการล้างและเพิ่มองค์ประกอบทั้งหมดของ ArrayList อีกครั้ง อย่างไรก็ตามหากคุณอยู่ในเธรด UI แล้วคุณไม่จำเป็นต้องโทรหารหัสผ่านrunOnUiThread()ฟังก์ชั่น
Andre

ขอบคุณ! มันใช้งานได้สำหรับฉัน สำหรับทุกคนที่ต้องการเรียกใช้จากแฟรกเมนต์คุณควรใช้ getActivity () runOnUiThread (Runnable ใหม่ ... เพื่อให้แน่ใจว่าโค้ดนั้นรันบนเธรด UI
codingpuss

ฉันไม่เห็นวัตถุประสงค์run = new Runnable()และเพิ่งให้ฟังก์ชั่นของฉันเป็นpublic void refreshUIThread()วิธีที่เป็นแบบจำลองrun()วิธีการของคุณ(ซึ่งก็ใช้ได้เช่นกัน)
T.Woody

11

ฉันมีปัญหากับการรีเฟรชมุมมองรายการแบบไดนามิก

โทรแจ้งข้อมูล DataSetChanged () ที่อแด็ปเตอร์ของคุณ

ข้อมูลเฉพาะเพิ่มเติมบางอย่างเกี่ยวกับวิธี / เวลาในการโทรแจ้งเตือน DataSetChanged () สามารถดูได้ในวิดีโอ Google I / O นี้

INFORMDataSetChanged () ทำงานไม่ถูกต้องในกรณีของฉัน [ฉันเรียกว่า NOTEDataSetChanged จากคลาสอื่น] ในกรณีที่ฉันแก้ไข ListView ในการทำงานกิจกรรม (Thread) วิดีโอนั้นต้องขอบคุณคริสโตเฟอร์ที่ให้คำแนะนำสุดท้าย

ในชั้นสองของฉันฉันใช้

Runnable run = new Runnable(){
     public void run(){
         contactsActivity.update();
     }
};
contactsActivity.runOnUiThread(run);

เพื่อ acces การปรับปรุง () จากกิจกรรมของฉัน การอัปเดตนี้รวมถึง

myAdapter.notifyDataSetChanged();

เพื่อบอกให้อะแด็ปเตอร์รีเฟรชมุมมอง ทำงานได้ดีเท่าที่ฉันสามารถพูดได้



5

หากคุณยังไม่พอใจกับ ListView Refreshment คุณสามารถดูตัวอย่างนี้สำหรับการโหลด listView จาก DB ที่จริงสิ่งที่คุณต้องทำคือเพียงแค่โหลด ListView อีกครั้งหลังจากที่คุณดำเนินการ CRUD มันไม่ใช่วิธีที่ดีที่สุดในการ รหัส แต่มันจะรีเฟรช ListView ตามที่คุณต้องการ ..

มันเหมาะกับฉัน .... ถ้าหากคุณพบทางออกที่ดีกว่าโปรดแชร์ ...

.......
......
ดำเนินการ CRUD ของคุณ ..
......
.....
DBAdapter.open ();
DBAdapter.insert_into_SingleList ();
// นำ DB_results นั้นมาและเพิ่มลงในรายการเป็นเนื้อหา ...
                                            ls2.setAdapter (ใหม่ ArrayAdapter (DynTABSample.this
    android.R.layout.simple_list_item_1, DBAdapter.DB_ListView));
                                            DBAdapter.close ();

2

โซลูชันที่เสนอโดยบุคคลในโพสต์นี้ใช้งานได้หรือไม่ขึ้นอยู่กับรุ่น Android ของอุปกรณ์ของคุณเป็นหลัก ตัวอย่างเช่นการใช้วิธี AddAll คุณต้องใส่ android: minSdkVersion = "10" ในอุปกรณ์ android ของคุณ

เพื่อแก้คำถามนี้สำหรับอุปกรณ์ทั้งหมดที่ฉันได้สร้างวิธีการของตัวเองในอะแดปเตอร์ของฉันและใช้ในการเพิ่มและลบวิธีการสืบทอดจาก ArrayAdapter ที่ปรับปรุงข้อมูลของคุณโดยไม่มีปัญหา

รหัสของฉัน: การใช้คลาสข้อมูลของฉันเอง RaceResult คุณใช้โมเดลข้อมูลของคุณเอง

ResultGpRowAdapter.java

public class ResultGpRowAdapter extends ArrayAdapter<RaceResult> {

    Context context;
    int resource;
    List<RaceResult> data=null;

        public ResultGpRowAdapter(Context context, int resource, List<RaceResult> objects)           {
        super(context, resource, objects);

        this.context = context;
        this.resource = resource;
        this.data = objects;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ........
        }

        //my own method to populate data           
        public void myAddAll(List<RaceResult> items) {

        for (RaceResult item:items){
            super.add(item);
        }
    }

ResultsGp.java

public class ResultsGp extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {

    ...........
    ...........
    ListView list = (ListView)findViewById(R.id.resultsGpList); 

    ResultGpRowAdapter adapter = new ResultGpRowAdapter(this,  R.layout.activity_result_gp_row, new ArrayList<RaceResult>()); //Empty data

   list.setAdapter(adapter);

   .... 
   ....
   ....
   //LOAD a ArrayList<RaceResult> with data

   ArrayList<RaceResult> data = new ArrayList<RaceResult>();
   data.add(new RaceResult(....));
   data.add(new RaceResult(....));
   .......

   adapter.myAddAll(data); //Your list will be udpdated!!!

1

หากคุณต้องการรักษาตำแหน่งการเลื่อนเมื่อรีเฟรชและคุณสามารถทำได้:

if (mEventListView.getAdapter() == null) {
    EventLogAdapter eventLogAdapter = new EventLogAdapter(mContext, events);
    mEventListView.setAdapter(eventLogAdapter);
} else {
    ((EventLogAdapter)mEventListView.getAdapter()).refill(events);
}

public void refill(List<EventLog> events) {
    mEvents.clear();
    mEvents.addAll(events);
    notifyDataSetChanged();
}

สำหรับข้อมูลรายละเอียดโปรดดูAndroid ListView: รักษาเลื่อนตำแหน่งของคุณเมื่อคุณรีเฟรช


1

เพียงใช้myArrayList.remove(position);ภายในฟัง:

  myListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override public void onItemClick(AdapterView<?> parent, android.view.View view, int position, long id) {
           myArrayList.remove(position);
           myArrayAdapter.notifyDataSetChanged();
        }
    });

1

คุณจำเป็นต้องใช้วัตถุเดียวของรายการว่าข้อมูล whoose ListViewคุณกำลังพองบน หากการอ้างอิงคือการเปลี่ยนแปลงก็ใช้ notifyDataSetChanged()งานไม่ได้เมื่อใดก็ตามที่คุณลบองค์ประกอบจากมุมมองรายการให้ลบองค์ประกอบเหล่านั้นออกจากรายการที่คุณใช้ไม่ว่าจะเป็น ArrayList <> หรืออย่างอื่นจากนั้นเรียก notifyDataSetChanged()ใช้วัตถุของคลาสอะแดปเตอร์ของคุณ

ดังนั้นที่นี่ดูว่าฉันจัดการมันในอะแดปเตอร์ของฉันดูด้านล่าง

public class CountryCodeListAdapter extends BaseAdapter implements OnItemClickListener{

private Context context;
private ArrayList<CountryDataObject> dObj;
private ViewHolder holder;
private Typeface itemFont;
private int selectedPosition=-1;
private ArrayList<CountryDataObject> completeList;

public CountryCodeListAdapter(Context context, ArrayList<CountryDataObject> dObj) {
    this.context = context;
    this.dObj=dObj;
    completeList=new  ArrayList<CountryDataObject>();
    completeList.addAll(dObj);
    itemFont=Typeface.createFromAsset(context.getAssets(), "CaviarDreams.ttf");
}

@Override
public int getCount() {
    return dObj.size();
}

@Override
public Object getItem(int position) {
    return dObj.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}
@Override
public View getView(int position, View view, ViewGroup parent) {
    if(view==null){
        holder = new ViewHolder();
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(R.layout.states_inflator_layout, null);
        holder.textView = ((TextView)view.findViewById(R.id.stateNameInflator));
        holder.checkImg=(ImageView)view.findViewById(R.id.checkBoxState);
        view.setTag(holder);
    }else{
        holder = (ViewHolder) view.getTag();
    }
    holder.textView.setText(dObj.get(position).getCountryName());
    holder.textView.setTypeface(itemFont);

    if(position==selectedPosition)
     {
         holder.checkImg.setImageResource(R.drawable.check);
     }
     else
     {
         holder.checkImg.setImageResource(R.drawable.uncheck);
     }
    return view;
}
private class ViewHolder{
    private TextView textView;
    private ImageView checkImg;
}

public void getFilter(String name) {
    dObj.clear();
    if(!name.equals("")){
    for (CountryDataObject item : completeList) {
        if(item.getCountryName().toLowerCase().startsWith(name.toLowerCase(),0)){
            dObj.add(item);
        }
    }
    }
    else {
        dObj.addAll(completeList);
    }
    selectedPosition=-1;
    notifyDataSetChanged();
    notifyDataSetInvalidated(); 
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
        long id) {
    Registration reg=(Registration)context;
    selectedPosition=position;
    reg.setSelectedCountryCode("+"+dObj.get(position).getCountryCode());
    notifyDataSetChanged();
}
}

1
คำอธิบายของคุณ underrated แต่จริงๆแล้วมันทำให้ฉันเข้าใจเกี่ยวกับการอ้างอิง arraylist ขอบคุณ
Abraham Putra Prakasa

0

refreshDrawableState()หลังจากลบข้อมูลจากมุมมองรายการคุณต้องโทร นี่คือตัวอย่าง:

final DatabaseHelper db = new DatabaseHelper (ActivityName.this);

db.open();

db.deleteContact(arg3);

mListView.refreshDrawableState();

db.close();

และdeleteContactวิธีการในDatabaseHelperชั้นเรียนจะมีลักษณะค่อนข้าง

public boolean deleteContact(long rowId) {

   return db.delete(TABLE_NAME, BaseColumns._ID + "=" + rowId, null) > 0;

}

0

ฉันไม่สามารถรับ informDataSetChanged () เพื่ออัปเดต SimpleAdapter ของฉันได้ดังนั้นฉันจึงลองลบมุมมองทั้งหมดที่แนบกับโครงร่างหลักโดยใช้ removeAllViews () จากนั้นเพิ่ม ListView และใช้งานได้ช่วยให้ฉันอัปเดต UI:

LinearLayout results = (LinearLayout)findViewById(R.id.results);
ListView lv = new ListView(this);
ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
SimpleAdapter adapter = new SimpleAdapter( this, list, R.layout.directory_row, 
                new String[] { "name", "dept" }, new int[] { R.id.name, R.id.dept } );

for (...) { 
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("name", name);
    map.put("dept", dept);
    list.add(map);
}

lv.setAdapter(adapter);
results.removeAllViews();     
results.addView(lv);

0

สำหรับฉันหลังจากการเปลี่ยนแปลงข้อมูลในฐานข้อมูล sql ไม่มีอะไรที่สามารถรีเฟรชมุมมองรายการ (เป็นมุมมองรายการแบบขยายได้) ดังนั้นถ้า informDataSetChanged () ไม่ช่วยคุณสามารถลองล้างรายการของคุณก่อนและเพิ่มอีกครั้งหลังจากการโทร ตัวอย่างเช่น

private List<List<SomeNewArray>> arrayList;
List<SomeNewArray> array1= getArrayList(...);
List<SomeNewArray> array2= getArrayList(...);
arrayList.clear();
arrayList.add(array1);
arrayList.add(array2);
notifyDataSetChanged();

หวังว่ามันสมเหตุสมผลสำหรับคุณ



0

ฉันก็เหมือนกันเมื่อในส่วนฉันต้องการเติม ListView (ใน TextView เดียว) ด้วยที่อยู่ mac ของอุปกรณ์ BLE ที่สแกนในบางครั้ง

สิ่งที่ฉันทำคือ:

public class Fragment01 extends android.support.v4.app.Fragment implements ...
{
    private ListView                listView;
    private ArrayAdapter<String>    arrayAdapter_string;

...

@Override
public void onActivityCreated(Bundle savedInstanceState)
{
    ...
    this.listView= (ListView) super.getActivity().findViewById(R.id.fragment01_listView);
    ...
    this.arrayAdapter_string= new ArrayAdapter<String>(super.getActivity(), R.layout.dispositivo_ble_item, R.id.fragment01_item_textView_titulo);
    this.listView.setAdapter(this.arrayAdapter_string);
}


@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)
{
    ...
    super.getActivity().runOnUiThread(new RefreshListView(device));
}


private class RefreshListView implements Runnable
{
    private BluetoothDevice bluetoothDevice;

    public RefreshListView(BluetoothDevice bluetoothDevice)
    {
        this.bluetoothDevice= bluetoothDevice;
    }

    @Override
    public void run()
    {
        Fragment01.this.arrayAdapter_string.add(new String(bluetoothDevice.toString()));
        Fragment01.this.arrayAdapter_string.notifyDataSetChanged();
    }
}

จากนั้น ListView จะเริ่มเติมข้อมูลแบบไดนามิกด้วยที่อยู่ mac ของอุปกรณ์ที่พบ


0

ฉันคิดว่ามันขึ้นอยู่กับความหมายของการรีเฟรช คุณหมายถึงว่าการแสดงผล GUI ควรมีการรีเฟรชหรือคุณหมายความว่ามุมมองลูกควรได้รับการรีเฟรชซึ่งคุณสามารถเรียกใช้ getChildAt (int) แบบเป็นโปรแกรมและรับมุมมองที่สอดคล้องกับสิ่งที่อยู่ในอะแดปเตอร์

หากคุณต้องการให้จอแสดงผล GUI รีเฟรชให้โทรแจ้งให้ทราบ DataSetChanged () บนอแด็ปเตอร์ GUI จะรีเฟรชเมื่อวาดใหม่ในครั้งถัดไป

หากคุณต้องการเรียกใช้ getChildAt (int) และรับมุมมองที่สะท้อนถึงสิ่งที่อยู่ในอะแดปเตอร์ให้โทรไปที่ layoutChildren () นี่จะทำให้มุมมองลูกถูกสร้างขึ้นใหม่จากข้อมูลอะแดปเตอร์


0

ฉันมี ArrayList ที่ฉันต้องการแสดงใน listview ArrayList มีองค์ประกอบจาก mysql ฉันลบล้างวิธี onRefresh และในวิธีนั้นฉันใช้tablelayout.removeAllViews (); จากนั้นทำซ้ำกระบวนการรับข้อมูลอีกครั้งจากฐานข้อมูล แต่ก่อนหน้านั้นอย่าลืมล้าง ArrayList ของคุณหรือโครงสร้างข้อมูลใด ๆ มิฉะนั้นข้อมูลใหม่จะถูกผนวกเข้ากับอันเก่า


0

หากคุณต้องการอัปเดต UI listview จากบริการให้ทำอะแดปเตอร์ให้คงที่ในกิจกรรมหลักของคุณและทำสิ่งนี้:

@Override
public void onDestroy() {
    if (MainActivity.isInFront == true) {
        if (MainActivity.adapter != null) {
            MainActivity.adapter.notifyDataSetChanged();
        }

        MainActivity.listView.setAdapter(MainActivity.adapter);
    }
}    

0

หากคุณกำลังจะไปโดยเส้นคู่มือ Android และคุณกำลังใช้ContentProvidersเพื่อรับข้อมูลจากDatabaseและคุณจะแสดงในการListViewใช้CursorLoaderและCursorAdaptersจากนั้นการเปลี่ยนแปลงทั้งหมดของคุณข้อมูลที่เกี่ยวข้องจะปรากฏใน ListView โดยอัตโนมัติ

getContext().getContentResolver().notifyChange(uri, null);เคอร์เซอร์ของคุณในContentProviderจะเพียงพอที่จะสะท้อนการเปลี่ยนแปลงไม่จำเป็นต้องมีการแก้ไขเพิ่มเติม

แต่เมื่อคุณไม่ได้ใช้สิ่งเหล่านี้คุณต้องบอกอะแดปเตอร์เมื่อชุดข้อมูลกำลังเปลี่ยนแปลง นอกจากนี้คุณต้องเติม / โหลดชุดข้อมูลของคุณอีกครั้ง (พูดรายการ) จากนั้นคุณต้องโทรหาnotifyDataSetChanged()อะแดปเตอร์

notifyDataSetChanged()จะไม่ทำงานหากไม่มีการเปลี่ยนแปลงในชุดข้อมูล นี่คือความคิดเห็นข้างต้นวิธีการในเอกสาร -

/**
 * Notifies the attached observers that the underlying data has been changed
 * and any View reflecting the data set should refresh itself.
 */

0

ฉันสามารถรับการแจ้งเตือน DataSetChanged ได้โดยการรับข้อมูลอะแดปเตอร์ใหม่เท่านั้นจากนั้นรีเซ็ตอะแดปเตอร์สำหรับมุมมองรายการจากนั้นทำการโทรออกดังนี้

    expandableAdapter = baseFragmentParent.setupEXLVAdapter();
    baseFragmentParent.setAdapter(expandableAdapter);
    expandableAdapter.notifyDataSetChanged(); 

0

ในตัวเลือกอื่น ๆ เป็นonWindowFocusChangedวิธีการ แต่แน่ใจว่ามันมีความละเอียดอ่อนและต้องการการเข้ารหัสพิเศษสำหรับผู้ที่สนใจ

 override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)

       // some controls needed
        programList = usersDBHelper.readProgram(model.title!!)
        notesAdapter = DailyAdapter(this, programList)
        notesAdapter.notifyDataSetChanged()
        listview_act_daily.adapter = notesAdapter
    }

0

พิจารณาว่าคุณส่งรายการไปยังอะแดปเตอร์ของคุณแล้ว
ใช้:

list.getAdapter().notifyDataSetChanged()

เพื่ออัปเดตรายการของคุณ


0

ถ้าฉันพูดถึงสถานการณ์ของฉันที่นี่คำตอบที่ไม่ใช่คำตอบข้างต้นจะไม่ทำงานเพราะฉันมีกิจกรรมที่แสดงรายการของค่า db พร้อมกับปุ่มลบและเมื่อกดปุ่มลบฉันต้องการลบรายการนั้นออกจากรายการ

สิ่งที่น่าสนใจคือฉันไม่ได้ใช้มุมมองรีไซเคิล แต่เป็นลิสต์แบบง่ายและมุมมองลิสต์นั้นเริ่มต้นได้ในคลาสอะแด็ปเตอร์ ดังนั้นการเรียกnotifyDataSetChanged()จะไม่ทำอะไรภายในคลาสอะแดปเตอร์และแม้แต่ในคลาสกิจกรรมที่วัตถุอะแดปเตอร์จะเริ่มต้นได้เนื่องจากวิธีการลบอยู่ในคลาสอะแดปเตอร์

ดังนั้นวิธีการคือการลบวัตถุออกจากอะแดปเตอร์ในgetViewวิธีการเรียนอะแดปเตอร์(เพื่อลบเฉพาะวัตถุนั้น แต่ถ้าคุณต้องการที่จะลบทั้งหมดโทรclear())

เพื่อให้คุณได้แนวคิดบางอย่างรหัสของฉันเป็นอย่างไร

public class WordAdapter extends ArrayAdapter<Word> {
  Context context;

  public WordAdapter(Activity context, ArrayList<Word> words) {}
    //.......

    @NonNull
    @Override
    public View getView(final int position, View convertView, ViewGroup group) {
      //.......
     ImageButton deleteBt = listItemView.findViewById(R.id.word_delete_bt);
     deleteBt.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
             if (vocabDb.deleteWord(currentWord.id)) {
                //.....
             } else{
                //.....
             }
             remove(getItem(position)); // <---- here is the trick ---<
             //clear() // if you want to clear everything
         }
    });
 //....

หมายเหตุ: ที่นี่remove()และgetItem()วิธีการที่สืบทอดมาจากชั้นอะแดปเตอร์

  • remove() - เพื่อลบรายการเฉพาะที่คลิก
  • getItem(position) - คือการรับไอเท็ม (ที่นี่นั่นคือวัตถุ Word ของฉันที่ฉันเพิ่มลงในรายการ) จากตำแหน่งที่คลิก

นี่คือวิธีที่ฉันตั้งค่าอะแดปเตอร์เป็นลิสต์วิวในคลาสกิจกรรม

    ArrayList<Word> wordList = new ArrayList();
    WordAdapter adapter = new WordAdapter(this, wordList);

    ListView list_view = (ListView) findViewById(R.id.activity_view_words);
    list_view.setAdapter(adapter);

-1

วิธีที่ง่ายที่สุดคือการสร้าง Adaper ใหม่และวางอันเก่า:

myListView.setAdapter(new MyListAdapter(...));

นี้ใช้หน่วยความจำเพิ่มเติม
PLAYER1

ขยะจะถูกเก็บรวบรวม
1712200
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.