2017-01-08 3 views
4

Введение

да, это жесткий один. По крайней мере, я думаю ... Чтобы очистить вещи:не onClickListener работает (правильно) после того, как ConfigurationChange фрагментарно

Я не нашел ответа на мой вопрос, после того, как поиск в Интернете (с помощью Google).

Все, что я нашел, было о людях, Наладка onClickListener «S для их View» s неправильно. Я думаю, это та же проблема в моем случае, но ни одна из других проблем не соответствовала моей.

This похоже на ту же проблему ... У него нет ответов.

Настройка

У меня есть три Fragment, настроил вместе с ViewPager в моем AppCompatActivity.

viewPager = (ViewPager) findViewById(R.id.main_view_pager); 
viewPager.setAdapter(new SectionsPagerAdapter(getSupportFragmentManager())); 

Обращаем внимание на то, что SectionsPagerAdapter.

public class SectionsPagerAdapter extends FragmentPagerAdapter { 

    SectionsPagerAdapter(FragmentManager fm) { 
     super(fm); 
    } 

    @Override 
    public Fragment getItem(int position) { 
     switch (position) { 
      case 0: 
       return MainTextHolder.newInstance(tabIndicatorOnClick); 
      case 1: 
       return PostWriter.newInstance(tabIndicatorOnClick); 
      case 2: 
       return TopPage.newInstance(tabIndicatorOnClick); 
      default: 
       return Error.newInstance(); 
     } 
    } 

    @Override 
    public int getCount() { 
     return 3; 
    } 

    // ... more methods 
} 

В каждом из Fragment-х у меня есть некоторый контент плюс пользовательские TabIndicator.

