getArguments() in Fragment returning null - android

I've studied all the fragment getArgument null pointer questions already answered and I can't seem to find a solution that works for me. My fragment is functioning properly (buttons doing proper function) except that it does not get any arguments passed in. I have set up my constructor and my calls to it various ways, and cannot avoid the NullPoint. I think it must be something around the lifecycle of the fragment, and the fragment appearing onscreen somehow not being the initiated one, but I can't get to the bottom of it. Any help will be greatly appreciated!
Fragment code:
public class BottomBar extends Fragment {
ImageButton goHome, goPending, goActive, goHelp, goChallenge;
BottomListener activityCallback;
int chalType;
String title;
String text;
//constructor log.d prints out that it has been reached
public static BottomBar init(int chalType, String ttl, String txt){
BottomBar bot = new BottomBar();
Bundle args = new Bundle();
args.putInt("chalType", chalType);
args.putString("title", ttl);
args.putString("text", txt);
bot.setArguments(args);
Log.d("Bottom Bar Init", "called");
return bot;
}
#Override
public void onAttach(Activity activity){
super.onAttach(activity);
try{
activityCallback = (BottomListener) activity;
} catch (ClassCastException e){
Log.d("bottom bar onAttach","class cast");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bottombarfrag, container, false);
goHome = (ImageButton) view.findViewById(R.id.goHome);
goPending = (ImageButton) view.findViewById(R.id.goPending);
goChallenge = (ImageButton) view.findViewById(R.id.challenge);
goActive = (ImageButton) view.findViewById(R.id.goActive);
goHelp = (ImageButton) view.findViewById(R.id.getInfo);
Bundle argsin = getArguments();
//never enters this loop... argsin always null
if(argsin!=null){
Log.d("bottombar oncreate", "argsin found");
chalType = argsin.getInt("chalType", 0);
title = argsin.getString("title");
text = argsin.getString("text");
}
//.... button activities, functioning properly ....
return view;
}
and main activity code that calls it:
public class MainActivity extends FragmentActivity {
Button btn, paydemo;
TextView tv1, tv2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String ttl = "Trial1 Home";
String txt = "string1text";
BottomBar bot = BottomBar.init(0, ttl, txt);
getSupportFragmentManager().beginTransaction().add(android.R.id.content, bot).commit();
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.clickbtn);
paydemo = (Button) findViewById(R.id.PayPalDemo);
tv1 = (TextView) findViewById(R.id.textView1);
tv2 = (TextView) findViewById(R.id.textView3);
tv1.setText("try1");
tv2.setText("");
// ...other button actions
}
Follow up:
I've found that I can get the fragment that I want, however it appears as a second instance on the fragment (located on top of display, not where desired), and the original instance is there, but not functioning properly (still with no args). I think that when I initialize the fragment in my activity I am not overwriting the existing fragment that is added by the xml. Maybe I need to initialize the Support Fragment Manager and link it to the proper instance to replace it? Thoughts?
xml where originally intended fragment is located (this is the fragment I want, but not the fragment that is being communicated with).
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Second Layout"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Button
android:id="#+id/retBut"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Return" />
<fragment
android:id="#+id/bottombar"
android:name="com.example.trial1.BottomBar"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_marginTop="0dp"
/>
</LinearLayout>

This one is tricky. Take a look at your activity: you are setting fragment and after that calling setContentView. setContentView removes all views from android.R.id.content, i think this breaks fragment's lifecycle somehow. Moreover it looks like a concept mistake: setting fragment and wiping it out after that. I suggest making a fragment container inside R.layout.activity_main, set activity content and after that put you fragment in this container.

So I came up with a functioning answer. I'm not convinced it's the proper way to do it, but it is working.
I created an inherited class for all the classes that reference this fragment, and created a set of public variables to represents the arguments passed to the fragment. I then had each class write the public variables in the super class instead of initiating a new fragment. The fragment then referenced the same public variables to pull information from.
Again, don't think it is the proper way to do it - the argument passing exists to be efficient - but it is working for me now. If anyone has a better idea for how I could accomplish this I'm all ears.
Thanks for all the help

Related

Android how do i acces elements in a fragment?

