Intereting Posts
Изменение отображаемого ящика навигации. Цвет элемента по умолчанию. Сведения об уничтожении и отдыхе компонентов приложений Android Async / ждет плохой практики под Android? Как запустить работу приложения Имя в android 5.0 (L)? Сохранить / получить «Rich Formatted Text» в базе данных без потери формата Android Custom Gallery для отключения прокрутки Как обновить список расширяемых списков при добавлении к нему нового элемента Что происходит с базой данных после обновления приложения из магазина приложений? Уменьшите размер растрового изображения до указанного размера в Android React Native ListView TextInput блокируется от оптимизации оптимизации производительности Ошибка приложения при выборе / прокрутке элементов на Spinner. (LG Mobile) (java.lang.IllegalStateException: Итерация уже запущена) Как создать поле поиска в контекстной панели действий? SQLite DB, доступный из нескольких потоков Cordova 3.5.0 – FAILED renaming /storage/emulated/0/tmprecording.3gp Конструктор SimpleCursorAdapter (Context, int, Cursor, String , int ) устарел

Фрагмент OnClickListener, вызванный после onDestroyView

У меня проблема, когда ListFragment.onListItemClick вызывается после onDestroyView . Я получаю много сообщений об ошибках в поле (10-20 в день ~ 1000 активных пользователей), но единственным способом, который я нашел для его воспроизведения, является нажатие кнопки «Назад» при щелчке по всему экрану. Действительно ли сотни пользователей действительно это делают? Это след:

 java.lang.IllegalStateException: Content view not yet created at au.com.example.activity.ListFragment.ensureList(ListFragment.java:860) at au.com.example.activity.ListFragment.getListView(ListFragment.java:695) at au.com.example.activity.MyFragment.onListItemClick(MyFragment.java:1290) at au.com.example.activity.ListFragment$2.onItemClick(ListFragment.java:90) at android.widget.AdapterView.performItemClick(AdapterView.java:301) at android.widget.AbsListView.performItemClick(AbsListView.java:1519) at android.widget.AbsListView$PerformClick.run(AbsListView.java:3278) at android.widget.AbsListView$1.run(AbsListView.java:4327) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5293) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869) at dalvik.system.NativeStart.main(Native Method) 

getListView().getItemAtPosition вызовом getListView().getItemAtPosition в MyFragment.onListItemClick (MyFragment: 1290). Как getView может возвращать null во время обратного вызова обработчика щелчка? Я также решил, что фрагмент был отсоединен на этом этапе, isAdded () был ложным, а getActivity – null.

Одним из способов было бы заменить getListView на public void onListItemClick(ListView listView, View v, int position, long id) переданный из обратного вызова public void onListItemClick(ListView listView, View v, int position, long id) , но другим функциям все равно придется обновлять другие части пользовательского интерфейса, так что это будет просто Переместите проблему в другое место. Вместо этого я включил обратный вызов в onDestroyView :

 public void onDestroyView() { mHandler.removeCallbacks(mRequestFocus); if(mList!=null){ mList.setOnItemClickListener(null); } mList = null; mListShown = false; mEmptyView = mProgressContainer = mListContainer = null; mStandardEmptyView = null; super.onDestroyView(); } 

Но у меня все еще есть эта проблема onClick в других (не-список) фрагментах тоже. Как именно структура обычно подавляет эти обратные вызовы при удалении фрагмента (например, в onBackPressed -> popBackStackImmediate() )? В onDestroyView я исключаю дополнительные представления, которые я создал в onCreateView . Нужно ли вручную очищать каждого слушателя, который я задал?

Это аналогичная проблема с неотвеченным ответом q: Fragment getView (), возвращающим null в обратном вызове OnClickListener

Я использую setOnRetainInstance(true) в своих фрагментах, кстати.

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

В Android, когда вы меняете или создаете фрагменты, все это делается через ожидающие транзакции, если не сказано иначе. Это по существу гонка.

 getSupportFragmentManager().beginTransaction() .replace(R.id.container, new ExampleFragment() .commit(); 

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

Конечным результатом является то, что транзакция фрагмента обрабатывается, фрагмент View уничтожается, а затем вы вызываете getView() и он возвращает null.

Вы можете попробовать несколько вещей:

  1. getSupportFragmentManager().executePendingTransactions() Это приведет к выполнению всех ожидающих транзакций сразу и удаляет ожидающий аспект

  2. Проверьте, есть ли метод Fragment isVisible() или isAdded() или какой-либо другой фрагмент «is», который позволяет вам получать информацию о текущем состоянии текущего состояния, которое Fragment находится в его жизненном цикле, прежде чем выполнять код, который потенциально может быть запущен после Фрагмент зрения уничтожается (т. Е. Нажмите на прослушиватели)

  3. Поэтому давайте скажем, что у вас есть обработчик кликов, когда пользователь нажимает на то, что вы анималируете на другой фрагмент. Вы можете использовать что-то вроде приведенного ниже кода, который вы выполняете перед FragmentTransaction в своем внешнем виде (в фрагменте это будет то, что возвращается с getView() ), и это либо навсегда отключит клики для представления, если оно было Будут уничтожены или временно отключены клики в течение определенного периода времени, если вы собираетесь повторно использовать представление.

Надеюсь это поможет.


 public class ClickUtil { /** * Disables any clicks inside the given given view. * * @param view The view to iterate over and disable all clicks. */ public static void disable(View view) { disable(view, null); } /** * Disables any clicks inside the given given view for a certain amount of time. * * @param view The view to iterate over and disable all clicks. * @param millis The number of millis to disable clicks for. */ public static void disable(View view, Long millis) { final List<View> clickableViews = (millis == null) ? null : new ArrayList<View>(); disableRecursive(view, clickableViews); if (millis != null) { MainThread.handler().postDelayed(new Runnable() { @Override public void run() { for (View v : clickableViews) { v.setClickable(true); } } }, millis); } } private static void disableRecursive(View view, List<View> clickableViews) { if (view.isClickable()) { view.setClickable(false); if (clickableViews != null) clickableViews.add(view); } if (view instanceof ViewGroup) { ViewGroup vg = (ViewGroup) view; for (int i = 0; i < vg.getChildCount(); i++) { disableRecursive(vg.getChildAt(i), clickableViews); } } } } 

Стань моей рукой, это связано с дополнительными фрагментами без гражданства, которые живут где-то внутри вашего приложения. Я лично препятствовал бы сохранению экземпляра и позволял Android делать с ним все возможное, в то время как вы используете стандартный механизм для сохранения своего состояния (saveInstanceState, базы данных, классы / шаблоны высокого уровня, SharedPreferences и т. Д.).

Лично у меня было много проблем при сохранении экземпляра фрагмента (обычно при повторном создании или повторной активации фрагментов через изменения конфигурации или выходе и повторном входе в приложение), в результате, как правило, на двух фрагментах, один из которых связан с представлениями, Без гражданства, таким образом бесполезным; И «реальный», сохраняющий прежнее состояние без какой-либо связи с представлениями, следовательно, заканчивая исключениями и всякими причудами, которые вы не хотите иметь.

Начните с того, чтобы не сохранить экземпляр и посмотреть, что происходит.

Вы можете использовать mHandler.removeCallbacksAndMessages (null) для меня во многих ситуациях.