(следующий xml файл мои View 's для индикатора)

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" > 

    <View 
     android:id="@+id/fragment_divider_one" 
     android:layout_width="0dp" 
     android:layout_height="match_parent" 
     android:layout_weight="1" 
     android:tag="one" /> 

    <View 
     android:id="@+id/fragment_divider_two" 
     android:layout_width="0dp" 
     android:layout_height="match_parent" 
     android:layout_weight="1" 
     android:tag="two" /> 

    <View 
     android:id="@+id/fragment_divider_three" 
     android:layout_width="0dp" 
     android:layout_height="match_parent" 
     android:layout_weight="1" 
     android:tag="three" /> 

</LinearLayout> 

А потом я установил OnClickListener для каждого из этих View-х (делителей) в onCreateView(LayoutInflater inflater, ViewGroup Bundle savedInstanceState) методе Fragment «s. OnClickListener уже подготовлен в моем Activity, где я также создаю экземпляр своего ViewPager, чтобы я мог изменить текущий Item (Fragment/tab).

private final View.OnClickListener tabIndicatorOnClick = new View.OnClickListener() { 
    @Override 
    public void onClick(View view) { 
     if (view.getTag().toString().equals("one")) 
      viewPager.setCurrentItem(0, true); // second argument for smooth transition 
     else if (view.getTag().toString().equals("two")) 
      viewPager.setCurrentItem(1, true); 
     else if (view.getTag().toString().equals("three")) 
      viewPager.setCurrentItem(2, true); 
    } 
}; 

я прохожу, что OnClickListener к Fragment «S, поместив его в мой newInstance(View.OnClickListener tabIndicatorOnClick) метод.

Это для одного из фрагментов. Это одинаково для других!

public static MainTextHolder newInstance(View.OnClickListener tabIndicatorOnClick) { 
    MainTextHolder fragment = new MainTextHolder(); 
    Bundle args = new Bundle(); 
    fragment.putIndicatorTabIndicatorOnClick(tabIndicatorOnClick); 
    fragment.setArguments(args); 
    fragment.setRetainInstance(true); 
    return fragment; 
} 

Мой putIndicatorTabIndicatorOnClick(View.OnClickListener tabIndicatorOnClick) метод в InterfaceVoid. Он просто применяет OnClickListener к Class (Fragment).

@Override 
public void putIndicatorTabIndicatorOnClick(View.OnClickListener tabIndicatorOnClick) { 
    this.tabIndicatorOnClick = tabIndicatorOnClick; 
} 

ли это работать

Да делает. Он отлично работает ... до тех пор, пока не произойдет ConfigurationChange.В моем случае я тестировал его с , изменяя ориентацию.

Проблема

Что происходит после того, как тот ConfigurationChange, что все идет нормально. OnClickListener применяется ко всем View «S в всеFragment» с, но tabIndicatorOnClickOnClickListener является ссылка нулевой объект во втором и третьем Fragment.

Так PostWriter и TopPage нет даже действительно OnClickListener на View-х по какой либо причине. Но становится лучше: в MainTextHolderFragmenttabIndicatorOnClick не является null object reference, но он не изменяет ViewPagerItem. Он запускает код, но не прокручивает Tab.

При включении «Не сохранять действия» Ind Параметры разработчика устройства и выходя из приложения, все OnClickListener «s являются null object references. Даже те, что в MainTextHolder.

Резюме

После ConfigurationChangeOnClickListener получают перешли в мой первый Fragment, но это не работает должным образом и в то Fragment остальных «ы он даже не прошел/а null object reference.

Вопрос может быть реплицироваться путем уничтожения Activity, а затем перезагрузить его.

В конце концов ...

... Я понятия не имею, что происходит неправильно. Надеюсь, что я правильно структурировал свой вопрос.

Может быть интерес

minSdkVersion:

targetSdkVersion:

У меня уже есть SpringIndicator на моем ViewPager. Это не имеет OnClickListener, поэтому я добавил свои собственные «наложенные» индикаторы, которые имеют необходимую функцию OnClick. Мне также нравится внешний вид, но если вы можете дать мне лучшее решение для моего TabIndicator, я также хотел бы получить это в качестве ответа.

я наткнулся на решение поставить прием в xml:onClick атрибут несколько раз, но для этого мне нужно было бы создать такой же OnClickListener для каждого Fragment, который на самом деле не хороший способ, и это также не решения моя проблема, но путь вокруг нее. - Мне нужно передать ViewPager в мой Fragment, а затем вызвать этот метод от xml, который, как я уже сказал, просто еще один способ сделать это, а не то, как я предпочитаю это делать. Также я не знаю, работает ли это. Скорее всего, я испытаю это.

Другие OnClickListener в Fragment все еще работают правильно. Так как я сказал, что проблема лежит в OnClickListener сама не работает правильно/null object reference.

+0

Вы пытались изменить свой манифест андроида: configChanges = "orientation | screenSize"? –

+0

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

+0

@MilosLulic да – creativecreatorormaybenot

ответ

2

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

Эта ошибка, похоже, исходит из того, что не учитывает изменения жизненного цикла фрагмента. Пока внутри ViewPager, фрагменты будут проходить через различные состояния, включая скрытые и отображаемые, когда они временно выключены, и приостанавливаются и возобновляются, если они находятся вне экрана, и система освобождает память и, наконец, создается и уничтожается, если система Android решает сохранить состояние экземпляра вашей деятельности (например, от изменения конфигурации). В последнем случае Android попытается восстановить состояние ваших фрагментов из состояния сохраненного экземпляра в вашем ViewPager. Поскольку у ваших фрагментов нет способа сохранить View.OnClickedListener, они были переданы в аргументы, они заканчиваются указателем null, когда они восстанавливаются, что вызывает вашу ошибку.

Чтобы исправить ошибку, я предлагаю вам не передавать View.OnClickedListener в качестве параметра для фрагментов. Скорее, выведите OnClickListener в свои фрагменты с помощью общедоступного метода в вашей деятельности и получите фрагменты в своем onResume(). Таким образом, вы можете гарантировать, что Фрагменты будут иметь ссылку на View.OnClickedListener всякий раз, когда они находятся в состоянии возобновления. Так что ваши onResume() может выглядеть примерно так:

@Override 
public void onResume() { 
    OnClickListener onClickListener = ((MyActivity) getActivity).getOnClickListener(); 
    putIndicatorTabIndicatorOnClick(onClickListener); 

}

Так как вы установили его в onResume(), вы должны удалить его в onPause():

@Override 
public void onPause() { 
    //set the onClickListener to null to free up the resource 
} 

Использование onResume() и onPause(), как это освобождение ресурсов от слушателей - это подход, рекомендованный в руководстве разработчика.

Конечно, вам необходимо убедиться, что ваша деятельность также управляет собственным жизненным циклом, проверяя сохраненное состояние в onCreate(Bundle savedInstanceState) и восстанавливая его соответствующим образом.

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

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

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

+0

Прежде всего, спасибо за ваш ответ. Большая информация. Хотя я не получил его на работу. Я понял, что в жизненном цикле метод 'onCreateView()' вызывается перед моим методом 'onResume()', поэтому мой указатель tabIndicator всегда имеет значение null при применении к 'View'. Я знаю, как обойти это, но есть ли способ лучше, чем устанавливать onClick в методе 'onResume()', который вам известен? – creativecreatorormaybenot

+0

Установка его в 'onResume()' является рекомендуемой практикой. Вы можете проверить жизненный цикл «Управление жизненным циклом» и соответствующие разделы Руководства для разработчиков. Фрагменты/действия не похожи на POJO, где вы всегда можете передавать зависимости в качестве параметров конструктора –

+0

Отлично! Спасибо за вашу помощь. У этого была какая-то действительно приятная дополнительная информация. – creativecreatorormaybenot

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