2013-09-12 3 views
3

Я выполняю некоторые тесты после настройки устройства изменения (изменение языка, ориентации и т. Д.), И я заметил, что после этого метод «notifyDataSetChanged()» не работает.notifyDataSetChanged после изменения конфигурации

Пример действия:

Я звоню updateList() каждый раз я выполнить действие, как удаление, сохранение и т.д. пользователь нажимает кнопку удаления, показана DialogFragment, «Вы уверены вы хотите delete? ", когда я изменяю ориентацию или язык или любую конфигурацию устройства, а затем нажмите« Да »в диалоговом окне, данные удаляются, но список не обновляется. Мне нужно прекратить действие, а затем вернуться, чтобы увидеть изменения.

BookAdapter:

public void updateList(ArrayList<Book> books) { 
    bookList = books; 
    notifyDataSetChanged(); 
} 

Что я могу сделать, чтобы сделать его работы после изменения конфигурации?

Edit:

BookAdapter Constructor:

public BookAdapter(Context c, ArrayList<Book> books) { 
    context = c; 
    bookList = books 
    bookDAO = BookDAO.getInstance(context); 
} 

BookFragment:

public class BookFragment extends Fragment { 

    private BookDAO bookDAO; 

    private BookAdapter bookAdapter; 

    private ListView listBook; 

    private View view; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 

     bookDAO = bookDAO.getInstance(getActivity()); 

     view = inflater.inflate(R.layout.book_tab, container, false); 

     ArrayList<Book> listBook = null; 

     try { 
      llistBook = bookDAO.getAll(); 
     } catch (Exception e) { 
      Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show(); 
      return view; 
     } 

     bookAdapter = new BookAdapter(getActivity(), listBook); 
     listBook = (ListView)view.findViewById(R.id.listBook); 
     listBook.setAdapter(bookAdapter); 

     return view; 

    } 

} 
+0

Насколько возможно, вы используете фрагменты, удерживающие этот адаптер? – Luksprog

+0

Да, я делаю! У меня есть один фрагмент для каждого адаптера, потому что я работаю с вкладками. – Otuyh

+0

Вкладки с 'ViewPager'? Если да, возможно, вы можете опубликовать код, который вы использовали для инициализации адаптера «ViewPager». Было бы полезно увидеть объявление полей и конструктор для 'BooksAdapter'. – Luksprog

ответ

2

Проблема возникает из-за того, что каждый раз, когда вы вращаетесь, меняете язык и т. Д., Активность воссоздается, а ваши фрагменты также воссоздаются (новый экземпляр), поэтому notififyDataSetChanged на самом деле уведомляет старые экземпляры ваших фрагментов. Решение для этого было бы. Сделайте свои фрагменты статичными. Затем вы создаете некоторый метод обновления для своих фрагментов и вызываете его, когда вы нажимаете «да» для своего диалога.

В вашей деятельности у вас должно быть что-то вроде этого.

private static BookFragment bookFragment; 
... 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
    ... 
    if (fragment1 == null) { 
     bookFragment = new BookFragment(); 
    } 

    ... 
} 

Создать некоторый интерфейс, как:

public interface Refreshable { 
    public void refresh(); 
} 

Затем реализовать этот интерфейс все ваши фрагменты. В методе, который вызывается, когда диалог положительного ответа, вы должны позвонить

... 
fragment.refresh(); 
... 

Внутри методе обновления из вас фрагмента вы можете вызвать его метод адаптера updateList (...)

не может быть более красивое решение, но оно работает ...

Почему это происходит ... Google Dev Team может знать об этом.

+0

Святой бог, это сработало! Я действительно хочу увидеть другие варианты, но этот ответ действительно решил мою проблему! Большое спасибо, Ygor! – Otuyh

0

Я использую ArrayList строк в моей GridViewAdapter, который проходит BaseAdapter.

поэтому в случае, если я изменил данные, касающиеся списка, я cann notifyDataSetChanged() на адаптере. Я действительно не вижу смысла, почему вы не можете назвать это?

Так что я хотел бы сделать это ovverride этот метод, а просто вызвать notifyDataSetChanged()

@Override 
public void onConfigurationChanged(Configuration newConfig) { 
    super.onConfigurationChanged(newConfig); 
    adapter.notifyDataSetChanged(); 
} 

Кроме того, ваша книга chnage данных на основе вашей конфигурации/ориентации?

0

Попробуйте использовать один и тот же список в течение всего жизненного цикла адаптера, и изменить только его содержание:

public class BookAdapter extends ArrayAdapter<Book> { 

    private final booklist; 
    // .. 

    public BookAdapter(Context c, ArrayList<Book> books) { 
     super(c, R.layout.yourlayout, books); 
     context = c; 
     bookList = books 
     bookDAO = BookDAO.getInstance(context); 
    } 

    public void updateList(ArrayList<Book> books) { 
     bookList.clear(); 
     boolList.addAll(books); 
     notifyDataSetChanged(); 
    } 

    // .. 
} 
+0