I've got an activity that loads 2 different fragments and switches between them when needed. The problem is I cant acces any elements that are in the fragments. I need to be able to set the typeface and text in the toolbar as well as be able to set the checkboxes.
fragment XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="3">
<include
layout="#layout/toolbar_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:id="#+id/cycle_button"
android:button="#null"
android:background="#drawable/cycle"
android:layout_weight="1"
android:layout_gravity="center_vertical" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:id="#+id/walk_button"
android:button="#null"
android:background="#drawable/walk"
android:layout_weight="1"
android:layout_gravity="center_vertical" />
java file:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
TextView appTitle = (TextView) toolbar.findViewById(R.id.toolbar_title);
appTitle.setText("title");
CheckBox cycle = (CheckBox) getView().findViewById(R.id.cycle_button);
CheckBox walk = (CheckBox) findViewById(R.id.walk_button);
}
the findViewById doesn't work on the fragment and it just keeps returning null.
You could send the desired values for your elements from your activity to the fragment when you're instantiating them.
But there are several methods you can choose to communicate between your activity and a fragment:
Therefore have a look at the guide Communicating with Fragments
1.) Bundle - Activity can construct a fragment and set arguments
2.) Methods - Activity can call methods on a fragment instance
3.) Listener - Fragment can fire listener events on an activity via an interface
Especially a Fragment with Arguments would be helpful to you:
In certain cases, your fragment may want to accept certain arguments.
A common pattern is to create a static newInstance method for creating
a Fragment with arguments. This is because a Fragment must have only a
constructor with no arguments. Instead, we want to use the
setArguments method such as:
public class DemoFragment extends Fragment {
// Creates a new fragment given an int and title
// DemoFragment.newInstance(5, "Hello");
public static DemoFragment newInstance(int someInt, String someTitle) {
DemoFragment fragmentDemo = new DemoFragment();
Bundle args = new Bundle();
args.putInt("someInt", someInt);
args.putString("someTitle", someTitle);
fragmentDemo.setArguments(args);
return fragmentDemo;
}
}
This sets certain arguments into the Fragment for later access within > onCreate. You can access the arguments later by using:
public class DemoFragment extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get back arguments
int SomeInt = getArguments().getInt("someInt", 0);
String someTitle = getArguments().getString("someTitle", "");
}
}
Now we can load a fragment dynamically in an Activity with:
// Within the activity
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
DemoFragment fragmentDemo = DemoFragment.newInstance(5, "my title");
ft.replace(R.id.your_placeholder, fragmentDemo);
ft.commit();
This pattern makes passing arguments to fragments for initialization fairly straightforward.
After instantiating your fragment you can go ahead and retrieve your desired views from the fragment's layout during inflating and set the values included in the fragment's arguments.
public class DemoFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View view = inflater.inflate(R.layout.your_fragment_layout, container, false);
// Retrieve views here via findElementById etc.. and set the attributes from the fragment's arguments
return view;
}
}
In Fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle avedInstanceState) {
View rootView = inflater.inflate(R.layout.yourlayout, null);
Toolbar toolbar = (Toolbar) rootView.findViewById(R.id.toolbar);
//...[other views get here]...
return rootView;
}
In fragment view creation is done in .onCreateView() method.
You can use ViewHolder pattern- save references to all views for accessing them in a future.
If you want to access activity from fragment, define interface in fragment and implement it in activity, so you can make a call like:
((MyInterface) getActivity()).changeToolbar()
For passing values into fragment use static method when you create fragement. Bear in mind, that data use pass must implement Parceleable interface

Android: Calling a function inside a fragment from a custom action bar

