77

I have a supported fragment activity which will load diff fragments. The fragment has some textView with id = "score" and I want to get its handle but findViewById for score's textView returns null. Why so?


textView is placed in fragment

public class MyActivity extends  extends ActionBarActivity
        implements NavigationDrawerFragment.NavigationDrawerCallbacks{

   private TextView scoreBoardTextView = null;

   protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_home);
     mNavigationDrawerFragment = (NavigationDrawerFragment)
                getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
     scoreBoardTextView = (TextView) findViewById(R.id.score); //this returns null
  }

    @Override
    public void onNavigationDrawerItemSelected(int position) {
      //set fragment    
    }

}
Korem
  • 11,383
  • 7
  • 55
  • 72
user93796
  • 18,749
  • 31
  • 94
  • 150

17 Answers17

71

Note:

Directly accessing fragment's views outside fragment is not a good idea. You should use fragment callback interfaces to handle such cases and avoid bugs. The following way works but it is not recommended as it is not a good practice.


If you want to access the TextView of Fragment inside its parent Activity then you should define a method inside your Fragment class like this:
public class MyFragment extends Fragment {

    TextView mTextView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.activity_main, container, false);
        mTextView = (TextView) view.findViewById(R.id.textView1);
        return view;
    }

    public void setTextViewText(String value){
        mTextView.setText(value);
    }


}

Now you can use this inside your Activity like this:

myFragment.setTextViewText("foo");

here myFragment is of type MyFragment.

If you want to access the whole TextView then you can define a method like this inside MyFragment.java:

public TextView getTextView1(){
    return mTextView;
}

By this you can access the TextView itself.

Hope this Helps. :)

SMR
  • 6,628
  • 2
  • 35
  • 56
  • 2
    This looks like a good answer, but the method to override show be `onCreateView()` and not `getView()`, I think. – matiash Jun 21 '14 at 16:14
  • This is the right way to do it, using view.findViewById() – Android Noob Jun 26 '14 at 11:27
  • You should not do this... why would the Activity access the Fragment's views directly??? Why don't you just move those views to the Activity's layout instead? What is the benefit of using fragments this way? – kupsef Jun 26 '14 at 19:49
  • @kupsef dont ask me ask the OP. I am just telling how it is done. I will not access the view directly. that why I also demonstrated the first method. – SMR Jun 27 '14 at 04:06
  • @kupsef suppose if i want to check whether a fragment's view is visible or not when the user presses the back button. Then this solution will be required. – Kaveesh Kanwal Aug 13 '15 at 09:27
  • 2
    You can implement the fragment in a way that it can tell you whether a specific view is visible or not. It is much cleaner. The fragment responsible for the view, and the Activity uses the interface provided by the fragment to acquire information about a view. There is no direct access. – kupsef Aug 13 '15 at 10:56
  • @kupsef I agree that we should not access fragments views directly outside the fragment. using interfaces is obviously a good approach but we need to check whether the fragment is visible or not. – SMR Aug 14 '15 at 07:02
  • @kupsef [this](http://stackoverflow.com/a/24458324/3193867) answer is also suggesting the same. you are welcome to edit the answer or write your own explaining the same in detail. – SMR Aug 14 '15 at 07:05
  • this doesn't show how activity access textview in a fragment. – Hatim Jan 12 '17 at 18:26
  • setTextViewText("foo"); this method is not static cannot be called directly PS this answer didn't work for me ( – jokermt235 Mar 26 '18 at 13:12
26

It is possible with following way:

Keep reference of inflated view in the Fragment like this :

public class MyFragment extends SherlockFragment{

MainMenuActivity activity;
public View view;
public MyFragment(){
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    if ( getActivity() instanceof MainMenuActivity){
        activity = (MainMenuActivity) getActivity();
    }

    view = inflater.inflate(R.layout.aboutus, container, false);        
    return view;
}

}

Create a function in the Activity, like this:

 public class MainMenuActivity extends SherlockFragmentActivity {

 SherlockFragment fragment = null;

 public void switchContent(SherlockFragment fragment) {     
    this.fragment = fragment;
    getSupportFragmentManager()
    .beginTransaction()
    .replace(R.id.mainmenu, fragment)
    .commit();

    invalidateOptionsMenu();
}

Its purpose is to keep reference of current fragment. Whenever you wanna switch fragment, you call above function, like this (from fragment):

activity.switchContent( new MyFragment_2());

Now you've current fragment reference. So you can directly access Fragment's views in Activity like this: this.fragment.view

Arsalan Mehmood
  • 1,432
  • 1
  • 15
  • 26
  • Parent activity should never manipulate the fragment's views directly. You SHOULD write a function INSIDE the fragment that performs the modification. Accessing fragment's views directly actually makes the fragment useless. Encapsulation is lost this way, you could have better added those view's to the Activity's layout instead. – kupsef Jun 26 '14 at 19:45
  • @kupsef Obviously we've to access them via method, I just accessed here for understanding. – Arsalan Mehmood Jun 26 '14 at 22:39
11

You have no need of reference of Fragment view to get its components in Activity. As you can directly access layout components of a Fragment in parent Activity.

Simply you can access any component by this

findViewById(R.id.child_of_fragment_layout);  
Ali Imran
  • 8,927
  • 3
  • 39
  • 50
  • 4
    That's true with one caveat (at least for me), the fragment view might not be ready yet. It worked when I moved that code to my activity's `onStart()` – Amr Mostafa Aug 01 '17 at 21:56
5

You can access with getView method of Fragment class.

For example You have a TextView in Your MyFragment with id of "text_view"
In Your Activity make a Fragment of Yours:

MyFragment myFragment = new MyFragment();

And when You need a child just call getView and then find Your childView.

View view = myFragment.getView();
if (view !=null) {
view.findViewById(R.id.text_view).setText("Child Accessed :D");
}

Note: if you want the root view of your fragment, then myFragment.getView(); is simply enough.

Saman Sattari
  • 3,322
  • 6
  • 30
  • 46
5

In order to access the TextView or Button or whatever in your fragment you need to do the following:

public class BlankFragment extends Fragment {
public View view;
public TextView textView;
public Button button;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    view =inflater.inflate(R.layout.fragment_blank, container, false);
    textView = (TextView)view.getRootView().findViewById(R.id.textView_fragment1);
    return view;
}

public void changeTextOfFragment(String text){
    textView.setText(text);
    view.setBackgroundResource(R.color.colorPrimaryDark);
}

Once that is done in your MainActivity or any other where you want to access your TextView from your Fragment you should make sure to set up the fragment in your OnCreate() method other ways it will most likely throw nullPointer. So your activity where you want to change the TextView should look smth like this:

public class MainActivity extends AppCompatActivity {
private Button button1;
private FragmentManager fragmentManager;
private FragmentTransaction fragmentTransaction;
BlankFragment blankFragment = new BlankFragment();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    button1 = (Button)findViewById(R.id.button1);
    changeFragment();

    fragmentManager = getFragmentManager();
    fragmentTransaction = fragmentManager.beginTransaction();
    fragmentTransaction.replace(R.id.fragment1,blankFragment);
    fragmentTransaction.commit();
}

private void changeFragment(){
    button1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            blankFragment.changeTextOfFragment("Enter here the text which you want to be displayed on your Updated Fragment");

        }
    });
}

