Подтвердить что ты не робот

Настройка RadioButton.setПроверено несколькими фрагментами

Эй, у меня есть действительно глупая проблема, и я не могу понять, почему она работает не так, как ожидалось. Поэтому у меня есть макет MultiFragment (у каждого есть несколько разных вопросов), используя viewpager и FragmentStatePagerAdapter. Когда я открываю экран, на котором размещаются все эти фрагменты, я пытаюсь восстановить предыдущее состояние (отмечая все ответы на вопросы) с помощью сетевого вызова. Однако кажется, что если мой фрагмент не отображается пользователю, он не может обновить проверенное состояние переключателя/флажков.

введите описание изображения здесь

Кто-нибудь знает, что я могу сделать для достижения желаемого поведения?

Приветствия и благодарности заранее!

 @Override
 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
     super.onViewCreated(view, savedInstanceState);
     presenter.restoreAnswersFromPreviousSession(questionId);
}

@Override 
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisible()) {
        if (isVisibleToUser) {
            presenter.restoreAnswersFromPreviousSession(questionId);
            Log.d("Fit", "My Fragment is visible");
        } else {
                   Log.d("Fit", "My Fragment is not visible");
               }
    }
}

Здесь я восстанавливаю состояние (вызывается после успешного запроса)

previousReplies = repliesToRestore;
for (QualityReportReply reportReply : repliesToRestore) {
  int id = reportReply.id();
  switch (id) {
    case 201: {
      boolean tooThin = (boolean) reportReply.value();
      if (tooThin) {
        materialTooThinGroupYes.setChecked(true);
      } else {
        materialTooThinGroupNo.setChecked(true);
      }
      break;
    }
    case 202: {
      boolean tooThick = (boolean) reportReply.value();
      if (tooThick) {
        materialTooThickGroupYes.setChecked(true);
      } else {
        materialTooThickGroupNo.setChecked(true);
      }
      break;
    }
    case 203: {
      boolean drawingThreads = (boolean) reportReply.value();
      if (drawingThreads) {
        materialDrawThreadsGroupYes.setChecked(true);
      } else {
        materialDrawThreadsGroupNo.setChecked(true);
      }
      break;
    }
    case 204: {
      boolean flyingThreads = (boolean) reportReply.value();
      if (flyingThreads) {
        materialFlyingThreadsGroupYes.setChecked(true);
      } else {
        materialFlyingThreadsGroupNo.setChecked(true);
      }
      break;
    }
    case 205: {
      boolean knots = (boolean) reportReply.value();
      if (knots) {
        materialKnotsGroupYes.setChecked(true);
      } else {
        materialKnotsGroupNo.setChecked(true);
      }
      break;
    }
4b9b3361

Ответ 1

UPDATE

Здесь - рабочий пример, вы можете его увидеть.

Я думаю, что вы восстанавливаете состояние на хосте Activity. Не делайте этого, делайте это в каждом Fragment. Скажем, у вас есть два фрагмента, Passform и Material, поэтому вместо того, чтобы делать это в Activity, сделайте вызов внутри фрагмента onCreateView.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_passform, container, false);
    new FetchPassFormState().execute();
    return view;
}

Обновить views внутри onPostExecute FetchPassFormState или где угодно, в соответствии с вашими потребностями.

UPDATE

Вы можете сделать одно. Вы должны добавить Fragments в свой QuestionsViewPagerAdapter, попробуйте setArguments вашего Fragments там. Как,

Fragment fragment = new YourFragment();
Bundle bundle = new Bundle();
bundle.putString("your_key", "Your Data");
...
fragment.setArguments(bundle);

Теперь добавьте этот Fragment. И внутри Fragment onCreateView, получим этот Bundle.

@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_material_questions, container, false);
    ButterKnife.bind(this, view);
    getFragmentComponent().inject(this);
    presenter.setView(this);

    Bundle bundle = getArguments();
    String youdData = bundle.getString("your_key");
    ...
}

И затем используйте эти данные для установки представлений.

Ответ 2

Вам нужно использовать setOffscreenPageLimit

viewPager.setOffscreenPageLimit(<total_page_count>);

Как говорится в документах

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

Ответ 3

Я думаю, что одна из проблем, которые у вас есть, - это сделать восстановление в onCreateView.

Так я обновляю свои фрагменты, вызывая веб-службы, когда фрагмент становится видимым.

callToRestore() запускает вызов async webservice (с использованием иона), после которого я получаю обратный вызов, который заполняет информацию моего фрагмента.