I have the following problem:
I have a custom layout for the action bar of my activity like that:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:divider="?android:attr/dividerVertical"
android:showDividers="middle"
android:dividerPadding="6dp">
<include layout="#layout/include_cancel_button" />
<include layout="#layout/include_done_button" />
</LinearLayout>
with an included button like that:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="?android:actionButtonStyle"
android:id="#+id/actionbar_done"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:onClick="saveSchwein" >
<TextView style="?android:actionBarTabTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingRight="10dp"
android:drawableLeft="#drawable/ic_action_ok"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:text="#string/ok" />
</FrameLayout>
This fragment is added to a ViewPager during the onCreate() of the activity like that:
viewPager = (ViewPager) findViewById(R.id.schweinpager);
tabPagerAdapter = new SchweinFragmentAdapter(getSupportFragmentManager());
viewPager.setAdapter(tabPagerAdapter);
actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
for (String tab_name : tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name).setTabListener(this).setTag(tab_name));
}
So far, everything works fine. I have three fragments displayed in tabs in the action bar and I can swipe an switch between them without problems.
Now here comes my actual problem:
I want to call a function inside the fragment from the custom action bar.
saveSchwein() in activity (because the function in the fragment is not found):
public void saveSchwein(View v) {
Fragment fragment = tabPagerAdapter.getItem(0);
((StammdatenFragment) fragment).saveSchwein();
}
and the corrosponding function in the fragment:
public void saveSchwein() {
if (getActivity() == null) {
System.out.println("getActivity ist null");
}
if (rootView == null) {
System.out.println("rootView ist null");
}
if (isAdded()) { System.out.println("Attached to Activity"); } else { System.out.println("NOT attached to Activity"); }
Schwein schwein = new Schwein();
schwein.setName(add_name.getText().toString());
schwein.setGeschlecht(geschlecht_spinner.getSelectedItem().toString());
schwein.setRasse(rasse_spinner.getSelectedItem().toString());
schwein.setGeburtsdatum(add_geburtsdatum.getText().toString());
schwein.setBesonderheiten(add_besonderheiten.getText().toString());
}
The rootView and the views gets assigned during the onCreateView() like this:
rootView = inflater.inflate(R.layout.fragment_schwein_stammdaten, container, false);
add_name = (EditText) rootView.findViewById(R.id.add_name);
geschlecht_spinner = (Spinner) rootView.findViewById(R.id.geschlecht_spinner);
rasse_spinner = (Spinner) rootView.findViewById(R.id.rasse_spinner);
add_geburtsdatum = (TextView) rootView.findViewById(R.id.add_geburtsdatum);
add_besonderheiten = (EditText) rootView.findViewById(R.id.add_besonderheiten);
The result is that rootView and getActivity() are both null and isAdded() is false, so the fragment is no longer attached to the activity. At this line I get the nullpointerexception:
schwein.setName(add_name.getText().toString());
I am now looking for an answer on my question since several days, but did not find the right answer yet. But I made progress by learning about the lifecircle of a fragment and figured out that is has to do something with the fact that the fragment is not active during actions in the custom action bar.
With an option menu like here Android Options Menu in Fragment it's working, but I prefer to use the custom action bar for that!
Any ideas?
What does your SchweinFragmentAdapter.getItem function look like? Often these functions simply create a Fragment, without first checking if the fragment already exists. That's the first thing to check, because in saveSchwein you are calling getItem directly, and you want to make sure you aren't creating a new fragment (that doesn't have a view or activity) and then calling the fragment's saveSchwein on that new unconfigured fragment. That would explain the behavior you are seeing.
If that is the case, then you can do this instead:
public void saveSchwein(View v) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("StammdatenFragment");
((StammdatenFragment) fragment).saveSchwein();
}
Another alternative would be to change the implementation of getItem, so that it keeps track of all the fragments it has created, and only creates new ones when needed.
public static class SchweinFragmentAdapter extends FragmentPagerAdapter {
private Fragment [] fragments = new Fragment[3];
#Override
public Fragment getItem(int position) {
Fragment fragment = fragments[position];
if (fragment == null) {
if (position == 0) {
fragment = new ...
} else if (position == 1) {
fragment = new ...
} else if (position == 2) {
fragment = new ...
}
fragments[position] = fragment;
}
return fragment;
}
}
EDIT:
Sorry, there is actually a problem with the solution I've given you. Yes, it works, but it could also lead to a memory leak because Android is already caching the fragments in FragmentPagerAdapter. I've been frustrated with this class because there is not a public API to get the tags that the adapter uses when it adds the fragments to your activity. However, since we can look at the code, we can see what they are doing.
The better solution, although it is ugly, is to use findFragmentByTag. However, the tag is not what I put in my initial answer. Try this instead:
private static final int POSITION_STAMMDATEN = //TODO the position of your fragment in the adapter
public void saveSchwein(View v) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag(
"android:switcher:" + viewPager.getId() + ":"
+ tabPagerAdapter.getItemId(POSITION_STAMMDATEN)");
((StammdatenFragment) fragment).saveSchwein();
}

Android: how to add another fragment to the main activity