Не работал = ( – Otuyh

-1

Я думаю, что проблема исходит из того, что любые изменения конфигурации, такие как ориентация будет перезагружен текущий Activity.

Из-за этого, я думаю, некоторые части вашего кода по-прежнему ссылаются на предыдущую деятельность, которая больше не существует, а notifyDataSetChanged больше не работает.

Есть 2 вещи, которые вы можете быстро попробовать:

  1. Добавить эту строку в файле манифеста для вашей деятельности: android:configChanges="orientation|locale". Это изменение означает, что система будет обрабатывать изменения, которые необходимо внести во время ориентации или изменения языка. Таким образом, приложение больше не будет воссоздавать активность самостоятельно (поэтому активность должна работать одинаково).

  2. Другой трюк может быть, чтобы добавить эту строку в начале функции onCreateView: setRetainInstance(true);. Эта линия будет сохранять состояние фрагмента во время изменения конфигурации, как объясняет документация: это

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

  • OnDestroy() не будет вызываться (но onDetach() будет по-прежнему, потому что фрагмент будучи отделен от своей текущей деятельности).
  • onCreate (Bundle) не будет вызываться, так как фрагмент не будет воссоздан.
  • onAttach (Activity) и onActivityCreated (Bundle) по-прежнему будут вызываться.

Просто быть информирован о том, что, как объяснил Fragment жизненный цикл будет немного изменить.

3) Последний вариант может быть, чтобы сохранить состояние активности с использованием onSaveInstanceState и onRestoreInstanceState, как описано подробно в этом ответе: https://stackoverflow.com/a/151940/2206688

+0

Число 1, я даже не пытаюсь сделать, ориентация и локаль - не единственные изменения, которые могут произойти. Я пробовал номер 2, я все еще могу воспроизвести проблему =/ – Otuyh

+0

Я добавил Третья идея, но дольше, чем установка, которая позволит вам сохранить состояние активности. –

6

Вы можете попробовать реализовать BookAdapter как Singleton, чтобы подтвердить, что вы не зовете updateList(..) от устаревшая ссылка.

Изменения, которые вам нужно будет сделать:

// I am assuming that you are using a BaseAdapter because 
// BookAdapter's constructor that you provided in the code above 
// does not contain a call to super(....) 
public class BookAdapter extends BaseAdapter { 

    private static BookAdapter mAdapter; 
    private Context context; 
    private static ArrayList<Book> bookList; 
    private BookDAO bookDAO; 

    // To keep at most one instance of BookAdapter 
    public static BookAdapter getInstance(Context con, ArrayList<Book> books) { 

     // If an instance exists, return it 
     if (mAdapter != null) { 
      bookList = books; 
      return mAdapter; 
     } 

     // Else, craete a new instance 
     mAdapter = new MyAdapter(con, books); 
     return mAdapter; 
    } 

    // BookAdapter's only constructor is declared as private to restrict access 
    private BookAdapter(Context con, ArrayList<Book> books) { 
     context = con; 
     bookList = books; 
     bookDAO = BookDAO.getInstance(context); 
    } 

    public void updateList(ArrayList<Book> books) { 
     bookList = books; 
     notifyDataSetChanged(); 
    } 

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

     // Retrieve object 
     Book bookItem = bookList.get(position); 

     .... 
     .... 

} 

} 

Это как onCreateView фрагмента изменится:

bookAdapter = BookAdapter.getInstance(getActivity(), listBook); 

код, который будет выполняться, когда пользователь нажимает да Are you sure you want to delete?:

// Remove entry from bookDAO 
// Remove entry from listBook 
// OR update listBook: 
try { 
    listBook = bookDAO.getAll(); 
} catch (Exception e) { 
    Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show(); 
} 

// Assertion: "listBook" does not contain the 
// item that was just deleted from "bookDAO" 

// Update ListView's contents 
bookAdapter.updateList(listBook); 
+0

Вид работы, но не полностью. Когда я меняю конфигурацию, при открывшемся диалоговом окне она не может снова отобразить диалог. Сообщение: Невозможно выполнить это действие после onSaveInstanceState ", когда я попытался открыть диалог после изменения конфигурации. – Otuyh

+0

@Hor Не могли бы вы объяснить часть« Вид обработанной »? И на данный момент вы используете рекомендации других ответов вместе с моими • Если возможно, отмените сделанные вами изменения, пока не дойдете до того, где все работает: за исключением того, что данные ListView не обновлялись. – Vikram

+0

Kind отработанных, потому что список был обновлен после удаления. И да, я откат до такой степени, что все работает. НО, теперь, когда я меняю конфигурацию, я не могу снова открыть диалоговое окно. Это сообщение, о котором я говорю в другом комментарии, появляется. – Otuyh

0

Почему вы храните свой Просмотр как элемент данных?

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

Попробуйте удалить это поле и использовать его и посмотреть, обновлен ли список.

+0

Что вы подразумеваете под «элементом данных»? Во всяком случае, я удалил View, используя только локальное свойство. Та же проблема. – Otuyh

Смежные вопросы