protected boolean restoreOnHold = false;

    @Override
        public void onResume() {
            super.onResume();
            if(restoreOnHold ){
                restoreOnHold = false;
                callToRestore();
            }
        }

    @Override
        public void setUserVisibleHint(boolean isVisible){
            super.setUserVisibleHint(isVisible);
            if (isVisible) {
                if(getView() != null){
                    restoreOnHold = false;

                    callToRestore();

                }else{
                    restoreOnHold = true;
                }

            }
        }

Ответ 4

Так как ваши фрагменты (которые являются VIEWS!) обрабатывают данные, у вас возникают проблемы с их обновлением в нужное время. Надеюсь, это даст вам хорошее начало для большего количества кодировок:-)

** edit: я хочу указать свой комментарий на putAllAnswersFromPreviousSessions (DataObject mObject)

    public class QuestionPagerAdapter extends FragmentStatePagerAdapter {

    private List<Fragment> mFragments;
    private Bundle mData = null;

    public QuestionPagerAdapter(FragmentManager fm) {
        super(fm);
        // u can add and remove fragments anytime during runtime with this List<Fragments>
        mFragments = new ArrayList<>();
    }

    /**
     * Everytime we show a new position, set your Bundle to your Fragments.
     * @param position
     * @return fragment with data;
     */
    @Override
    public Fragment getItem(int position) {
//        Note, that the method .setArguments(Bundle bundle) should only be called,
//        before the Fragments are attached. Therefore, we need to
//        @Override getItemPosition(Obj) to ensure, that your Fragments are redrawn, when selected;
        mFragments.get(position).setArguments(mData);
        return mFragments.get(position);
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

    @Override
    public int getCount() {
        return mFragments.size();
    }

    /**
     * Invoke this Method from your activity, when u get your data from the internet;
     * You could register an receiver inside your activity and when u get an result from your AsyncTask,
     * u could call
     *          mQuestionPagerAdapter.putAllAnswersFromPreviousSessions(result);
     *          mQuestionPagerAdapter.notifyDataSetChanged();
     * @param mObject a simple data object.
     */
    public void putAllAnswersFromPreviousSessions(DataObject mObject){
        Bundle dataObject = new Bundle();
        boolean[] mReceivedData = mObject.getAllAnswers();
        for (int i = 0; i < mReceivedData.length; i++){
            dataObject.putBoolean("answer_"+String.valueOf(i), mReceivedData[i]);
        }
        this.mData = dataObject;
    }
}

Если вы заботитесь о том, чтобы ваши данные загружались перед показом ваших фрагментов, вы не должны вызывать mQuestionPagerAdapter.notifyDataSetChanged(). Этот метод заставляет FragmentStatePagerAdapter перерисовывать ваши фрагменты, и положение экрана будет потеряно (тот же фрагмент будет показан, хотя:-))

Еще один аккуратный трюк, который я узнал, - это получение ваших данных в любое время из вашего FragmentStatePagerAdapter:

     @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 
            super.onViewCreated(view, savedInstanceState);
            mViewPager = (ViewPager) getActivity().findViewById(R.id.view_pager);
            mStatePagerAdapter = (FragmentStatePagerAdapter) mViewPager.getAdapter();
        }

При использовании обоих подходов вы должны иметь возможность хранить свои данные за пределами своих представлений (ваши фрагменты) и получать/устанавливать их, когда вам нужно.

public class DataObject {

    private boolean[] mAnswersFromPreviousSessions;

    /**
     * This data-object is a suggestion.
     * Since u need to decide between three states (true / false / empty),
     * u should work with enums e.g.
     * @param answers your data..
     */
    public DataObject(boolean[] answers) {
        super();
        this.mAnswersFromPreviousSessions = answers;
    }

    /** get all answers, or **/
    public boolean[] getAllAnswers() {
        return mAnswersFromPreviousSessions;
    }

    /** just ask for a specific one **/
    public boolean getAnswerFor(int questionPosition){
        return mAnswersFromPreviousSessions[questionPosition];
    }
}

Gruß

** следующее редактирование: я не знаю, почему я получаю мгновенно вниз, но мой подход соответствует его требованиям. Он получает свои данные в setArguments(), даже до создания Фрагмента. Поэтому он может даже применить его в OnCreateView(). Прокомментируйте @downvote.

Ответ 5

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

Ответ 6

Прежде всего, когда вы создаете действие, выполните следующие действия. 1. Сетевой вызов для всех данных. 2. При успешном результате разделите данные для разных фрагментов. В вашем случае 4 фрагмента, я думаю. 3. настроить просмотр пейджера и добавить фрагменты. 4. Отправляйте соответствующие данные фрагментам с помощью фрагмента .setArguments(bundle) и получайте данные с помощью getArguments. 5. Задайте результат для вашего переключателя/флажков на onCreateView вашего фрагмента.