I asked a question about how to add a Fragment that contained something drawn using OpenGL ES
here. Someone was kind enough to answer that for me, but unfortunately today I encountered another problem. As I mentioned in my other question, my purpose is to add other Fragments next to the one that contains OpenGL and because I am a beginner in Android development I don't seem to understand how this is done.
Here's what I want: right now, my code is exactly the one from my other question. I also have this Fragment:
public class TextFragment extends Fragment
{
private TextView textview;
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.text_fragment,
container, false);
textview = (TextView) view.findViewById(R.id.textView1);
return view;
}
}
together with its layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/frag2">
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Fragment Two"
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>
and I want to add this to my main activity, where right now I only have the OpenGL Fragment. Here's my main activity:
public class FragmentExampleActivity extends FragmentActivity implements ToolbarFragment.ToolbarListener
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener()
{
public void onBackStackChanged()
{
int backCount = getSupportFragmentManager().getBackStackEntryCount();
if (backCount == 0)
{
finish();
}
}
});
if (savedInstanceState == null)
{
getSupportFragmentManager()
.beginTransaction()
.add(R.id.main_container, new OpenGLES20ActivityFrag())
.addToBackStack(null)
.commit();
}
}
}
and the Fragment that has OpenGL in it and that I have already added to the main activity:
public class OpenGLES20ActivityFrag extends Fragment
{
private GLSurfaceView mGLView;
public OpenGLES20ActivityFrag()
{
super();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
mGLView = new MyGLSurfaceView(this.getActivity());
return mGLView;
}
}
What I tried and failed: using another call to the .add method inside getSupportFragmentManager() or adapting this bit of code for my second Fragment
getSupportFragmentManager()
.beginTransaction()
.add(R.id.frag2, TextFragment)
.addToBackStack(null)
.commit();
that gave me an 'expression expected' error in the add method. I tried adding this constructor to my second Fragment
public TextFragment()
{
super();
}
and then inside the add method I put .add(R.id.frag2, new TextFragment())
which still didn't work.
In order to dynamically add a Fragment to a layout, what you need is a container (like in your case, it was R.id.main_container). Thus, if you want to add multiple fragments, what you need is multiple containers, like so:
<LinearLayout android:orientation="vertical" android:layout_height="fill_parent" android:layout_width="fill_parent">
<FrameLayout android:id="#+id/main_container_1" android:layout_weight="1" android:layout_height="fill_parent" android:layout_width="fill_parent"/>
<FrameLayout android:id="#+id/main_container_2" android:layout_weight="1" android:layout_height="fill_parent" android:layout_width="fill_parent"/>
</LinearLayout>
(this snippet is from How to split the screen with two equal LinearLayouts? )
And then you would need to add the two Fragments:
if (savedInstanceState == null)
{
getSupportFragmentManager()
.beginTransaction()
.add(R.id.main_container_1, new OpenGLES20ActivityFrag())
.commit();
getSupportFragmentManager()
.beginTransaction()
.add(R.id.main_container_2, new TextFragment())
.commit();
}
Please note that with multiple Fragments on a single Activity, it's better not to add them to the backstack, because then you'd have to press Back as many times as there are Fragments, and in this case it's more reasonable to navigate between the "views" or states of the application with Activities, and not by replacing the Fragments.
(considering the backstack doesn't change, I don't think the backstack listener needs to be removed, but that's done so that if you press Back, you don't end the Activity, but the Fragments within it first if you have them added to the backstack. But the Activity doesn't end when it contains no fragments, and you'd have an "empty view", hence why that was added.)
Please also check if the rotation works and data is maintained even after the activity reconstruction, because there's a chance you need to set the retain instance state to true explicitly on the Fragments for that to work.

getting a null-object reference back with findViewById [duplicate]

