I have a ViewPager2, with two pages. One the get an email and another to get a phone number. To obtain the values I added two get methods to the adapter but I'm not sure this is the correct and safest way to do it. Here is my code:
public class PhoneEmailFragment extends Fragment {
private View view;
private final String[] tabs = {"Phone", "Email"};
private User user;
private int pageSelected = 0;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_phone_email, container, false);
return view;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
assert getArguments() != null;
user = getArguments().getParcelable("user");
}
@Override
public void onStart() {
super.onStart();
viewpagerSetup();
}
private void viewpagerSetup() {
TabLayout tabLayout = view.findViewById(R.id.register_phone_email_tab);
ViewPager2 viewPager2 = view.findViewById(R.id.register_viewpager);
SwipeAdapter adapter = new SwipeAdapter(this);
viewPager2.setAdapter(adapter);
viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
pageSelected = position;
}
});
new TabLayoutMediator(
tabLayout,
viewPager2,
(tab, position) -> tab.setText(tabs[position])
).attach();
}
public void saveValue() {
switch (pageSelected) {
case 0:
user.setUserPhoneNumber();
break;
case 1:
user.setUserEmail();
break;
}
}
static class SwipeAdapter extends FragmentStateAdapter {
public SwipeAdapter(@NonNull Fragment fragment) {
super(fragment);
}
@NonNull
@Override
public Fragment createFragment(int position) {
Fragment fragment = new Fragment();
switch (position) {
case 0:
fragment = new PhoneFieldFragment();
break;
case 1:
fragment = new EmailFieldFragment();
break;
}
return fragment;
}
@Override
public int getItemCount() {
return 2;
}
}
}
I want to use the value from the EditText on the saveValue() method.
Obtaining the values of the EditText
should be done inside your fragment classes. In order to get the values of the EditText
from the fragments, the 2 get methods should be removed from your SwipeAdapter
class and findViewById()
calls should be placed in your fragment classes like below:
public class EmailFieldFragment extends Fragment {
private MainViewModel mainViewModel;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mainViewModel = new ViewModelProvider(requireActivity()).get(MainViewModel.class);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_email_field, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Do this after an action, example - after a button click
EditText emailEt = view.findViewById(R.id.email_et);
emailEt.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (count < 1) { // i.e - no user input
mainViewModel.setEmail("");
} else {
mainViewModel.setEmail(s.toString());
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
}
I updated the SwipeAdapter
to accept list of fragments as follows:
public class SwipeAdapter extends FragmentStateAdapter {
private final List<Fragment> fragments;
public SwipeAdapter(@NonNull FragmentActivity fragmentActivity,
List<Fragment> fragmentList) {
super(fragmentActivity);
this.fragments = fragmentList;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return fragments.get(position);
}
@Override
public int getItemCount() {
return fragments.size();
}
}
I created a viewModel class that holds the values of the EditText fields in LiveData
objects. These fields are then observed from the activity (or fragment). See the code below:
public class MainViewModel extends ViewModel {
private final MutableLiveData<String> _email = new
MutableLiveData<>();
public LiveData<String> email = _email;
private final MutableLiveData<String> _phone = new
MutableLiveData<>();
public LiveData<String> phone = _phone;
public void setEmail(String email) {
_email.setValue(email);
}
public void setPhone(String phone) {
_phone.setValue(phone);
}
}
I also added the lifecycle dependencies.
Finally, this is the code for the Activity below:
public class MainActivity extends AppCompatActivity {
private String email = "";
private String phone = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainViewModel mainViewModel = new ViewModelProvider(this).get(MainViewModel.class);
PhoneFieldFragment phoneFieldFragment = new PhoneFieldFragment();
EmailFieldFragment emailFieldFragment = new EmailFieldFragment();
List<Fragment> fragmentList = new ArrayList<>();
fragmentList.add(phoneFieldFragment);
fragmentList.add(emailFieldFragment);
SwipeAdapter swipeAdapter = new SwipeAdapter(this, fragmentList);
ViewPager2 viewPager = findViewById(R.id.viewPager);
viewPager.setAdapter(swipeAdapter);
Button button = findViewById(R.id.get_field_button);
mainViewModel.email.observe(MainActivity.this, new Observer<String>() {
@Override
public void onChanged(String s) {
email = s;
}
});
mainViewModel.phone.observe(MainActivity.this, new Observer<String>() {
@Override
public void onChanged(String s) {
phone = s;
}
});
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "Email: " + email + "\nPhone: " + phone, Toast.LENGTH_SHORT).show();
// Both email and phone number are available here, so you can call your setValue() method here
}
});
}
}
This is a link to the entire codebase on github
EDIT
I used a shared viewModel class that connects the viewPager fragments and their host activity (or another fragment as the case may be).
I get the text from the EditText as the user is typing using a TextWatcher
.