Является ли ArrayAdapter потоком безопасным в android? Если нет, что я могу сделать, чтобы сделать его потокобезопасным?

ArrayAdapter я расширяю ArrayAdapter и в коде, где я переопределяю getView(int i, View v, ViewGroup g) , я извлекаю текущий элемент с помощью getItem(i) . Могу ли я быть уверенным, что getItem(i) вернет элемент, даже если другие потоки будут обрабатывать один и тот же ArrayAdapter ?

Я не уверен, но я думаю, что ответ отрицательный. Если да, то что вы предлагаете сделать, чтобы сделать его потокобезопасным?

Solutions Collecting From Web of "Является ли ArrayAdapter потоком безопасным в android? Если нет, что я могу сделать, чтобы сделать его потокобезопасным?"

Дело не в том, что ArrayAdapter является потокобезопасным. ListView и другие подобные виджеты пользовательского интерфейса, которые работают с адаптером, не позволяют неожиданно изменять содержимое адаптера. И это больше, чем просто из-за других потоков – вам нужно сообщить ListView об изменении, которое вы сделаете, прежде чем он попытается взаимодействовать с вашим адаптером.

Если вы разрешаете другому потоку изменять адаптер или модифицируете его в основном потоке, но не сообщаете ListView об изменении, прежде чем разрешить что-либо еще, вы случайно (из-за расы) получите исключения, выданные ListView об изменении адаптера неожиданно.

В конкретном случае ArrayAdapter, если вы используете API для изменения его содержимого, он позаботится о том, чтобы показать представление списка об изменении. Однако вы должны внести такие изменения в основной поток, чтобы убедиться, что просмотр списка не пытается получить доступ к адаптеру между точкой, в которой выполняется ваше изменение, и о представлении списка об этом изменении.

Если вы просто делаете простые изменения в ArrayAdapter (добавив и удалив несколько элементов), тогда вы будете в порядке, но вы должны сделать это в основном потоке.

Для более значительных изменений (например, адаптер получает новый набор данных из-за получения новых данных с сервера). Подумайте, не используйте ArrayAdapter и вместо этого создайте собственный подкласс BaseAdapter. ArrayAdapter предназначен для ситуаций, когда у вас есть небольшой простой довольно статический набор данных для показа – простые ситуации. Для более сложных вещей вы, вероятно, будете счастливее, просто внедряя BaseAdapter и самостоятельно управляя данными.

Типичный способ обновления адаптера в этих сложных ситуациях состоит в том, что фоновый поток генерирует новый набор данных, и как только он будет доступен, в основном потоке он будет автоматически заменен на адаптер с вызовом notifyDataSetChanged (), чтобы ListView Что данные изменились.

Итак, скажем, вы показываете некоторые данные, которые представляют собой массив объектов MyItem. Храните данные в массиве воспроизведения:

 ArrayList<MyItem> 

Внедрите подкласс BaseAdapter, который показывает этот список:

 class MyAdapter extends BaseAdapter<MyItem> { ArrayList<MyItem> mItems; public int getCount() { return mItems != null ? mItems.size() : 0; } public MyItem getItem(int position) { return mItems.get(i); } ... } 

И теперь вот функция, которую вы можете реализовать на адаптере, который может быть вызван из другого потока, чтобы предоставить новый набор данных, который будет показан:

  final Handler mHandler = new Handler(); void setDataFromAnyThread(final ArrayList<MyItem> newData) { // Enqueue work on mHandler to change the data on // the main thread. mHandler.post(new Runnable() { @Override public void run() { mItems = newData; notifyDataSetChanged(); } }); } 

Конечно, если вы используете AsyncTask для создания ваших данных, у этого уже есть удобное средство для выполнения этой работы в основном потоке. Аналогично, вы можете использовать новый объект Loader, чтобы заботиться о генерации в фоновом режиме.

И если вы все еще хотите использовать ArrayAdapter, в своей функции выше вы можете сделать это, очистив текущие данные и добавив новые данные в теперь пустой адаптер. Это просто больше накладных расходов, которые на самом деле ничего не приносят вам.

Адаптер Array не является потокобезопасным. Я видел его сбой из-за проблем с параллелизмом. Адаптер массива преобразует ваш массив только в виде основного потока (GUI). Поэтому, если вы стараетесь только изменить массив (добавить или удалить) в основном потоке, вы можете убедиться, что он будет выполняться только каждый раз на 1 поток.