如何在不同的片段上使用 ModelView 来获取 EditText 的输入并将 TextView 设置为其值?

How to use ModelView on different Fragments to get the input of an EditText and set a TextView to its value?

所以基本上我想要实现的是将 EditText 的输入显示到另一个 Fragment 的 TextView 中。因此,用户回答一个问题并单击一个按钮,该按钮将他带到下一个片段,在 TextView 中应显示他的答案。由于我使用相同的方法有 3 个问题,因此我使用 ModelView 来实现此目的。由于我对编程比较陌生,所以我不知道这是否是我实现它的正确方法。非常感谢您的帮助!

这是我的视图模型:

public class SharedViewModel extends ViewModel {


private HashMap<Integer, MutableLiveData<String>> answers = new HashMap<>();

public MutableLiveData<String> getAnswer(int questionId) {
    return answers.get(questionId);
}

public void setAnswer(int questionId, String answer) {
    if (answers.get(questionId) != null) {
        answers.get(questionId).setValue(answer);
    }
}
}

这是我第一个问题的第一个片段:

   ...

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

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

        btnNavFrag1 = view.findViewById(R.id.btn_question1);

        mEditTextQuestion1 = view.findViewById(R.id.edit_text_question_1);

        btnNavFrag1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                viewModel.getAnswer(1);

                ((GameActivity)getActivity()).setViewPager(2);

            }
        });

        return view;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        viewModel = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        viewModel.getAnswer(1).observe(getViewLifecycleOwner(), new Observer<CharSequence>() {
            @Override
            public void onChanged(@Nullable CharSequence charSequence) {
                mEditTextQuestion1.setText(charSequence);
            }
        });
    }

这是我的答案概述片段,它显示在第一个问题片段之后,输入的答案应该替换 TextView 的默认值:

   ...

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

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

        btnNavFragAns1 = view.findViewById(R.id.next_question_1);

        tv_answer1 = view.findViewById(R.id.answer_player_1_text_view);

        btnNavFragAns1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                ((GameActivity)getActivity()).setViewPager(3);

            }
        });

        return view;
    }

    @Override
    public void onActivityCreated(Bundle bundle) {
        super.onActivityCreated(bundle);

        viewModel = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        viewModel.getAnswer(1).observe(getViewLifecycleOwner(), new Observer<CharSequence>() {
            @Override
            public void onChanged(@Nullable CharSequence charSequence) {
                tv_answer1.setText(charSequence);
            }
        });
    }
    }

Currently I get a NullPointerException at this line:

    viewModel.getAnswer(1).observe(getViewLifecycleOwner(), new Observer<CharSequence>() {

在代码的这个特定部分:您没有为 get answer on key 1 设置任何值,您应该首先输入 MutableLiveData"1":

viewModel.getAnswer(1)

首先你必须在 private HashMap<Integer, MutableLiveData<String>> answers = new HashMap<>();:

中输入一些东西作为键 1
answers.put(1, new MutableLiveData<String>());

之后您可以通过代码访问可变的实时数据:viewModel.getAnswer(1)

public void setAnswer(int questionId, String answer) {
    if (answers.get(questionId) != null) {
        answers.get(questionId).setValue(answer);
    }
}

LiveData 初始化错误。 您正在访问它而无需在 OnActivityCreated() 中进行内部初始化。 首先初始化你的 mutablelivedata。

我将举例说明如何使用 ViewModel 解决您的问题。

视图模型

public class ViewModel_RoutineStartConnection extends AndroidViewModel{

public ViewModel_RoutineStartConnection(
      @NonNull Application application) {
    super(application);
  }

private MutableLiveData<String> sAnswer = new MutableLiveData<>();

public void setAnswer(String sAnswer){
 this.sAnswer.post(sAnswer);
}

public LiveData<String> getsAnswer(){
return this.sAnswer;
}

}

使用 EditText 设置值的片段

public class Fragment_getAnswer extends Fragment {

private ViewModel_RoutineStartConnection myViewModle;
private EditText edittext;

@Nullable
  @Override
  public View onCreateView(
      @NonNull LayoutInflater inflater,
      @Nullable ViewGroup container,
      @Nullable Bundle savedInstanceState) {
    View root =
        inflater.inflate(R.layout.YOURLAYOUT, container, false);

edittext = root.findViewById(R.id.YOURID);
edittext.setOnEditorActionListener(listener);

return root;
}

@Override
  public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    myViewModle = ViewModelProviders.of(getActivity()).get(ViewModel_RoutineStartConnection.class);

  }

public TextView.OnEditorActionListener listener = new OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) {
      if (i == EditorInfo.IME_ACTION_DONE) {
         myViewModle.setAnswer(edittext.getText.toString);
      }
      return false;
    }
  };
}