This is a canonical question for a problem frequently posted on StackOverflow.
I'm following a tutorial. I've created a new activity using a wizard. I get NullPointerException when attempting to call a method on Views obtained with findViewById() in my activity onCreate().
Activity onCreate():
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View something = findViewById(R.id.something);
something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
Layout XML (fragment_main.xml):
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
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="packagename.MainActivity$PlaceholderFragment" >
<View
android:layout_width="100dp"
android:layout_height="100dp"
android:id="#+id/something" />
</RelativeLayout>
The tutorial is probably outdated, attempting to create an activity-based UI instead of the fragment-based UI preferred by wizard-generated code.
The view is in the fragment layout (fragment_main.xml) and not in the activity layout (activity_main.xml). onCreate() is too early in the lifecycle to find it in the activity view hierarchy, and a null is returned. Invoking a method on null causes the NPE.
The preferred solution is to move the code to the fragment onCreateView(), calling findViewById() on the inflated fragment layout rootView:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
View something = rootView.findViewById(R.id.something); // not activity findViewById()
something.setOnClickListener(new View.OnClickListener() { ... });
return rootView;
}
As a side note, the fragment layout will eventually be a part of the activity view hierarchy and discoverable with activity findViewById() but only after the fragment transaction has been run. Pending fragment transactions get executed in super.onStart() after onCreate().
Try OnStart() method and just use
View view = getView().findViewById(R.id.something);
or Declare any View using getView().findViewById method in onStart()
Declare click listener on view by anyView.setOnClickListener(this);
Try to shift your accessing views to the onViewCreated method of fragment because sometimes when you try to access the views in onCreate method they are not rendered at the time resulting null pointer exception.
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
View something = findViewById(R.id.something);
something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
Agreed, this is a typical error because people often don't really understand how Fragments work when they begin working on Android development. To alleviate confusion, I created a simple example code that I originally posted on Application is stopped in android emulator , but I posted it here as well.
An example is the following:
public class ContainerActivity extends FragmentActivity implements ExampleFragment.Callback
{
#Override
public void onCreate(Bundle saveInstanceState)
{
super.onCreate(saveInstanceState);
this.setContentView(R.layout.activity_container);
if (saveInstanceState == null)
{
getSupportFragmentManager().beginTransaction()
.add(R.id.activity_container_container, new ExampleFragment())
.addToBackStack(null)
.commit();
}
getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener()
{
public void onBackStackChanged()
{
int backCount = getSupportFragmentManager().getBackStackEntryCount();
if (backCount == 0)
{
finish();
}
}
});
}
#Override
public void exampleFragmentCallback()
{
Toast.makeText(this, "Hello!", Toast.LENGTH_LONG).show();
}
}
activity_container.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/activity_container_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
ExampleFragment:
public class ExampleFragment extends Fragment implements View.OnClickListener
{
public static interface Callback
{
void exampleFragmentCallback();
}
private Button btnOne;
private Button btnTwo;
private Button btnThree;
private Callback callback;
#Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
try
{
this.callback = (Callback) activity;
}
catch (ClassCastException e)
{
Log.e(this.getClass().getSimpleName(), "Activity must implement Callback interface.", e);
throw e;
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_example, container, false);
btnOne = (Button) rootView.findViewById(R.id.example_button_one);
btnTwo = (Button) rootView.findViewById(R.id.example_button_two);
btnThree = (Button) rootView.findViewById(R.id.example_button_three);
btnOne.setOnClickListener(this);
btnTwo.setOnClickListener(this);
btnThree.setOnClickListener(this);
return rootView;
}
#Override
public void onClick(View v)
{
if (btnOne == v)
{
Toast.makeText(getActivity(), "One.", Toast.LENGTH_LONG).show();
}
else if (btnTwo == v)
{
Toast.makeText(getActivity(), "Two.", Toast.LENGTH_LONG).show();
}
else if (btnThree == v)
{
callback.exampleFragmentCallback();
}
}
}
fragment_example.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="#+id/example_button_one"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="30dp"
android:text="#string/hello"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"/>
<Button
android:id="#+id/example_button_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/example_button_one"
android:layout_alignRight="#+id/example_button_one"
android:layout_below="#+id/example_button_one"
android:layout_marginTop="30dp"
android:text="#string/hello" />
<Button
android:id="#+id/example_button_three"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/example_button_two"
android:layout_alignRight="#+id/example_button_two"
android:layout_below="#+id/example_button_two"
android:layout_marginTop="30dp"
android:text="#string/hello" />
</RelativeLayout>
And that should be a valid example, it shows how you can use an Activity to display a Fragment, and handle events in that Fragment. And also how to communicate with the containing Activity.
The view "something" is in fragment and not in activity, so instead of accessing it in activity you must access it in the fragment class like
In PlaceholderFragment.class
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_main, container,
false);
View something = root .findViewById(R.id.something);
something.setOnClickListener(new View.OnClickListener() { ... });
return root;
}
You are trying to access UI elements in the onCreate() but , it is too early to access them , since in fragment views can be created in onCreateView() method.
And onActivityCreated() method is reliable to handle any actions on them, since activity is fully loaded in this state.
Add the following in your activity_main.xml
<fragment
android:id="#+id/myFragment"
android:name="packagename.MainActivity$PlaceholderFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</fragment>
Since you have declared your View in the fragment_main.xml,move that piece of code where you get the NPE in the onCreateView() method of the fragment.
This should solve the issue.
in the posted code above in the question there is a problem :
you are using R.layout.activity_main in oncreate method, but the xml files name is "fragment_main.xml" , means you are trying to get the view of fragment_main.xml file which is not being shown so it gives null pointer exception. change the code like :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);// your xml layout ,where the views are
View something = findViewById(R.id.something);
something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
You have to remember important thing is :
NullPointerException occurs when you have declared your variable and trying to retreive its value before assigning value to it.
Use onViewCreated() Method whenever using or calling views from fragments.
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
View v = view.findViewById(R.id.whatever)
}
I've got the same NullPointerException initializing a listener after calling findViewById() onCreate() and onCreateView() methods.
But when I've used the onActivityCreated(Bundle savedInstanceState) {...} it works. So, I could access the GroupView and set my listener.
I hope it be helpful.
Most popular library for finding views which is used by almost every developer.
ButterKnife
As I can their are enough answers explaining finding views with proper methodology. But if you are android developer and code frequently on daily basis then you can use butter-knife which saves a lot time in finding views and you don't have write code for it, With in 2-3 steps you can find views in milliseconds.
Add dependency in app level gradle:
implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
Add plugin for butter knife:
File -> Settings -> plugins->
Then search for Android ButterKnife Zelezny and install plugin and restart your studio and you are done with it.
Now just go to Oncreate method of your activity and right click on your layout_name and tap on generate button and select butterknife injection option and your views references will be automatically created like mention below:
#BindView(R.id.rv_featured_artist)
ViewPager rvFeaturedArtist;
#BindView(R.id.indicator)
PageIndicator indicator;
#BindView(R.id.rv_artist)
RecyclerView rvArtist;
#BindView(R.id.nsv)
NestedScrollingView nsv;
#BindView(R.id.btn_filter)
Button btnFilter;

