2

I'm trying to get the activity calling getActivity() in the fragments contained in a ViewPager and this ViewPager is contained inside a Fragment. I need to call some methods from this activity in those fragments but the getActivity is always returning NULL for this fragments.

I don't know if this is a good approach but I need the fragments contained by the view pager to update their contents based on action bar actions and display messages saying is done or there was an error.

Help with this would be greatly appreciated.

Here is the code:

Internal Fragment:

    public class ReportSessionsFragment extends ReportPageFragment implements IUpdateView {

    private static final String TAG = ReportSessionsFragment.class.getSimpleName();

    private Sessions fSessions;

    private List<Report> reportList = null;
    private ReportsAdapter adapter = null;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        settings = ((BaseActivity)getActivity()).settings;
    }

    @Override
    public void onStart() {
        super.onStart();
        setCounter(db.getSessionsCount());

        if(settings.getSelectedRoom() != null){
            reportList = db.getSessionsByRoom(settings.getSelectedRoom().getName(),
                    settings.getStatusSelectedList());
            adapter = new ReportsAdapter(getActivity(), reportList, EReport.Sessions);
            mRecyclerView.setAdapter(adapter);
        }

    }

    @Override
    public void onStop() {
        super.onStop();
    }

    @Override
    public void reload() {
        HashMap<String, Object> parameters = new HashMap<>();
        parameters.put(Fetcher.REQUEST_PARAMETERS, getEventInformation());

        showProgress(getString(R.string.txt_requesting_sessions));
        fSessions = new Sessions(getActivity(), this);
        fSessions.handleSession(parameters, false);
    }

    @Override
    public void delta() {

    }

    @Override
    public void updateProcess(String message) {

    }

    @Override
    public void onProcessEnded(RequestType type, boolean isProvisioningCompleted, String message) {
        reportList = db.getSessionsByRoom(settings.getSelectedRoom().getName(),
                settings.getStatusSelectedList());
        adapter.notifyDataSetChanged();
        hideProgress();
    }

    @Override
    public void onError(Exception e, boolean isProvisioningCompleted) {
        hideProgress();
        showError(getString(R.string.txt_error_title),
                e.getMessage());
    }
}

Fragment containing the ViewPager:

    public class ReportSessionsFragment extends ReportPageFragment implements IUpdateView {

    private static final String TAG = ReportSessionsFragment.class.getSimpleName();

    private Sessions fSessions;

    private List<Report> reportList = null;
    private ReportsAdapter adapter = null;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        settings = ((BaseActivity)getActivity()).settings;
    }

    @Override
    public void onStart() {
        super.onStart();
        setCounter(db.getSessionsCount());

        if(settings.getSelectedRoom() != null){
            reportList = db.getSessionsByRoom(settings.getSelectedRoom().getName(),
                    settings.getStatusSelectedList());
            adapter = new ReportsAdapter(getActivity(), reportList, EReport.Sessions);
            mRecyclerView.setAdapter(adapter);
        }

    }

    @Override
    public void onStop() {
        super.onStop();
    }

    @Override
    public void reload() {
        HashMap<String, Object> parameters = new HashMap<>();
        parameters.put(Fetcher.REQUEST_PARAMETERS, getEventInformation());

        showProgress(getString(R.string.txt_requesting_sessions));
        fSessions = new Sessions(getActivity(), this);
        fSessions.handleSession(parameters, false);
    }

    @Override
    public void delta() {

    }

    @Override
    public void updateProcess(String message) {

    }

    @Override
    public void onProcessEnded(RequestType type, boolean isProvisioningCompleted, String message) {
        reportList = db.getSessionsByRoom(settings.getSelectedRoom().getName(),
                settings.getStatusSelectedList());
        adapter.notifyDataSetChanged();
        hideProgress();
    }

    @Override
    public void onError(Exception e, boolean isProvisioningCompleted) {
        hideProgress();
        showError(getString(R.string.txt_error_title),
                e.getMessage());
    }
}

