I am building a quiz app that has two types of questionnaires. I have a DialogAlert that allows the user to choose which questionnaire (two options: either "history" or "chemistry") they want to complete and have the results display in a fragment.
My goal is to be able to display the textview ("history" or "chemistry") that the questionnaire they selected in the result fragment.
I have a Dialog
class:
public class DialogAlert extends DialogFragment {
private Context context;
String selection;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final String[] items = {"History", "Chemistry"};
AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity());
builder.setTitle("Select a topic to complete")
.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
selection = items[which];
}
})
// Set the action buttons
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
switch (selection)
{
case("History"):
Intent intent_hist = new Intent(getActivity(), historyquestions.class);
startActivity(intent_hist);
break;
case("Chemistry"):
Intent intent_chem = new Intent(getActivity(), chemistryquestions.class);
startActivity(intent_chem);
break;
}
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
Toast.makeText(getActivity(), "No topic was selected", Toast.LENGTH_SHORT)
.show();
dialog.cancel();
}
});
return builder.create();
}
My Result
fragment in which I have a placeholder textview that I want to display what the user had selected (either history or chemistry) based on the positive/ negative button above:
public class homeFragment extends Fragment{
TextView topic
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View layoutView = inflater.inflate(R.layout.fragment_home, container, false);
topic = (TextView) layoutView.findViewById(R.id.topic);
return layoutView;
}
}
How should I approach this? The challenge is that the result is shown in one of the fragments and I am unsure how would I "pass" what the user had selected in the Dialog
to the Result
fragment. Can someone please help?
Thank you in advance!
*Edit with the home fragment Id
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.home.homeFragment">
<FrameLayout
android:id="@+id/home_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<LinearLayout
android:id="@+id/layout1"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_marginStart="10dp"
android:layout_marginTop="270dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
android:background="@drawable/layout_bg"
android:orientation="vertical"
android:weightSum="300">
<TextView
android:id="@+id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_weight="10"
android:fontFamily="@font/inter_regular"
android:text="Selection of topic"
android:textColor="#000000"
android:textSize="22sp" />
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/topic"
android:layout_width="340dp"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:fontFamily="@font/inter_regular"
android:text="Topic"
android:textColor="#000000"
android:textSize="20sp" />
</TableRow>
</LinearLayout>
</FrameLayout>
Edit 2023-02-13
HomeViewModel
class:
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class HomeViewModel extends ViewModel {
private final MutableLiveData<String> mText;
public HomeViewModel() {
mText = new MutableLiveData<>();
mText.setValue("This is a home fragment");
}
// getText method
public LiveData<String> getText() {
return mText;
}
// function to update the mText value
public void setText(String updateText) {
mText.setValue(updateText);
}
}
homeFragment
class:
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.annotation.Nullable;
public class homeFragment extends Fragment{
private HomeViewModel homeViewModel;
public View onCreateView(@NonNull LayoutInflater inflater,ViewGroup container, Bundle savedInstanceState) {
View layoutView = inflater.inflate(R.layout.fragment_home, container, false);
homeViewModel =
ViewModelProviders.of(requireActivity()).get(HomeViewModel.class);
final TextView topic = (TextView)layoutView.findViewById(R.id.topic);
homeViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
topic.setText(s);
}
});
return layoutView;
}
Dialog
class:
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.lifecycle.ViewModelProviders;
import com.example.quizzApp.MainActivity;
import com.example.quizzApp.ui.home.HomeViewModel;
public class DialogAlert extends DialogFragment {
private Context context;
String selection;
private HomeViewModel model;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(requireActivity()).get(HomeViewModel.class);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final String[] items = {"History", "Chemistry"};
AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity());
// Set the dialog title
builder.setTitle("Select a topic to complete")
// Specify the list array, the items to be selected by default (null for none),
// and the listener through which to receive callbacks when items are selected
.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
selection = items[which];
}
})
// Set the action buttons
// User clicked OK, so save the selectedItems results somewhere
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
switch (selection)
{
case("History"):
model.setText("History");
Intent intent_hist = new Intent(getActivity(), MainActivity.class);
startActivity(intent_hist);
break;
case("Chemistry"):
model.setText("Chemistry");
Intent intent_chem = new Intent(getActivity(), MainActivity.class);
startActivity(intent_chem);
break;
}
}
})
// or return them to the component that opened the dialog
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
Toast.makeText(getActivity(), "No topic was selected", Toast.LENGTH_SHORT)
.show();
dialog.cancel();
}
});
return builder.create();
}
You have created an App with Bottom Navigation Activity template. There should be 3 tabs Home
, Dashboard
, Notifications
. And somehow you have opened a DialogFragment
and that allows you to choose between History
or Chemistry
as the topic. And upon selecting either one and press OK, your Home
fragment should display the topic selected.
If you are using Bottom Navigation Activity template, there should be a HomeViewModel
class. You can make use of this HomeViewModel
class, share it among different Fragments, and update the view accordingly.
HomeFragment
class:
public class HomeFragment extends Fragment {
private HomeViewModel homeViewModel;
private Button btnDialog;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
// Please notice the below line, getting ViewModel using the below method can ensure
// the model can be shared across different Fragments
homeViewModel =
ViewModelProviders.of(requireActivity()).get(HomeViewModel.class);
// new ViewModelProvider(this).get(HomeViewModel.class);
View root = inflater.inflate(R.layout.fragment_home, container, false);
final TextView textView = root.findViewById(R.id.text_home);
// You have registered the ViewModel to change your HomeFragment TextView. So if the value
// of mText has been updated, the TextView in HomeFragment will also be updated
// accordingly.
homeViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
textView.setText(s);
}
});
// This btnDialog is just my testing button, it is a button to open your mentioned
// DialogFragment. So you can ignore this button and the openDialog(View) function.
btnDialog = root.findViewById(R.id.btnDialog);
btnDialog.setOnClickListener(this::openDialog);
return root;
}
// As mentioned above, this function can be ignored
public void openDialog(View v) {
DialogAlert frag = new DialogAlert();
frag.show(getChildFragmentManager(), "DialogAlert");
}
}
HomeViewModel
class:
public class HomeViewModel extends ViewModel {
private MutableLiveData<String> mText;
public HomeViewModel() {
mText = new MutableLiveData<>();
mText.setValue("This is home fragment");
}
public LiveData<String> getText() {
return mText;
}
// You need to add a function so that you can update mText value
public void setText(String updateText) {
mText.setValue(updateText);
}
}
DialogAlert
class:
public class DialogAlert extends DialogFragment {
private Context context;
String selection;
// Define a variable to hold the ViewModel class
private HomeViewModel model;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Obtain the HomeViewModel so that we can update the value of mText and sync to view in
// HomeFragment
model = ViewModelProviders.of(requireActivity()).get(HomeViewModel.class);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final String[] items = {"History", "Chemistry"};
AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity());
builder.setTitle("Select a topic to complete")
.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
selection = items[which];
}
})
// Set the action buttons
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
switch (selection) {
case ("History"):
// Magic line, it will trigger the onChanged() in HomeFragment
model.setText("History");
dialog.dismiss();
break;
case ("Chemistry"):
// Magic line, it will trigger the onChanged() in HomeFragment
model.setText("Chemistry");
dialog.dismiss();
break;
}
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
Toast.makeText(getActivity(), "No topic was selected", Toast.LENGTH_SHORT)
.show();
dialog.cancel();
}
});
return builder.create();
}
}
With the above code, after you have selected the option in DialogFragment
, your HomeFragment
TextView should be updated at once.
Regarding on the following code:
switch (selection)
{
case("History"):
Intent intent_hist = new Intent(getActivity(), historyquestions.class);
startActivity(intent_hist);
break;
case("Chemistry"):
Intent intent_chem = new Intent(getActivity(), chemistryquestions.class);
startActivity(intent_chem);
break;
}
The above code will start an Activity
to either historyquestions
Activity or chemistryquestions
Activity (if you have properly created these Activity), instead of proceeding to your result homeFragment
Fragment.
It is a good practice to follow Java naming conventions when you name classes. For example: