Yang ingin saya lakukan : menjalankan utas latar belakang yang menghitung konten ListView dan memperbarui ListView sebagian, sementara hasilnya dihitung.
Yang saya tahu harus saya hindari : Saya tidak bisa main-main dengan konten ListAdapter dari utas latar belakang, jadi saya mewarisi AsyncTask dan menerbitkan hasil (menambahkan entri ke adaptor) dari onProgressUpdate. Adaptor saya menggunakan ArrayList objek hasil, semua operasi pada daftar array disinkronkan.
Penelitian orang lain : ada data yang sangat berharga di sini . Saya juga menderita crash hampir setiap hari untuk sekelompok ~ 500 pengguna, dan ketika saya menambahkan list.setVisibility(GONE)/trackList.setVisibility(VISIBLE)
blok di onProgressUpdate, crash diturunkan dengan faktor 10 tetapi tidak hilang. (disarankan dalam jawaban )
Apa yang saya dapatkan kadang-kadang : tolong perhatikan, itu terjadi sangat jarang (seminggu sekali untuk salah satu dari pengguna 3.5k). Tapi saya ingin menyingkirkan bug ini sepenuhnya. Ini adalah stacktrace parsial:
`java.lang.IllegalStateException:` The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(2131296334, class android.widget.ListView) with Adapter(class com.transportoid.Tracks.TrackListAdapter)]
at android.widget.ListView.layoutChildren(ListView.java:1432)
at android.widget.AbsListView.onTouchEvent(AbsListView.java:2062)
at android.widget.ListView.onTouchEvent(ListView.java:3234)
at android.view.View.dispatchTouchEvent(View.java:3709)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:852)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
[...]
Tolong? Tidak diperlukan lagi, lihat di bawah
JAWABAN FINAL: Ternyata, saya menelepon notifyDataSetChanged
setiap 5 insersi untuk menghindari perubahan daftar yang tiba-tiba berkedip. Itu tidak bisa dilakukan dengan cara seperti itu, selalu beri tahu adaptor ketika daftar dasar berubah. Bug ini sudah lama hilang untuk saya sekarang.
Jawaban:
Saya memiliki masalah yang sama.
Saya menambahkan item ke
ArrayList
luar saya di utas UI.Solusi: Saya telah melakukan keduanya,
adding the items
dan memanggilnotifyDataSetChanged()
thread UI.sumber
Saya memiliki masalah yang sama, tetapi saya memperbaikinya menggunakan metode ini
dari kelas
ListView
sumber
Ini adalah Masalah MultiThreading dan Menggunakan Blok yang Disinkronkan Dengan Benar Ini dapat dicegah. Tanpa meletakkan hal-hal tambahan di UI Thread dan menyebabkan hilangnya respons aplikasi.
Saya juga menghadapi hal yang sama. Dan sebagai jawaban yang paling diterima menyarankan membuat perubahan ke data adaptor dari UI Thread dapat menyelesaikan masalah. Itu akan berhasil tetapi merupakan solusi yang cepat dan mudah tetapi bukan yang terbaik.
Seperti yang Anda lihat untuk kasus normal. Memperbarui adaptor data dari utas latar belakang dan memanggil notifyDataSetChanged di utas UI berfungsi.
IllegalStateException ini muncul ketika utas ui memperbarui tampilan dan utas latar belakang lainnya mengubah data lagi. Momen itu yang menyebabkan masalah ini.
Jadi, jika Anda akan menyinkronkan semua kode yang mengubah data adaptor dan membuat panggilan notifydatasetchange. Masalah ini harus hilang. Seperti yang terjadi pada saya dan saya masih memperbarui data dari utas latar belakang.
Ini adalah kode khusus kasus saya untuk dirujuk oleh orang lain.
Pemuat saya di layar utama memuat kontak buku telepon ke sumber data saya di latar belakang.
PhoneBookManager ini. GetPhoneBookContacts membaca kontak dari buku telepon dan mengisinya dalam hashmaps. Yang secara langsung dapat digunakan untuk Daftar Adaptor untuk menggambar daftar.
Ada tombol di layar saya. Itu membuka aktivitas di mana nomor telepon ini terdaftar. Jika saya langsung mengaturAdapter di atas daftar sebelum utas sebelumnya menyelesaikan pekerjaannya yang merupakan kasus naviagtion cepat lebih jarang terjadi. Itu muncul pengecualian. Yang merupakan judul dari pertanyaan SO ini. Jadi saya harus melakukan sesuatu seperti ini di aktivitas kedua.
Loader saya di aktivitas kedua menunggu untuk menyelesaikan utas pertama. Sampai ini menunjukkan bilah kemajuan. Periksa loadInBackground dari kedua loader.
Kemudian ia menciptakan adaptor dan mengirimkannya ke aktivitas di mana pada thread ui saya sebut setAdapter.
Itu memecahkan masalah saya.
Kode ini hanya potongan. Anda perlu mengubahnya untuk dikompilasi dengan baik untuk Anda.
Semoga ini membantu
sumber
Saya memecahkan ini dengan memiliki 2 Daftar. Satu daftar yang saya gunakan hanya untuk adaptor, dan saya melakukan semua perubahan / pembaruan data pada daftar lainnya. Ini memungkinkan saya untuk melakukan pembaruan pada satu daftar di utas latar belakang, dan kemudian memperbarui daftar "adaptor" di utas utama / UI:
sumber
Saya menulis kode ini dan menjalankannya dalam gambar 2,1 emulator selama ~ 12 jam dan tidak mendapatkan IllegalStateException. Saya akan memberikan kerangka kerja android manfaat dari keraguan yang satu ini dan mengatakan bahwa kemungkinan besar kesalahan dalam kode Anda. Saya harap ini membantu. Mungkin Anda bisa menyesuaikannya dengan daftar dan data Anda.
sumber
Beberapa hari yang lalu saya menemukan masalah yang sama dan menyebabkan beberapa ribu crash per hari, sekitar 0,1% pengguna memenuhi situasi ini. Saya mencoba
setVisibility(GONE/VISIBLE)
danrequestLayout()
, tetapi jumlah macet hanya berkurang sedikit.Dan saya akhirnya menyelesaikannya. Tidak ada apa-apa dengan
setVisibility(GONE/VISIBLE)
. Tidak ada apa-apa denganrequestLayout()
.Akhirnya saya menemukan alasannya adalah saya menggunakan
Handler
panggilannotifyDataSetChanged()
setelah pembaruan data, yang dapat menyebabkan semacam:checkForTap()
/onTouchEvent()
dan akhirnya memanggillayoutChildren()
)notifyDataSetChanged()
dan memperbarui tampilanDan saya membuat kesalahan lain dalam
getCount()
,getItem()
dangetView()
, saya langsung menggunakan bidang di DataSource, daripada menyalinnya ke adaptor. Jadi akhirnya crash ketika:getCount()
dangetView()
dipanggil, dan listview menemukan data tidak konsisten, dan melempar pengecualian sepertijava.lang.IllegalStateException: The content of the adapter has changed but...
. Pengecualian umum lainnya adalahIndexOutOfBoundException
jika Anda menggunakan header / footer diListView
.Jadi solusinya mudah, saya hanya menyalin data ke adaptor dari DataSource saya ketika Handler saya memicu adaptor untuk mendapatkan data dan panggilan
notifyDataSetChanged()
. Kecelakaan sekarang tidak pernah terjadi lagi.sumber
Seandainya ini terjadi sesekali, ternyata saya hanya memiliki masalah ini ketika daftar telah digulir setelah item terakhir 'memuat lebih banyak' diklik. Jika daftar tidak digulir, semuanya bekerja dengan baik.
Setelah BANYAK debugging, itu adalah bug di pihak saya, tetapi juga ada ketidakkonsistenan dalam kode Android.
Ketika validasi terjadi, kode ini dieksekusi di ListView
Tetapi ketika onChange terjadi, kode ini diaktifkan di AdapterView (induk dari ListView)
Perhatikan cara Adaptor TIDAK dijamin Sama!
Dalam kasus saya, karena itu adalah 'LoadMoreAdapter' saya mengembalikan WrappedAdapter dalam panggilan getAdapter (untuk akses ke objek yang mendasarinya). Ini menghasilkan jumlah yang berbeda karena item 'Muat Lebih Banyak' tambahan dan Pengecualian dilemparkan.
Saya hanya melakukan ini karena dokumen membuatnya sepertinya tidak apa-apa untuk dilakukan
ListView.getAdapter javadoc
sumber
Masalah saya terkait dengan penggunaan Filter bersama dengan ListView.
Saat mengatur atau memperbarui model data yang mendasari ListView, saya melakukan sesuatu seperti ini:
Memanggil
filter()
di baris terakhir akan (dan harus) menyebabkannotifyDataSetChanged()
dipanggil dalam FilterpublishResults()
. Terkadang ini bekerja dengan baik, khususnya di Nexus 5. saya yang cepat. Namun pada kenyataannya, ini menyembunyikan bug yang akan Anda perhatikan dengan perangkat yang lebih lambat atau dalam kondisi intensif sumber daya.Masalahnya adalah bahwa penyaringan dilakukan secara tidak sinkron, dan dengan demikian antara akhir
filter()
pernyataan dan panggilan untukpublishResults()
, keduanya di utas UI, beberapa kode utas UI lainnya dapat menjalankan dan mengubah konten adaptor.Cara memperbaiki yang sebenarnya mudah, cukup panggil
notifyDataSetChanged()
juga sebelum meminta penyaringan dilakukan:sumber
Saya memiliki Daftar jika objek Feed. Itu ditambahkan dan terpotong dari utas UI. Ini berfungsi dengan baik dengan adaptor di bawah ini. Saya tetap memanggil
FeedAdapter.notifyDataSetChanged
utas UI tetapi sedikit kemudian. Saya memang suka ini karena objek Feed saya tetap tersimpan dalam memori di Layanan Lokal bahkan ketika UI mati.sumber
Saya menghadapi masalah yang sama dengan log kesalahan yang persis sama. Dalam kasus saya
onProgress()
tentang AsyncTask menambahkan nilai ke adaptor menggunakanmAdapter.add(newEntry)
. Untuk menghindari UI menjadi kurang responsif, saya mengaturmAdapter.setNotifyOnChange(false)
dan memanggilmAdapter.notifyDataSetChanged()
4 kali kedua. Sekali per detik array diurutkan.Ini berfungsi dengan baik dan terlihat sangat membuat ketagihan, tetapi sayangnya sangat mungkin untuk menghentikannya dengan menyentuh item daftar yang ditampilkan cukup sering.
Tapi sepertinya saya telah menemukan solusi yang dapat diterima. Dugaan saya bahwa bahkan jika Anda hanya bekerja pada utas ui adaptor tidak menerima banyak perubahan pada data itu tanpa menelepon
notifyDataSetChanged()
, karena ini saya membuat antrian yang menyimpan semua item baru sampai 300ms yang disebutkan selesai. Jika saat ini tercapai, saya menambahkan semua item yang disimpan dalam satu kesempatan dan panggilannotifyDataSetChanged()
. Sampai sekarang saya tidak dapat lagi crash daftar .sumber
Ini adalah bug yang dikenal di Android 4 hingga 4.4 (KitKat) dan diselesaikan di "> 4.4"
Lihat di sini: https://code.google.com/p/android/issues/detail?id=71936
sumber
Bahkan saya menghadapi masalah yang sama dalam aplikasi notifikasi XMPP saya, pesan penerima perlu ditambahkan kembali ke tampilan daftar (diimplementasikan dengan
ArrayList
). Ketika saya mencoba menambahkan konten penerima melaluiMessageListener
(utas terpisah), aplikasi berhenti dengan kesalahan di atas. Saya memecahkan ini dengan menambahkan konten ke metode sayaarraylist
&setListviewadapater
melaluirunOnUiThread
yang merupakan bagian dari kelas Activity. Ini menyelesaikan masalah saya.sumber
Saya menghadapi masalah yang sama, inilah cara saya memecahkan dalam kasus saya. Saya memverifikasi apakah
task
sudahRUNNING
atauFINISHED
karena tugas hanya dapat dijalankan sekali. Di bawah ini Anda akan melihat kode parsial dan diadaptasi dari solusi saya.sumber
Saya memiliki masalah yang sama dan saya menyelesaikannya. Masalah saya adalah bahwa saya menggunakan
listview
, dengan adaptor array dan dengan filter. Pada metode iniperformFiltering
saya mengacaukan array yang memiliki data dan itu adalah masalah karena metode ini tidak berjalan pada utas UI dan AKHIRNYA memunculkan beberapa masalah.sumber
Salah satu penyebab kecelakaan ini adalah bahwa
ArrayList
objek tidak dapat berubah sepenuhnya. Jadi, ketika saya menghapus item, saya harus melakukan ini:Ini memperbaiki crash untuk saya.
sumber
Dalam kasus saya, saya memanggil metode
GetFilter()
pada adaptor dariTextWatcher()
metode pada Kegiatan utama, dan saya menambahkan data dengan For loop onGetFilter()
. Solusinya adalah mengubah loop UntukAfterTextChanged()
sub metode pada Kegiatan utama dan menghapus panggilan keGetFilter()
sumber
sumber
Saya juga mendapatkan kesalahan yang sama persis dan menggunakan AsyncTask:
Saya menyelesaikannya dengan meletakkan
adapter.notifyDataSetChanged();
di bagian bawah utas UI saya, yaitu metode onyncTask AsyncTask saya. Seperti ini :Sekarang aplikasi saya berfungsi.
EDIT: Faktanya, aplikasi saya masih crash setiap 1 dari 10 kali, memberikan kesalahan yang sama.
Akhirnya saya menemukan
runOnUiThread
posting sebelumnya, yang saya pikir bisa bermanfaat. Jadi saya memasukkannya ke dalam metode doInBackground saya, seperti ini:Dan saya menghapus
adapter.notifyDataSetChanged();
metodenya. Sekarang, aplikasi saya tidak pernah macet.sumber
Silakan coba salah satu solusi ini:
Terkadang, jika Anda menambahkan objek baru ke daftar data di utas (atau
doInBackground
metode), kesalahan ini akan terjadi. Solusinya adalah: buat daftar sementara dan lakukan menambahkan data ke daftar ini di utas (ataudoInBackground
), kemudian lakukan menyalin semua data dari daftar sementara ke daftar adaptor di utas UI (atauonPostExcute
)Pastikan semua pembaruan UI disebut di utas UI.
sumber
Saya memiliki masalah yang sama ketika menambahkan data baru di lazy image loader yang baru saja saya taruh
di
semoga membantu anda
sumber
Seperti @Mullins berkata, "
Saya menambahkan item dan memanggil
notifyDataSetChanged()
thread UI dan saya menyelesaikan ini. - Mullins".Dalam kasus saya saya punya
asynctask
dan saya disebutnotifyDataSetChanged()
dalamdoInBackground()
metode dan masalah diselesaikan, ketika saya menelepon darionPostExecute()
saya menerima pengecualian.sumber
Saya punya kebiasaan
ListAdapter
dan meneleponsuper.notifyDataSetChanged()
di awal dan bukan di akhir metodesumber
Saya memiliki sittuation yang sama, saya memiliki banyak buttongroup menyisipkan item saya di listview dan saya mengubah beberapa nilai boolean di dalam item saya seperti holder.rbVar.setOnclik ...
masalah saya terjadi karena saya memanggil metode di dalam getView (); dan sedang menyimpan objek di dalam Sharepreference, jadi saya memiliki kesalahan yang sama di atas
Bagaimana saya memecahkannya; Saya menghapus metode saya di dalam getView () untuk notifyDataSetInvalidated () dan masalah hilang
sumber
Saya memiliki masalah yang sama. akhirnya saya mendapat solusinya
sebelum memperbarui tampilan daftar, jika tombol lunak hadir, tutup terlebih dahulu. setelah itu atur sumber data dan panggil notifydatasetchanged ().
sambil menutup keypad, listview internal akan memperbarui ui-nya. itu terus memanggil sampai menutup tombol. waktu itu jika sumber data berubah maka saya akan melemparkan pengecualian ini. jika data diperbarui di onActivityResult, ada kemungkinan kesalahan yang sama.
sumber
Solusi saya:
1) buat a
temp ArrayList
.2) lakukan pekerjaan berat Anda (sqlite row fetch, ...) dalam
doInBackground
metode dan tambahkan item ke temp arraylist.3) tambahkan semua item dari temp araylist ke daftar array listview Anda dalam
onPostExecute
metode.note:
Anda mungkin ingin menghapus beberapa item dari listview dan juga menghapus dari database sqlite dan mungkin menghapus beberapa file yang terkait dengan item dari sdcard, cukup hapus item dari database dan hapus file terkait mereka dan tambahkan mereka ke temp arraylist dibackground thread
. lalu masukUI thread
hapus item yang ada di temp arraylist dari daftar listview itu.Semoga ini membantu.
sumber