Search code examples
androidandroid-fragmentsnullpointerexceptionfragmentfindviewbyid

Accessing fragment's view from an activity


I have an activity that holds a fragment, it adds it by doing this in the onCreate (From a Google example):

    // Check that the activity is using the layout version with
    // the fragment_container FrameLayout
    if (findViewById(R.id.fragment_container) != null) {

        // However, if we're being restored from a previous state,
        // then we don't need to do anything and should return or else
        // we could end up with overlapping fragments.
        if (savedInstanceState != null) {
            return;
        }

        // Create a new Fragment to be placed in the activity layout
        RecordFragment firstFragment = new RecordFragment();

        // In case this activity was started with special instructions from an
        // Intent, pass the Intent's extras to the fragment as arguments
        firstFragment.setArguments(getIntent().getExtras());

        // Add the fragment to the 'fragment_container' FrameLayout
        getSupportFragmentManager().beginTransaction()
                .add(R.id.fragment_container, firstFragment).commit();

This is the activity layout:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />

This is the Fragment:

public class RecordFragment extends Fragment {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_record, container, false);
}

And the fragment_record.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.controlcenter.RecordActivity$PlaceholderFragment" >

<TextView
    android:id="@+id/textView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Information:"
    android:textAppearance="?android:attr/textAppearanceMedium" />

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <EditText
        android:id="@+id/action_info"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:ems="10" />

    <ImageView
        android:id="@+id/arrow_button"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:src="@drawable/ic_action_forward" />

</LinearLayout>

In the fragment there is a arrow button. I want the activity to add a listener to the button so when it is clicked the fragment will slide out and another fragment will slide in. Im having trouble accessing that button, I'm trying to use

firstFragment.getView().findViewById(R.id.arrow_button)

But it appears getView is returning null although I overload the onCreateView() method.


Solution

  • The simple answer is that you don't. Treat the Fragment's view as something that's internal to the fragment. Instead, set the activity as a listener to the Fragment via an interface you define and then set the click listener in the fragment to call the fragment's listener.

    public class MyFragment extends Fragment {
        public interface MyListener {
            public void onAction();
        }
    
        private MyListener mListener;
        public void setListener(MyListener listener) {
            mListener = listener;
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View root = inflater.inflate(R.layout.fragment_record, container, false);
    
            root.findViewById(R.id.arrow_button).setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (mListener != null) {
                        mListener.onAction();
                    }
                }
            });
            return root;
        }
        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
            if (activity instanceof MyListener) {
                mListener = (MyListener) activity;
            } else {
                // Maybe throw an exception if you want to be strict
            }
        }
    }
    

    And your Activity class would need this:

    public class MyActivity extends Activity implements MyFragment.MyListener {
        public void onAction() {
            // TODO whatever you need to do when the button is clicked
        }
    }