片段读取值

public class Fragment_setAnswer extends Fragment {

private ViewModel_RoutineStartConnection myViewModle;
private TextView textview;

@Nullable
  @Override
  public View onCreateView(
      @NonNull LayoutInflater inflater,
      @Nullable ViewGroup container,
      @Nullable Bundle savedInstanceState) {
    View root =
        inflater.inflate(R.layout.YOURLAYOUT, container, false);

textview= root.findViewById(R.id.YOURID);

return root;
}

@Override
  public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    myViewModle = ViewModelProviders.of(getActivity()).get(ViewModel_RoutineStartConnection.class);
 myViewModle.getsAnswer.observe(getViewLifecycleOwner(), obs_getsAnswer):
  }

private Observer<String> obs_getsAnswer= new Observer<String>() {
    @Override
    public void onChanged(@Nullable String sAnswer) {
      textview.setText(sAnswer);
    }
  };

}

要对所有答案使用此方法,我建议为每个答案添加一个 "id"。 所以当你设置 setAnswer("01" + answerText)

当您观察数据时,您可以使用:

switch(sAnswer.subString(0,3)){
case "01":
//set answer text for answer 1
break;

经过长时间的尝试,我找到了解决问题的正确方法:

我正在使用 ViewModel,因此 6 个不同的片段可以在 ViewModel 的函数中存储和检索数据。所以基本上,如果你有一个片段,其中有一个 EditText 并想在另一个片段中显示它的输入,这就是对我有用的方式:

  1. 使用 set 和 get 方法创建 ViewModel:
public class SharedViewModel extends ViewModel {


    private MutableLiveData<String> mAnswer1 = new MutableLiveData<>();
    private MutableLiveData<String> mAnswer2 = new MutableLiveData<>();
    private MutableLiveData<String> mAnswer3 = new MutableLiveData<>();

    public void setAnswer1 (String answer1){
        mAnswer1.setValue(answer1);
    }

    public void setAnswer2 (String answer2){
        mAnswer2.setValue(answer2);
    }

    public void setAnswer3 (String answer3){
        mAnswer3.setValue(answer3);
    }

    public LiveData<String> getAnswer1(){
        return mAnswer1;
    }
    public LiveData<String> getAnswer2(){
        return mAnswer2;
    }
    public LiveData<String> getAnswer3(){
        return mAnswer3;
    }
}

  1. 在您有 EditText 并想使用其输入的片段中,您必须调用 ViewModel 的 set 方法。:
// This method gets the input of the EditText and "sends" it to the SharedViewModel where the next fragment can access it
    @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        EditText nameEditText = view.findViewById(R.id.edit_text_question_1);

        // Add Text Watcher on name input text
        nameEditText.addTextChangedListener(new TextWatcher() {
            @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                viewModel.setAnswer1(charSequence.toString());
            }

            @Override public void afterTextChanged(Editable editable) {

            }
        });
    }

在 onCreate 方法之前你必须调用这个:

public FragmentQuestion1() {
        // Required empty public constructor
    }

    /**
     * Create a new instance of this fragment
     * @return A new instance of fragment FirstFragment.
     */
    public static FragmentQuestion1 newInstance() {
        return new FragmentQuestion1();
    }

    @Override public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // init ViewModel
        viewModel = ViewModelProviders.of(requireActivity()).get(SharedViewModel.class);
    }
  1. 在要使用输入的片段中,只需调用 ViewModel 的 get 方法即可:
// Gets the answer from player 1 from the previous fragment and set the TextView to the answer
    @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        tv_answer1 = view.findViewById(R.id.answer_player_1_text_view);

        viewModel.getAnswer1().observe(requireActivity(), new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {
                tv_answer1.setText(s);
            }
        });
    }

就像在另一个片段中一样,你必须在 onCreate 方法之前调用以下内容:

/**
     * Use this factory method to create a new instance of this fragment.
     *
     * @return A new instance of fragment SecondFragment.
     */
    public static FragmentAnswer1 newInstance() {
        return new FragmentAnswer1();
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // initialise ViewModel here
        viewModel = ViewModelProviders.of(requireActivity()).get(SharedViewModel.class);
    }

我希望这会以某种方式帮助某些人,因为我花了很长时间才找到问题的正确答案。