Действие onCreate:

public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    // load the layout
    setContentView(R.layout.activity_layout);

    //  Your network call
    presenter.restoreAnswersFromPreviousSession(questionId);

}
@Override
public void onSuccess(Object result){

      // setup view your view pager and fragments here.
      // add restored replies to fragments.

      Fragment fragment = new FragmentOne();
      Bundle bundle = new Bundle();
      bundle.putExtra("restored_replies", replies);
      fragment.setArguments(bundle);

}

И получите восстановленные ответы на onCreateView для каждого фрагмента. Установите флажки/радиокнопки в соответствии с полученными данными.

@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      View view = inflater.inflate(R.layout.fragment_questions, container, false);

      ...
      Bundle bundle = getArguments();
      Object data = bundle.getSerializableExtra("restored_replies"); 
      // Serialize object before passing as an argument.
      // set you check boxes and radio buttons according to the data received.
      ...

      return view;
}

Сводка: Сделать сетевой вызов по активности и отправить результат на соответствующие фрагменты, чтобы показать.

Ответ 7

Я с комментарием Киранкумара Зинзувадия

У меня была точно такая же проблема с RadioButton во ViewPager. Причина в том, что setChecked() не работает, когда он невидим.

Поэтому я вызвал setChecked() для ViewPager.OnPageChangeListener.onPageSelected()

Jav

@Override 
public void onPageSelected(int position){
    if(position == 2){
        materialTooThinGroupYes.setChecked(true);
    }
}

Котлин>

override fun onPageSelected(position: Int) {
    if(position == 2){
        materialTooThinGroupYes.isChecked = true;
    }
}

Ответ 8

У меня такая же проблема с моим приложением Quiz. И я обнаружил одно: система Android не обновляет пользовательский интерфейс при вызове функции radioButton.setChecked(true);. Но это внутренне отражается в коде (когда вы его проверяете - проверено или нет).

Чтобы устранить эту проблему, вы должны использовать следующий вызов функции виджета RadioButton.

radioButton.setSelectedState(true); //This makes the ui selected. use false to make the ui not selected.

Здесь, как и для вашего кода, вы должны изменить свою функцию на

previousReplies = repliesToRestore;
for (QualityReportReply reportReply : repliesToRestore) {
  int id = reportReply.id();
  switch (id) {
    case 201: {
      boolean tooThin = (boolean) reportReply.value();
      if (tooThin) {
        materialTooThinGroupYes.setChecked(true); //Keep it if you want to get the values from the code
        materialTooThinGroupYes.setSelectedState(true); //To Change the UI
      } else {
        materialTooThinGroupNo.setChecked(true);
        materialTooThinGroupNo.setSelectedState(true); //To Change the UI
      }
      break;
    }
    case 202: {
      boolean tooThick = (boolean) reportReply.value();
      if (tooThick) {
        materialTooThickGroupYes.setChecked(true);
        materialTooThickGroupYes.setSelectedState(true); //To Change the UI
      } else {
        materialTooThickGroupNo.setChecked(true);
        materialTooThickGroupNo.setSelectedState(true); //To Change the UI
      }
      break;
    }
    case 203: {
      boolean drawingThreads = (boolean) reportReply.value();
      if (drawingThreads) {
        materialDrawThreadsGroupYes.setChecked(true);
        materialDrawThreadsGroupYes.setSelectedState(true); //To Change the UI
      } else {
        materialDrawThreadsGroupNo.setChecked(true);
        materialDrawThreadsGroupNo.setSelectedState(true); //To Change the UI
      }
      break;
    }
    case 204: {
      boolean flyingThreads = (boolean) reportReply.value();
      if (flyingThreads) {
        materialFlyingThreadsGroupYes.setChecked(true);
        materialFlyingThreadsGroupYes.setSelectedState(true); //To Change the UI
      } else {
        materialFlyingThreadsGroupNo.setChecked(true);
        materialFlyingThreadsGroupNo.setSelectedState(true); //To Change the UI
      }
      break;
    }
    case 205: {
      boolean knots = (boolean) reportReply.value();
      if (knots) {
        materialKnotsGroupYes.setChecked(true);
        materialKnotsGroupYes.setSelectedState(true); //To Change the UI
      } else {
        materialKnotsGroupNo.setChecked(true);
        materialKnotsGroupNO.setSelectedState(true); //To Change the UI
      }
      break;
    }