【问题标题】:Setting RadioButton.setChecked with Multiple Fragments使用多个片段设置 RadioButton.setChecked
【发布时间】:2017-09-01 02:01:59
【问题描述】:

嘿,我有一个非常愚蠢的问题,我不知道为什么它没有按预期工作。 所以我有一个使用 viewpager 和 FragmentStatePagerAdapter 的 MultiFragment 布局(每个都有一些不同的问题)。 当我打开包含所有这些片段的屏幕时,我正在尝试使用网络调用恢复以前的状态(标记所有已回答的问题)。 但是,如果我的 Fragment 对用户不可见,它似乎无法更新单选按钮/复选框的选中状态。

有人知道我可以做些什么来实现期望的行为吗?

提前干杯和感谢!

 @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;
    }

【问题讨论】:

  • 您必须等待片段可见,然后更新按钮/复选框的检查状态。
  • 我在这里添加了我的代码
  • 问题是我需要在 onViewCreated 和变得可见时执行两次请求,因为每当用户输入新选项卡时我总是想显示最新状态,但它似乎不是在 viewpager 中的第一个片段上触发,并且由于我动态添加它们(仅 2 或 3 个)可以在某些时候添加我必须进行网络调用
  • 所以你说 onViewCreated 没有被调用,或者你在每次滑动时调用 api(你不想要)?
  • 我在描述中添加了一张图片,它显示了不想要的行为,这些字段以某种方式预先选择,但这不是我需要的正常检查状态,如果我设置 setChecked() 和设置 this 的片段不可见

标签: android android-fragments android-viewpager radio-button


【解决方案1】:

更新

Here 是一个工作示例,您可以查看它。

我认为您正在恢复主机 Activity 上的状态。不要这样做,在每个Fragment 中都这样做。假设您有两个片段,PassformMaterial,所以不要在 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;
}

根据您的需要,在 onPostExecuteFetchPassFormState 中更新 views 或任何您想要的位置。

更新

你可以做一件事。您必须在您的QuestionsViewPagerAdapter 中添加Fragments,尝试在您的Fragments 中添加setArguments。喜欢,

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

现在添加这个fragment。在FragmentonCreateView 中,得到这个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");
    ...
}

然后使用这些数据来设置视图。

【讨论】:

  • 您在问题中说When I open the screen that hosts all these fragments I am trying to restore the previous state (marking all answered questions) 。这就是为什么我建议你这样做。你能告诉我你的主机ActivityFragmentonCreateView了解更多细节吗?
  • 我用你想要的东西添加了 2 个要点,我很绝望,所以我尝试两者都做,恢复活动中的状态并将值传递给片段,但我最初的方法是加载片段内的数据(但是我会执行 3 次相同的请求,这就是为什么我将加载移动到活动的中心位置)
  • 是的,我认为这并不能解决我的问题,因为我已经这样做了,不同之处在于我正在解析 onCreate 中的参数
【解决方案2】:

你需要使用setOffscreenPageLimit

viewPager.setOffscreenPageLimit(<total_page_count>);

如文件所述

设置在空闲状态下视图层次结构中当前页面任一侧应保留的页面数。超出此限制的页面将在需要时从适配器重新创建。

【讨论】:

  • 这也无济于事,我仍然只看到一个专注的状态,但他们没有被“选中”
  • @dhartwich 这将有助于在 ViewPager 中滑动时不重新创建片段。您需要手动更新您的复选框。
【解决方案3】:

我认为您遇到的问题之一是在 onCreateView 中进行恢复。

这是我在片段变得可见时通过调用 web 服务来更新片段的方式。

callToRestore() 触发异步 Web 服务调用(使用 ion),之后我得到一个填充片段信息的回调。

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;
                }

            }
        }

【讨论】:

  • 我都尝试了(在 onCreateView 和 setUserVisibleHint 中进行),但没有显示我想要的结果
  • 这三个组件你加了吗?成员变量 restoreOnHold、onResume() 和 setUserVisibleHint() ?如果您在 setUserVisibleHint 上设置断点,您的 ViewPager 是否调用了该方法?
  • 我不知道您描述的 restoreOnHold 字段,如果该片段不是用户看到的第一个片段,则调用了 setUserVisibleHint 方法(第一个片段也从未存在此问题)
  • 您必须添加该成员变量,因为它是在 onResume 方法和 setUserVisibleHint 方法中都检查的标志。它的作用取决于首先调用哪个方法。查看我作为答案发布的所有内容,三个组件。
  • 所以你的意思是它可能是一种并发问题?而且我应该只做一次我的请求,这样我就不会设置状态两次?我理解正确吗?
【解决方案4】:

在托管主要片段时尝试在网络调用后将答案保存在一个模型类中,然后在每个片段中使用该模型类来填充详细信息。

【讨论】:

    【解决方案5】:

    首先,当您创建活动时,请执行以下步骤。 1.所有数据的网络调用。 2. 在成功的结果中,为不同的片段分离数据。在你的情况下,我猜是 4 个片段。 3.设置视图寻呼机并添加片段。 4. 使用 fragment.setArguments(bundle) 将各自的数据发送到 Fragment,并使用 getArguments 获取数据。 5. 在片段的 onCreateView 上将结果设置为单选按钮/复选框。

    创建活动:

    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;
    }
    

    总结:对活动进行网络调用并将结果发送到各个片段以显示。

    【讨论】:

      【解决方案6】:

      我同意 Kirankumar Zinzuvadia 的评论

      我在 ViewPager 中的 RadioButton 遇到了完全相同的问题。原因是 setChecked() 在不可见时不起作用。

      所以我在 ViewPager.OnPageChangeListener.onPageSelected() 上调用了 setChecked()

      Java>

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

      科特林>

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

      【讨论】:

        【解决方案7】:

        由于您的片段(即 VIEWS!)处理数据,因此您在正确的时间更新它们时遇到了问题。我希望这给你一个好的开始更多的编码:-)

        ** 编辑:我想指出我对 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];
            }
        }
        

        【讨论】:

          【解决方案8】:

          我的测验应用也有同样的问题。而且我发现了一件事,当调用radioButton.setChecked(true); 函数时,android 系统没有更新UI。但它反映在代码内部(当您检查它时 - 是否检查)。

          要解决此问题,您必须使用小部件 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;
              }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-04-10
            • 1970-01-01
            • 1970-01-01
            • 2018-09-04
            • 2014-01-11
            • 2021-10-07
            • 2023-04-09
            相关资源
            最近更新 更多