Hope this helps :)

F.A. Botic
  • 71
  • 1
  • 2
3

Just put in fragment instead of putting in activity:

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

    TextView scoreBoardTextView = (TextView) rootView.findViewById(R.id.score);

    return rootView;
}
Zoran
  • 1,484
  • 1
  • 10
  • 13
3

Only doing this:

((Your_Activity) this.getActivity()).YouyActivityElements;
SMR
  • 6,628
  • 2
  • 35
  • 56
Lalit kumar
  • 2,377
  • 1
  • 22
  • 17
2

If your TextView placed inside Fragment that case you cannot access TextView inside your Fragment Parent Activity you can set the interface for intercommunication between Fragment and Activity and send Data when you click on TextView or anyother thing which you want to happend

Ramkailash
  • 1,852
  • 1
  • 23
  • 19
1

You can't access Fragment element in Parent Activity, But You can pass values to your Fragment by following way.

in your onNavigationDrawerItemSelected method of MyActivity do the following

int myScore = 100;
@Override
public void onNavigationDrawerItemSelected(int position) {
    // update the main content by replacing fragments
    FragmentManager fragmentManager = getSupportFragmentManager();
    fragmentManager
            .beginTransaction()
            .replace(R.id.container,
                    MyFragment.newInstance(myScore)).commit();
}

And in MyFragment class create a method called newInstance like following

private static final String SCORE = "score";
public static MyFragment newInstance(int score) {
    MyFragment fragment = new MyFragment();
    Bundle args = new Bundle();
    args.putInt(SCORE, score);
    fragment.setArguments(args);
    return fragment;
}

And in MyFragment's onCreateView() method

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_main, container,
            false);
    TextView textView = (TextView) rootView
            .findViewById(R.id.score);
    textView.setText(Integer.toString(getArguments().getInt(
            SCORE)));
    return rootView;
}

That's All, I hope this will help you. If not please let me know.

Gunaseelan
  • 14,415
  • 11
  • 80
  • 128
0

The score textView is in the layout of fragment, it's not in the layout of the MyActivity, i.e. R.layout.activity_home. So you could find the score textview in that fragment once you inflate the corresponding layout file.

Sherlock
  • 135
  • 1
  • 6
  • I need the handle of "scoreBoardTextView "activity in my Parent activity that loads the fragment.How do i do that? – user93796 Jun 12 '14 at 16:04
0

It returns null cause the TextView is an element of the Fragment, not the Activity.

Please note that the idea of using Fragment is to encapsulate a module inside the Fragment, which means the Activity should not have direct access to it's properties. Consider moving your logic where you get the TextView reference inside the Fragment

Christopher Francisco
  • 15,672
  • 28
  • 94
  • 206
0

Simply declare TextView as public in fragment, initialize it by findViewById() in fragment's onCreateView(). Now by using the Fragment Object which you added in activity you can access TextView.

0

You need to call method findViewById from your fragment view.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_home);
    mNavigationDrawerFragment = (NavigationDrawerFragment)
            getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
    scoreBoardTextView = (TextView) mNavigationDrawerFragment.getView().findViewById(R.id.score); 
}

This way works for me.

Yoric
  • 499
  • 3
  • 7
0

I suggest you to make the textview part of your activity layout. Alternately you can have the textview as a separete fragment. Have a look at my question here. Its similar to yours but in reverse direction. Here's a stripped down version of code I used in my project. The explanation are along the code.

The Activity Class

public class MainActivity extends ActionBarActivity {
PlaceFragment fragment;
TextView fragmentsTextView;

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

@Override
protected void onStart() {
    // TODO Auto-generated method stub
    super.onStart();
    Bundle bundle = new Bundle();
    bundle.putString("score", "1000");
    fragment = PlaceFragment.newInstance(bundle);
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.replace(R.id.container, fragment);
    ft.addToBackStack(null);
    ft.commit();
    // method 1
    // fragment is added some ways to access views
    // get the reference of fragment's textview
    if (fragment.getTextView() != null) {
        fragmentsTextView = fragment.getTextView();
    }
    // method 2
    // using static method dont use in production code
    // PlaceFragment.textViewInFragment.setText("2000");

    // method 3
    // let the fragment handle update its own text this is the recommended
    // way wait until fragment transaction is complete before calling
    //fragment.updateText("2000");

}

}

The fragment class:

public class PlaceFragment extends Fragment {
public TextView textViewInFragment;// to access via object.field same to
                                    // string.length

// public static TextView textViewInFragment;//to access via
// PlaceFragment.textView dont try this in production code
public PlaceFragment() {
}

public static PlaceFragment newInstance(Bundle bundle) {
    PlaceFragment fragment = new PlaceFragment();
    fragment.setArguments(bundle);
    return fragment;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    View view = inflater.inflate(R.layout.fragment_place, container, false);
    textViewInFragment = (TextView) view
            .findViewById(R.id.textViewInFragment);
    return view;
}

@Override
public void onStart() {
    // TODO Auto-generated method stub
    super.onStart();
    if (getArguments() != null) {
        textViewInFragment.setText(getArguments().getString("score"));

    }
}

public TextView getTextView() {
    if (textViewInFragment != null) {
        return textViewInFragment;// returns instance of inflated textview
    }
    return null;// return null and check null
}

public void updateText(String text) {
    textViewInFragment.setText(text);// this is recommended way to alter
                                        // view property of fragment in
                                        // activity
}

}

Communication from activity to fragment is straight forward. This is because activity contains fragment. Keep the fragment object and access its property via setters and getters or the public fields inside it. But communication from fragment to activity requires an interface.

Community
  • 1
  • 1
Illegal Argument
  • 10,090
  • 2
  • 44
  • 61
0

why you don't access it directly from your FragmentPagerAdapter,

SubAccountFragment subAccountFragment = (SubAccountFragment) mSectionsPagerAdapter.getItem(1);
subAccountFragment.requestConnectPressed(view);

and here is the full example:

import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.Locale;


public class TabsActivity extends ActionBarActivity implements ActionBar.TabListener {

    /**
     * The {@link android.support.v4.view.PagerAdapter} that will provide
     * fragments for each of the sections. We use a
     * {@link FragmentPagerAdapter} derivative, which will keep every
     * loaded fragment in memory. If this becomes too memory intensive, it
     * may be best to switch to a
     * {@link android.support.v4.app.FragmentStatePagerAdapter}.
     */
    SectionsPagerAdapter mSectionsPagerAdapter;

