Search code examples
androidfragmentandroid-tablayout

findViewByID not work in tab layout


i use tab layout matching this tutorial:

tab layout tutorial androidhive

It works fine, but when I add a button to fragment_one.xml , i cant use setOnClickListener for this button Because findViewById not work in MainActivity.java

the MainActivity bellow code:

public class MainActivity extends AppCompatActivity {
Button button;

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

    ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
    setupViewPager(viewPager);

    TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
    tabLayout.setupWithViewPager(viewPager);

    button = (Button) findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
           Snackbar.make(view, "Replace with your own action",Snackbar.LENGTH_LONG).setAction("Action", null).show();
        }
    });
}

the app stopped with this error: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener' on a null object reference

Where should the button be defined and setOnClickListener?


Solution

  • Even though a fragment is hosted by an activity, it has its own layout (which is contained in the activity's layout) and therefore you'll have to define the fragment's view in its java class.

    In most cases, a fragment would have its own Java class for you to manage and manipulate it, so in your case, it should look like this:

    public class OneFragment extends Fragment{
    
        public OneFragment() {
            // Required empty public constructor
        }
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View view=inflater.inflate(R.layout.fragment_one, container, false);
            Button button=view.findViewById(R.id.myButtonInFragment);
            return view;
        }
    
    }
    

    If you'd like to access this button from its parent activity, you can achieve it by making the button public:

    public class OneFragment extends Fragment{
    
       public Button button;
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View view=inflater.inflate(R.layout.fragment_one, container, false);
            button=view.findViewById(R.id.myButtonInFragment);
            return view;
        }
    }
    

    and then, access it using the fragment's instance in your activity:

    OneFragment myFragment=new OneFragment();
    

    After you have attached the fragment to the activity, you can use:

    myFragment.button.setClickEnabled(false);
    

    However, accessing fragment's children outside of the fragment is not recommended, and you should avoid it if you can.