문제

안드로이드를 새로 고치는 방법 ListView 동적 데이터를 추가/삭제 한 후?

도움이 되었습니까?

해결책

부르다 notifyDataSetChanged() 너의 Adapter 해당 어댑터에서 데이터를 수정 한 후에는 객체.

전화 방법/시기에 대한 추가 세부 사항 notifyDataSetChanged() 볼 수 있습니다 이 Google I/O 비디오.

다른 팁

또한 이것을 사용할 수 있습니다.

myListView.invalidateViews();

모든 것을 무시하십시오 invalidate(), invalidateViews(), requestLayout(), ...이 질문에 대한 답변.

옳은 일 (그리고 운 좋게도 정답으로 표시됨)은 전화합니다 notifyDataSetChanged() 어댑터에.

문제 해결

전화하는 경우 notifyDataSetChanged() 모든 레이아웃 방법이 도움이되지는 않습니다. 나를 믿으세요 ListView 올바르게 업데이트되었습니다. 차이를 찾지 못하면 어댑터의 데이터가 어디에서 나오는지 확인해야합니다.

이것이 단지 컬렉션 인 경우, 메모리에 보관하고있는 경우, 전화하기 전에 실제로 컬렉션에 항목을 삭제하거나 추가했는지 확인하십시오. notifyDataSetChanged().

데이터베이스 또는 서비스 백엔드로 작업하는 경우 호출하기 전에 정보를 다시 검색하거나 메모리 데이터를 조작하기 위해 메소드를 호출해야합니다. notifyDataSetChanged().

문제는 이것입니다 notifyDataSetChanged 데이터 세트가 변경된 경우에만 작동합니다. 변화가 나오지 않으면 볼 수있는 곳입니다. 필요한 경우 디버깅하십시오.

Arrayadapter vs 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

원할 때마다 실행할 수 있습니다.

runOnUiThread(run);

OnCreate(), 당신은 런닝 가능한 스레드를 설정합니다 :

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

ListView의 동적 새로 고침에 문제가 있습니다.

어댑터에서 notifydatasetchanged ()를 호출하십시오.

이 Google I/O 비디오에서 NotifyDatasetchAnged ()를 호출하는 방법/시기에 대한 추가 세부 사항을 볼 수 있습니다.

NotifyDataSetchanged ()는 제 경우에 제대로 작동하지 않았습니다. 실행 중 활동 (스레드)에서 ListView를 편집했습니다. 그 비디오 크리스토퍼에게 감사합니다 최종 힌트를 주었다.

두 번째 수업에서 나는 사용했습니다

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

내 활동에서 update ()를 acces. 이 업데이트에는 포함됩니다

myAdapter.notifyDataSetChanged();

어댑터에 뷰를 새로 고치라고 지시합니다. 내가 말할 수있는 한 잘 작동했습니다.

사용중인 경우 단순한 쿠커스 라도프 전화 해보세요 requery () 커서 개체에서.

ListView Comphrowment에 여전히 만족하지 않는 경우이 스 니펫을 볼 수 있습니다. DB에서 ListView를로드하는 것입니다. 실제로해야 할 일은 CRUD 작업을 수행 한 후에는 최선의 방법이 아닌 최선의 방법이 아닙니다. 코드이지만 원하는대로 ListView를 새로 고칠 것입니다.

그것은 나를 위해 작동합니다 .... 더 나은 해결책을 찾으면 공유하십시오 ...

.......
......
do your CRUD Operations..
......
.....
DBAdapter.open();
DBAdapter.insert_into_SingleList();
// Bring that DB_results and add it to list as its contents....
                                            ls2.setAdapter(new ArrayAdapter(DynTABSample.this,
    android.R.layout.simple_list_item_1,                        DBAdapter.DB_ListView));
                                            DBAdapter.close();

이 게시물의 사람들이 제안한 솔루션은 주로 장치의 Android 버전에 따라 작동하지 않습니다. 예를 들어 addall 메소드를 사용하려면 Android 장치에 Android : minsdkversion = "10"을 넣어야합니다.

모든 장치에 대해이 질문을 해결하기 위해 어댑터에서 자체 메소드를 작성하고 추가 및 제거 메소드 내부에서 AdrrayAdapter에서 데이터를 상속받는 데 문제가 없습니다.

내 코드 : 내 자신의 데이터 클래스 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!!!

새로 고침 할 때 스크롤 위치를 유지하려면이 작업을 수행 할 수 있습니다.

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 : 새로 고침 될 때 스크롤 위치를 유지합니다..

그냥 사용하십시오 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();
        }
    });

당신은 당신이 팽창시키고있는 데이터의 목록의 단일 객체를 사용해야합니다. 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();
}
}

목록보기에서 데이터를 삭제 한 후에는 호출해야합니다. 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;

}

