0

In my fragment, I am fetching a string from the web and I want the hosting activity to be enable to get this string and use it to set the subtitle of it's actionbar when the backstack changes. I follow this answer and is using the third option.

This are my codes:

Match Activity

public class Match extends AppCompatActivity implements FragmentManager.OnBackStackChangedListener{


    public String matchTitle



    public String getMatchTitle() {
        return matchTitle;
    }

    public void setMatchTitle(String matchTitle) {
        this.matchTitle = matchTitle;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {

    //The usuals

    if (savedInstanceState == null) {
                Bundle bundle = new Bundle();
                Fragment fragment;

                fragment = new DetailsFragment();
                bundle.putString("match_link", news_id);
                fragment.setArguments(bundle);

                FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
                ft.setCustomAnimations(android.R.anim.slide_out_right, android.R.anim.slide_in_left, android.R.anim.slide_out_right, android.R.anim.slide_in_left);
                ft.add(R.id.match_frame, fragment);
                ft.commit();
            }

            if (savedInstanceState != null) {
                mContent = getSupportFragmentManager().getFragment(savedInstanceState, "mContent");
            }
    }

    ....
    @Override
        public void onBackStackChanged() {
            String subtitle = getMatchTitle();
            mToolbar.setSubtitle(subtitle);
        }

        ...

DetailsFragment

public class DetailsFragment extends Fragment {

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


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    Log.d(TAG, "onCreateView called");
    //The usuals
  }

        private void  getMatch() {
    Log.d(TAG, "getMatch called");
    String matchJson = GET_URL + matchID;
    JsonObjectRequest matchDetails = new JsonObjectRequest(Method.GET, matchJson, null,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject response) {
                    Log.d(TAG, "onResponse for getMatch called");
                    parseJson(response);
                    mainMatch = response;
                    if (progressBar != null) {
                        progressBar.setVisibility(View.GONE);
                    }
                }
            },
            new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.d(TAG,  "onErrorResponse for getMatch called");
            if (progressBar != null) {
                progressBar.setVisibility(View.GONE);
            }
            if (sthWrongAlert != null) {
                sthWrongAlert.show();
            }
        }
    });


    //Creating requestqueue
    RequestQueue requestQueue = Volley.newRequestQueue(getActivity());

    //Adding request queue
    requestQueue.add(matchDetails);
}

private void parseJson(JSONObject object) {
    Log.d(TAG, "Parsing Json");
    try {
        final String title = String.valueOf(Html.fromHtml(object.getString("title")));
        matchTitle.setText(title);

            Match match = new Match();
            match.setMatchTitle(title);


    } catch (JSONException w) {
        w.printStackTrace();

    }
}

NOTE I know I can easily set the subtitle from the fragment but I don't want to do that. I just want to make sure I can access a variable in a fragment from it's host activity.

Community
  • 1
  • 1
X09
  • 3,827
  • 10
  • 47
  • 92

2 Answers2

1

One way to do this is to define an interface in the Fragment, and have the activity implement the interface. For example:

public class DetailsFragment {
    public interface OnTitleChangedListener {
        void onTitleChanged(String newTitle);
    }

    private OnTitleChangedListener mListener;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mListener = (OnTitleChangedListener) context;
        // TODO ensure instanceof OntTitleChangeListener
    }
}

Then, in your volley onResponse callback, call mListener.onTitleChanged(newTitle) to communicate the change to the activity. Your activity code might look like:

public class MatchActivity implements DetailsFragment.OnTitleChangedListener {
    @Override
    public void onTitleChanged(String newTitle) {
         mToolbar.setSubtitle(newTitle);
    }
chessdork
  • 1,999
  • 1
  • 19
  • 20
  • Hi chessdork, thank you for your answer. Initially I was doing it as you suggested but what actually happens is that if another instance of **DetailsFragment** is added and added the title of the toolbar will the value gotten from the last added instance of **DetailsFragment**. That's why I wanted the activity to listen for changes in the backstack, get the current value of the title and use it to set the subtitle if the activity. – X09 Jun 02 '16 at 18:16
  • I see. It seems like it would be easier to put the Toolbar in the Fragment, since the title is dependent on fragment state. – chessdork Jun 02 '16 at 18:29
  • Is that to say I can't access a variable in a fragment from it's parent Activity? – X09 Jun 02 '16 at 18:50
  • Well, you could always define a public getter in the fragment. Say `getTitle`. Then in your activity, `((DetailFragment) getFragmentManager().findFragmentByTag()).getTitle()`. The issue here is that the DetailFragment whose title you want is changing. And the result of `getTitle` depends on whether or not the Volley request has finished. You could try getting the topmost fragment on the backstack, and access the title via your public getter. But this seems much harder than just putting the toolbar in the Fragment. – chessdork Jun 02 '16 at 19:08
  • The problem is not going for the hard solution so far it works. – X09 Jun 02 '16 at 19:19
  • Actually, in the main code the activity is already listening for when the data has been fetched and parsed in the fragment and setting the subtitle but like I said before the title is not updated when the backstack changes. And pls how do I get the title of the current fragment in the backstack like you suggested? – X09 Jun 02 '16 at 19:25
0

Accessing the variable directly from fragment in activity introduces strong coupling between the fragment and the host activity. I would suggest to use a communication library such as otto, http://square.github.io/otto/ , to handle the communication between these two. You can register the activity to listen to a SubtitleChangeEvent and then fire this event from the fragment when the subtitle change needs to be reflected.

qichuan
  • 1,110
  • 7
  • 8