The Activity:

    public class ReportsActivity extends BaseActivity implements IReports {

    private static final String TAG = ReportsActivity.class.getSimpleName();

    private ReportsFragment reportFragment;
    private HashMap<Integer, MenuItem> menuReports;

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

        reportFragment = new ReportsFragment();
        addFragment(reportFragment);
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_reports, menu);

        menuReports = new HashMap<>();

        for(int index = 0; index < menu.size(); index++ ){
            MenuItem mi = menu.getItem(index);
            menuReports.put(mi.getItemId(), mi);
        }

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        ReportPageFragment reportPage = (ReportPageFragment)reportFragment.getCurrentReportPage();

        switch (item.getItemId()){
            case R.id.action_reload:
                reportPage.reload();
                break;
            case R.id.action_delta:
                reportPage.delta();
                break;
        }

        return true;
    }

    @Override
    public void displayOptionsByReport(int position) {
        MenuItem miReload = null;
        if(menuReports != null){
             miReload = (MenuItem) menuReports.get(R.id.action_reload);
        }

        switch (position){
            case REPORT_SESSION:
                miReload.setVisible(true);
                break;
            case REPORT_ENROLLMENT:
                miReload.setVisible(true);
                break;
            case REPORT_REGISTRANTS:
                miReload.setVisible(false);
                break;
            case REPORT_ASSOCIATIONS:
                miReload.setVisible(false);
                break;
        }
    }
}

FragmentPagerAdapter:

public class ReportsPagerAdapter extends FragmentStatePagerAdapter {

private Context ctx;

public ReportsPagerAdapter(Context ctx, FragmentManager fm) {
    super(fm);
    this.ctx = ctx;
}

@Override
public Fragment getItem(int position) {
    Fragment fragment = null;

    switch (position){
        case 0:
            fragment = Fragment.instantiate(ctx, ReportSessionsFragment.class.getName());
            break;
        case 1:
            fragment = Fragment.instantiate(ctx, ReportEnrollmentFragment.class.getName());
            break;
        case 2:
            fragment = Fragment.instantiate(ctx, ReportRegistrantsFragment.class.getName());
            break;
        case 3:
            fragment = Fragment.instantiate(ctx, ReportAssociationsFragment.class.getName());
            break;
    }

    return fragment;
}

@Override
public int getCount() {
    String[] reportListNames = ctx.getResources().getStringArray(R.array.reports);
    return reportListNames.length;
}

@Override
public CharSequence getPageTitle(int position) {
    String[] reportListNames = ctx.getResources().getStringArray(R.array.reports);
    return reportListNames[position];
}
}
Dyan
  • 1,703
  • 4
  • 19
  • 26
  • Why don't you just remove the middle fragment, containing the ViewPager in Activity directly? What did ReportsFragment do? Is it really necessary? – Ted Yu Jul 08 '15 at 16:37
  • Well is one thing I could do, but I need this to work on phones and tables. So, when is in landscape the app shows 2 fragments and one of them is the one with the view pager, right now that works. The problem starts when I press the action bar buttons and the context can't be captured by the fragments in the ViewPager. – Dyan Jul 08 '15 at 17:31
  • I don't see where are they being detached to not be able to get the context. – Dyan Jul 08 '15 at 17:32

1 Answers1

9

Every fragment, even those that are childen of another fragment, receive a call to onAttach() when they are added to the fragment tree. The activity containing the fragment is passed in as a parameter. The simplest solution is may be to save the activity as a member of your fragment. Then it is available when needed later.

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    //save the activity to a member of this fragment
    mHostActivity = activity;
}

An alternative, for a fragment that is always at a fixed depth in the tree, is to use getParent() as many times as needed to get to the top-most fragment. For example, in your fragments that are children of the pager fragment:

getParentFragment().getActivity()
Bob Snyder
  • 37,759
  • 6
  • 111
  • 158
  • 1
    Thank you for your answer, my problem wasn't related to what I posted in the question, was something more related to what you answered. I was instantiating the fragments every single time I was getting the item in that position. But thanks to your answer I checked the onAttach and saw it was being overwritten by the getItem method in my adapter, I'll vote for you answer cause it made me think a little(day and a half looking for ideas) and find the solution to my problem. – Dyan Jul 08 '15 at 20:28
  • onAttach(activity) is deprecated in android.support.v4.app.Fragment. Using getActivity() seems to be a better option. – Dusko Sep 18 '15 at 09:32
  • 2
    @Dusko Clarification to your comment: onAttach(Activity) was deprecated in API level 23 and replaced by onAttach(Context). – Bob Snyder Sep 18 '15 at 15:07
  • @qbix yes I saw that. You can use class casting on context but I enclose it in if-case checking isinstanceof because, as others have mentioned, context might be different. – Dusko Sep 18 '15 at 15:18