단순한 DataSetchanged ()가 단순한 DataSetchanged ()를 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);

SQL 데이터베이스에서 정보를 변경 한 후에 나에게는 NOTYDATASETHEND ()가 도움이되지 않으면 목록보기 (특정 확장 가능한 목록보기)를 새로 고칠 수 없습니다. 먼저 목록을 지우고 다시 추가 할 수 있습니다. 예를 들어

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

그것이 당신에게 의미가 있기를 바랍니다.

SimplecursorAdapter를 사용하면 어댑터에서 ChangeCursor (NewCursor)를 호출 할 수 있습니다.

조각에서, 나는 시간에 걸쳐 스캔 한 BLE 장치의 MAC 주소로 ListView (단일 텍스트 뷰)를 채우고 싶었을 때 동일했습니다.

내가 한 일은 이것이었습니다.

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 주소로 동적으로 채워지기 시작했습니다.

나는 그것이 당신이 새로 고침의 의미에 달려 있다고 생각합니다. GUI 디스플레이가 새로 고침되어야한다는 것을 의미합니까, 아니면 getchildat (int)를 프로그래밍 방식으로 호출하고 어댑터의 내용에 해당하는보기를 얻을 수 있도록 어린이보기가 새로 고침되어야한다는 것을 의미합니까?

GUI 디스플레이를 새로 고치려면 어댑터에서 NotifyDataSetchanged ()를 호출하십시오. 다음에 다시 그려지면 GUI가 새로 고침됩니다.

GetChildat (int)를 호출하고 어댑터의 내용이 무엇인지 반영하는 견해를 얻으려면 LayoutChildren ()을 호출하십시오. 이로 인해 아동 뷰는 어댑터 데이터에서 재구성됩니다.

ListView에 표시하고 싶었던 ArrayList가있었습니다. ArrayList에는 MySQL의 요소가 포함되어 있습니다. 나는 onrefresh 메소드를 지나치게 과도하게 사용했고 그 방법에서 내가 사용했습니다. TableLayout.removeallViews (); 그런 다음 데이터베이스에서 데이터를 다시 가져 오는 프로세스를 반복했습니다. 그러나 그 전에 Arraylist를 지우거나 모든 데이터 Structre 또는 새로운 데이터가 기존 데이터에 추가됩니다 ..

서비스에서 UI ListView를 업데이트하려면 주요 활동에서 어댑터를 정적으로 만들고 다음을 수행하십시오.

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

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

Android 가이드 라인을 사용하고 있고 사용하는 경우 ContentProviders 데이터를 얻으려면 Database 그리고 당신은 그것을 표시하고 있습니다 ListView 사용 CursorLoader 그리고 CursorAdapters , 그러면 관련 데이터의 모든 변경 사항은 ListView에 자동으로 반영됩니다.

당신의 getContext().getContentResolver().notifyChange(uri, null); 커서에서 ContentProvider 추가 작업에 대한 변경 사항을 반영하기에 충분할 것입니다.

그러나이 모든 것을 사용하지 않을 때는 데이터 세트가 변경 될 때 어댑터를 알려야합니다. 또한 데이터 세트 (예 : 목록)를 다시 인구 / 다시로드해야하며 전화해야합니다. notifyDataSetChanged() 어댑터에서.

notifyDataSetChanged()DATSET에 변경 사항이 없으면 작동하지 않습니다. 다음은 문서의 메소드의 주석입니다.

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

새로운 어댑터 데이터를 얻은 다음 목록보기의 어댑터를 재설정 한 다음 호출을하기 만하면서만 NotifyDatasetchEnd를 얻을 수있었습니다.

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

다른 옵션은입니다 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
    }

어댑터에 목록을 전달했다고 생각하십시오.
사용:

list.getAdapter().notifyDataSetChanged()

목록을 업데이트합니다.

여기에서 내 시나리오에 대해 이야기 한 경우, 삭제 버튼과 함께 DB 값의 목록을 표시하는 활동이 있었기 때문에 위의 답변이 작동하지 않고 삭제 버튼을 누르면 목록에서 해당 항목을 삭제하고 싶었습니다.

멋진 것은 Recycler보기를 사용하지 않았지만 간단한 목록보기와 그 목록보기는 어댑터 클래스에서 초기화되었습니다. 그래서, 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) - 클릭 된 위치에서 항목 (여기서 목록에 추가 한 내 단어 객체)을 가져 오는 것입니다.

이것은 어댑터를 활동 클래스의 ListView로 설정하는 방법입니다.

    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);

가장 쉬운 것은 새로운 아디퍼를 만들고 오래된 것을 떨어 뜨리는 것입니다.

myListView.setAdapter(new MyListAdapter(...));
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top