Search code examples
androidandroid-fragmentsandroid-fragmentactivity

How to call a specific Fragment's getActivity()?


My problem is that i have a recyclerview implemented on a fragment that uses Room. RecyclerView, Adapter and Database need to be together in one class (i guess).

My problem is that if I put them into StudentActivity,

recyclerView = findViewById(R.id.SubjectRecyclerView);

will be null, because the Fragment won't be available by the time this function called.

If i put them into StudentSubjectsFragment, everything would be good, but NewSubjectDialogFragment tells me that StudentActivity needs to implement NewSubjectDialogFragment because of this:

    private NewSubjectDialogListener listener;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FragmentActivity activity = getActivity();
        if (activity instanceof NewSubjectDialogListener) {
            listener = (NewSubjectDialogListener) activity;
        } else {
            throw new RuntimeException("Activity must implement the NewSubjectDialogListener interface!");
        }
    }

If at the

FragmentActivity activity = getActivity();

line somehow I would be able to call the getActivity() function of StudentSubjectsFragment class, I think it would solve my problem, and then the class that would implement the NewSubjectDialogFragment would be the StudentSubjectsFragment instead of StudentActivity.

I tried this:

FragmentActivity activity = getActivity().getSupportFragmentManager().findFragmentByTag("StudentSubjectsFragment").getActivity();

But activity is null.

StudentSubjectsFragment class:

public class StudentSubjectsFragment extends Fragment
        implements NewSubjectDialogFragment.NewSubjectDialogListener,
        SubjectAdapter.SubjectClickListener {

    public static final String TAG = "StudentSubjectsFragment";

    private RecyclerView recyclerView;
    private SubjectAdapter adapter;
    private SubjectDatabase database;

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

        FloatingActionButton fab = rootView.findViewById(R.id.fabbb);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new NewSubjectDialogFragment().show(getActivity().getSupportFragmentManager(), NewSubjectDialogFragment.TAG);
            }
        });

        database = Room.databaseBuilder(
                getActivity(),
                SubjectDatabase.class,
                "subject-list"
        ).build();

        recyclerView = rootView.findViewById(R.id.SubjectRecyclerView);
        adapter = new SubjectAdapter(this);
        loadItemsInBackground();
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        recyclerView.setAdapter(adapter);

        return rootView;
    }

    private void loadItemsInBackground() {
        new AsyncTask<Void, Void, List<Subject>>() {

            @Override
            protected List<Subject> doInBackground(Void... voids) {
                return database.subjectDao().getAll();
            }

            @Override
            protected void onPostExecute(List<Subject> subjects) {
                adapter.update(subjects);
            }
        }.execute();
    }

    @Override
    public void onItemChanged(final Subject item) {
        new AsyncTask<Void, Void, Boolean>() {

            @Override
            protected Boolean doInBackground(Void... voids) {
                database.subjectDao().update(item);
                return true;
            }

            @Override
            protected void onPostExecute(Boolean isSuccessful) {
                Log.d("StudentActivity", "Subject update was successful");
            }
        }.execute();
    }

    @Override
    public void onItemDeleted(final Subject item) {
        new AsyncTask<Void, Void, Boolean>() {

            @Override
            protected Boolean doInBackground(Void... voids) {
                database.subjectDao().deleteItem(item);
                return true;
            }

        }.execute();
    }

    @Override
    public void onSubjectCreated(final Subject newItem) {
        new AsyncTask<Void, Void, Subject>() {

            @Override
            protected Subject doInBackground(Void... voids) {
                newItem.id = database.subjectDao().insert(newItem);
                return newItem;
            }

            @Override
            protected void onPostExecute(Subject subject) {
                adapter.addItem(subject);
            }
        }.execute();
    }
}

StudentActivity class:

public class StudentActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_student);

        ViewPager vpProfile = findViewById(R.id.vpStudent);
        vpProfile.setAdapter(new StudentPagerAdapter(getSupportFragmentManager()));
    }
}

NewSubjectDialogFragment class:

public class NewSubjectDialogFragment extends DialogFragment {

    private EditText nameEditText;

    public static final String TAG = "NewSubjectDialogFragment";

    public interface NewSubjectDialogListener {
        void onSubjectCreated(Subject newItem);
    }

    private NewSubjectDialogListener listener;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FragmentActivity activity = getActivity().getSupportFragmentManager().findFragmentByTag("StudentSubjectsFragment").getActivity();
        if (activity instanceof NewSubjectDialogListener) {
            listener = (NewSubjectDialogListener) activity;
        } else {
            throw new RuntimeException("Activity must implement the NewSubjectDialogListener interface!");
        }
    }

    private boolean isValid() {
        return nameEditText.getText().length() > 0;
    }

    private Subject getSubject() {
        Subject subject = new Subject();
        subject.name = nameEditText.getText().toString();
        return subject;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        return new AlertDialog.Builder(requireContext())
                .setTitle(R.string.new_subject_item)
                .setView(getContentView())
                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        if (isValid()) {
                            listener.onSubjectCreated(getSubject());
                        }
                    }
                })
                .setNegativeButton(R.string.cancel, null)
                .create();
    }

    private View getContentView() {
        final View contentView = LayoutInflater.from(getContext()).inflate(R.layout.dialog_new_subject_item, null);
        nameEditText = contentView.findViewById(R.id.SubjectNameEditText);
        return contentView;
    }
}

I think there is a way to change NewSubjectDialogFragment to work with StudentSubjectsFragment but I am a beginner in android developing and don't know how to do it.


Solution

  • Solution of Mike M. worked perfectly.

    The working code parts are the following:

    NewSubjectDialogFragment:

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Fragment fragment = getParentFragment();
        if (fragment instanceof NewSubjectDialogListener) {
            listener = (NewSubjectDialogListener) fragment;
        } else {
            throw new RuntimeException("Fragment must implement the NewSubjectDialogListener interface!");
        }
    }
    

    StudentSubjectFragment:

    FloatingActionButton fab = rootView.findViewById(R.id.fabbb);
        fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            new NewSubjectDialogFragment().show(getChildFragmentManager(), NewSubjectDialogFragment.TAG);
        }
    });