    /**
     * The {@link ViewPager} that will host the section contents.
     */
    ViewPager mViewPager;

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

        // Set up the action bar.
        final ActionBar actionBar = getSupportActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        // Create the adapter that will return a fragment for each of the three
        // primary sections of the activity.
        mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

        // Set up the ViewPager with the sections adapter.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mSectionsPagerAdapter);

        // When swiping between different sections, select the corresponding
        // tab. We can also use ActionBar.Tab#select() to do this if we have
        // a reference to the Tab.
        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                actionBar.setSelectedNavigationItem(position);
            }
        });

        // For each of the sections in the app, add a tab to the action bar.
        for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
            // Create a tab with text corresponding to the page title defined by
            // the adapter. Also specify this Activity object, which implements
            // the TabListener interface, as the callback (listener) for when
            // this tab is selected.
            ActionBar.Tab tab = actionBar.newTab();

            View tabView = this.getLayoutInflater().inflate(R.layout.activity_tab, null);

            ImageView icon = (ImageView) tabView.findViewById(R.id.tab_icon);
            icon.setImageDrawable(getResources().getDrawable(mSectionsPagerAdapter.getPageIcon(i)));

            TextView title = (TextView) tabView.findViewById(R.id.tab_title);
            title.setText(mSectionsPagerAdapter.getPageTitle(i));

            tab.setCustomView(tabView);

            tab.setTabListener(this);

            actionBar.addTab(tab);
        }
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_tabs, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_logout) {
            finish();
            gotoLogin();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
        // When the given tab is selected, switch to the corresponding page in
        // the ViewPager.
        mViewPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }

    @Override
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }

    /**
     * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
     * one of the sections/tabs/pages.
     */
    public class SectionsPagerAdapter extends FragmentPagerAdapter {

        public ProfileFragment profileFragment;
        public SubAccountFragment subAccountFragment;
        public ChatFragment chatFragment;

        public SectionsPagerAdapter(FragmentManager fm) {
            super(fm);
            profileFragment = new ProfileFragment();
            subAccountFragment = new SubAccountFragment();
            chatFragment = new ChatFragment();
        }

        @Override
        public Fragment getItem(int position) {
            switch (position) {
                case 0:
                    return profileFragment;
                case 1:
                    return subAccountFragment;
                case 2:
                    return chatFragment;
            }
            return null;
        }

        @Override
        public int getCount() {
            // Show 3 total pages.
            return 3;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            Locale l = Locale.getDefault();
            switch (position) {
                case 0:
                    return getString(R.string.title_section1).toUpperCase(l);
                case 1:
                    return getString(R.string.title_section2).toUpperCase(l);
                case 2:
                    return getString(R.string.title_section3).toUpperCase(l);
            }
            return null;
        }

        public int getPageIcon(int position) {
            switch (position) {
                case 0:
                    return R.drawable.tab_icon_0;
                case 1:
                    return R.drawable.tab_icon_1;
                case 2:
                    return R.drawable.tab_icon_2;
            }
            return 0;
        }
    }


    public void gotoLogin() {
        Intent intent = new Intent(this, LoginActivity.class);
        this.startActivity(intent);
    }

    public void requestConnectPressed(View view){
        SubAccountFragment subAccountFragment = (SubAccountFragment) mSectionsPagerAdapter.getItem(1);
        subAccountFragment.requestConnectPressed(view);
    }
}
Fareed Alnamrouti
  • 30,771
  • 4
  • 85
  • 76
0

If the view is already inflated (e.g. visible) on the screen then you can just use findViewById(R.id.yourTextView) within the activity as normal and it will return the handle to the text view or null if the view was not found.

sham
  • 1,346
  • 1
  • 20
  • 28
0

I just use methods to access fragment views from parent activity, because we create a new fragment class object to insert the fragment. So I do like this.

class BrowserFragment : Fragment(), Serializable {
    private lateinit var webView: NestedScrollWebView
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        webView = view.findViewById(R.id.web_view)
    }
    fun getWebView(): WebView {
        return webView
    }
}

In MainActivity

val browserFragment = BrowserFragment()
val fragmentTransaction = supportFragmentManager.beginTransaction()
fragmentTransaction.add(R.id.browser_fragment_placeholder, browserFragment)
fragmentTransaction.commit()

val webView = browserFragment.getWebView()
Jeeva
  • 3,975
  • 3
  • 23
  • 47