findViewById returns NULL when using Fragment

I'm new to Android developing and of course on Fragments.
I want to access the controls of my fragment in main activity but 'findViewById' returns null.
without fragment the code works fine.
Here's part of my code:
The fragment:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:ignore="HardcodedText" >
<EditText
android:id="#+id/txtXML"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:ems="10"
android:scrollbars="vertical">
</EditText>
</LinearLayout>
the onCreate of MainActivity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.main);
this.initialisePaging();
EditText txtXML = (EditText) findViewById(R.id.txtXML);}
on this point the txtXML is null.
What's Missing in my code or what should I do?
Try like this on your fragments on onCreateView
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (container == null) {
return null;
}
LinearLayout ll = (LinearLayout )inflater.inflate(R.layout.tab_frag1_layout, container, false);
EditText txtXML = (EditText) ll.findViewById(R.id.txtXML);
return ll;
}
You should inflate the layout of the fragment on onCreateView method of the Fragment then you can simply access it's elements with findViewById on your Activity.
In this Example my fragment layout is a LinearLayout so I Cast the inflate result to LinearLayout.
public class FrgResults extends Fragment
{
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
//some code
LinearLayout ll = (LinearLayout)inflater.inflate(R.layout.frg_result, container, false);
//some code
return ll;
}
}
I'm late, but for anyone else having this issue. You should be inflating your view in the onCreateView method. Then override the onCreateActivity method and you can use getView().findViewById there.
#Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment, container, false);
}
You can't access the the view of fragment in activity class by findViewById instead what you can do is...
You must have an object of Fragment class in you activity file, right? create getter method of EditText class in that fragment class and access that method in your activity.
create a call back in Fragment class on the event where you need the Edittext obj.
1) Try this:
Eclipse menu -> Project -> Clean...
update
2) If you have 2 or more instances of 'main' layout, check if all of them have a view with 'txtXML' id
3)
A Fragment is a piece of an application's user interface or behavior that can be placed in an Activity. Interaction with fragments is done through FragmentManager, which can be obtained via Activity.getFragmentManager() and Fragment.getFragmentManager().
The Fragment class can be used many ways to achieve a wide variety of results. It is core, it represents a particular operation or interface that is running within a larger Activity. A Fragment is closely tied to the Activity it is in, and can not be used apart from one. Though Fragment defines its own lifecycle, that lifecycle is dependent on its activity: if the activity is stopped, no fragments inside of it can be started; when the activity is destroyed, all fragments will be destroyed.
Study this. you must use FragmentManager.
If you want use findViewById as you use at activities onCreate, you can simply put all in overrided method onActivityCreated.
All the answers above tell you how you should "return the layout" but don't exactly tell you how to reference the layout that was returned so I was unable to use any of the solutions given. I used a different approach to solve the problem. In the Fragment class that handles the fragment, got to the onViewCreated() class and create a context variable in it that saves the context of the parent activity (main activity in my case).
public void onViewCreated(#NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Context fragmentContext = (MainActivity) view.getContext();
}
Once that is done, you can use the new context to access items on your fragment from inside the onViewCreated() method.
EditText editText = context.findViewById(R.id.textXML);

Categories

Resources