I've been working on an app that displays articles and shows the article's title on the toolbar and if I set the article text and toolbar text by calling the method from the article fragment on the main activity in the fragment's onResume method then it works fine, however as soon as I try doing it after calling a specific method within the fragment it just doesnt work giving me java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object reference
I have tried changing everything and making the refreshDisplay method get called at different times and renaming and changing and completely removing the method input from newClassArticle and no matter what - no matter if I just use static strings, no matter if I don't even change the strings - after newClassArticle is called on the fragment, it will no longer execute the actions within refreshDisplay and will give the above error.
This is the newArticle method in the main activity:
public void newArticle() {
frag_article newArticle = new frag_article();
newArticle.setArguments(getIntent().getExtras());
FragmentManager fragManager = getFragmentManager();
FragmentTransaction transaction = fragManager.beginTransaction();
transaction.replace(R.id.activeFrag, newArticle);
transaction.commit();
newArticle.newArticleClass(articles.get(0));
}
This is the setActionBarTitle method in the main activity:
public void setActionBarTitle(String title) {
getSupportActionBar().setTitle(title);
}
This is the newClassArticle method in the fragment:
public void newClassArticle(class_article newArticleClass){
articleTitle = newArticleClass.title;
articleBody = newArticleClass.body;
refreshDisplay();
}
and this is the refreshDisplay method in the fragment:
public void refreshDisplay(){
activity.setActionBarTitle(articleTitle);
txtBody.setText(articleBody);
}
Any help on this infuriating issue would be welcome
Related
So I've got a main activity that hosts all of the fragments in my app. Let me just say beforehand that every time I open a new fragment, I do it like this:
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(vg.getId(), new MyFragment()); //obviously MyFragment varies from usage to usage but nothing else
ft.addToBackStack("My Fragment's Name");
ft.commit();
MyFragment in this case extends androidx.fragment.app.Fragment, which only has a method getFragmentManager(). It does NOT have getSupportFragmentManager().
If I want to go back to a previous fragment, from the currently shown fragment I would do getFragmentManager().popBackStackImmediate(). However, if I wanted to pop the backstack from the activity, I have to use getSupportFragmentManager().popBackStackImmediate() or else nothing happens. This led me to assume that calling getFragmentManager() from a fragment returned the same reference as calling getSupportFragmentManager() from the activity. However, if I try to run getSupportFragmentManager().getBackStackEntryAt(/* an int */) from the main activity I get a NullPointerException. If I run getSupportFragmentManager().getBackStackEntryCount() from the main activity it always returns zero.
So why is it then that getSupportFragmentManager() in the main activity simultaneously works and doesn't work? Why can I use it to pop the backstack, yet I can't access the backstack itself from the main activity? I'm totally clueless. Help would be appreciated.
EDIT: This is my onBackPressed():
#Override
public void onBackPressed() {
getSupportFragmentManager().popBackStackImmediate();
getWindow().setSoftInputMode(defaultSoftInputMode);
try {
String fragmentName = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName();
Toast.makeText(getApplicationContext(), fragmentName, Toast.LENGTH_SHORT).show(); // Debug to see if the correct name is being shown
} catch (NullPointerException npe) {
// Print to console
// It always catches an error here and I don't know why
}
}
The specific method which throws the exception is getSupportFragmentManager().getBackStackEntryAt(int index). Further inspection shows that this method queries an ArrayList<BackStackRecord> for a value, but the exception occurs because this ArrayList is null.
Hello so I am trying to pass an array list from my activity to the fragment and this is what I did :
FirstActivity :
AdminInterface instanceForInterface;
OnCreate
//
System.out.println(results.size) ; //works fine
instanceForInterface.onDataRecieved(results); // here I am getting the exception
//
public interface AdminInterface {
void onDataRecieved(ArrayList <Result> response);
}
public void setInterface(UserFragment anInterface) {
this.instanceForInterface = anInterface;
}
Fragment
OnActivityCreated
((FirstActivity) getActivity()).setInterface(this);
#Override
public void onDataRecieved(ArrayList<Result> response) {
processData(response);
}
Exception
Attempt to invoke interface method 'void **************.onDataRecieved(java.util.ArrayList)' on a null object reference
What I think :
I am calling this line
instanceForInterface.onDataRecieved(results); in OnCreate()
before the initialisation of
((FirstActivity) getActivity()).setInterface(this); in OnActivityCreated()
Solution Please ??
Thank You
The problem is that your fragment's onActivityCreated() method is invoked after your activity's onCreate() method.
The smallest change you can make to achieve the behavior you want is to use the onResumeFragments() method in your activity. That is, delete the line instanceForInterface.onDataRecieved(results); from your onCreate and add this code:
#Override
protected void onResumeFragments() {
super.onResumeFragments();
instanceForInterface.onDataRecieved(results);
}
onResumeFragments() will be invoked by the system after both your activity's onCreate() and your fragment's onActivityCreated() methods.
That being said, chances are quite good that you would be better off with a different approach entirely. For instance, you could have your activity expose a getter for results and have your fragment retrieve the results to work with (rather than have your activity store a reference to your fragment).
Further reading about the Activity and Fragment lifecycles:
https://developer.android.com/guide/components/activities/activity-lifecycle.html
https://developer.android.com/guide/components/fragments.html
My Application consist of 4 fragment as tabs being loaded inside a parent Fragment using FragmentPagerAdapter.
The problem is when I run the app and press back and re-open the app I receive this error log:
FATAL EXCEPTION: main
java.lang.NullPointerException: Attempt to invoke virtual method 'android.os.Handler android.support.v4.app.FragmentHostCallback.getHandler()' on a null object reference
at android.support.v4.app.FragmentManagerImpl.ensureExecReady(FragmentManager.java:1949)
at android.support.v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:1965)
at android.support.v4.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:620)
at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:143)
at android.support.v4.view.ViewPager.setAdapter(ViewPager.java:513)
...
the line of code inside parent Fragment is:
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
and ViewPage and Adapter both are not null!!
I have to mention that all my Fragments lifecycle is being managed and the null issue is happening inside the adapter!, and the same Adapter is working fine when I use an Activity as parent instead of Fragment!!!
After a lot of research, it looks like it is a support library issue:
Activity with fragment and ViewPager crashesh on configuration
change Android Support Library issue 24.1.0
I also found this answer, but it looks unusual adding a flag to my code:
Attempt to invoke virtual method ‘android.os.Handler android.support.v4.app.FragmentHostCallback.getHandler()’ on a null object
I override the finishUpdate method of my FragmentPagerAdapter like this and problem solved for now!
#Override
public void finishUpdate(ViewGroup container) {
try{
super.finishUpdate(container);
} catch (NullPointerException nullPointerException){
System.out.println("Catch the NullPointerException in FragmentPagerAdapter.finishUpdate");
}
}
any better answer? please let me know...
I have the same issue on my project. But it is my fault.
WHY
I call onBackPressed in a callback after the activity has invoked onDestroy();
Because the mHost instance in the FragmentManager is set to null after onDestroy() called.
and when call onBackPressed it will use the mHost instance again.
#Override
public void onBackPressed() {
// super.onBackPressed();
finish();
}
Override the onBackPressed in activity..
remove the super call : super.onBackPressed
and call finish.
I know it might be late, but here's my stupid mistake I didn't see straight away:
#Override
public void onStop() {
super.onDestroy(); //I was calling the wrong super
}
I had the same issue and it was caused by the reuse of ViewPager instance by different instances of a fragment. A solution was to null the adapter in onDestroyView() method of the fragment.
#Override public void onDestroyView() {
mViewPager.setAdapter(null);
super.onDestroyView();
}
Project demoing the issue and the solution can be found here.
I had the same issue. In my case the problem was that I was re-using without noticing the adapter from the previous time opened.
I looked into the FragmentManager.java class that send the exception and on the very same line that crashes says:
"Must be called from main thread of fragment host"
my code was:
PagerAdapter adapter = MPageAdapter.getInstance(getSupportFragmentManager());
viewPager.setAdapter(adapter);
because I was using my PageAdapter as a bridge to communicate between fragments I used a singleton pattern. That worked well for me but once I repeated this structure in another activity I got the same exception. And the reason was that I forgot to destroy the singleton of my adapter class at the end of every use.
#Override
protected void onDestroy() {
MPageAdapter.Destroy(); //I forgot this one, that makes singleton = null;
super.onDestroy();
}
I solved it by adding !isFinishing in onBackPressed() of my Activity.
override fun onBackPressed() {
if (!isFinishing) {
super.onBackPressed()
// your implementation specific code here..
}
}
The issue in my case was through some code flow, my DialogFragment was calling the onBackPressed() of its parent Activity just after calling finish() which causing this crash.
Hope it helps if someone is still looking for answer!
I was using the wrong activity reference to fetch
getSupportFragmentManager()
Using the correct activity fixed the crash for me.
Just comment super.onBackPressed() method and write finish() instead
#Override
public void onBackPressed() {
// super.onBackPressed();
finish();
}
In my case this worked!
I have been stuck on this for awhile, I am loading a fragment from within an activity (replacing another). It loads fine and I can see it and return to the previous fragment, but when I call a method to load data into it I get a null pointer exception. My first code was this...
public class MainActivity extends Activity implements MainListFragment.MainListListener, StoryFragment.StoryListener {
MainListFragment mainListFragment;
StoryFragment storyFragment;
.
.
.
public void onMainListClick(DBRecordType recordType, int recordID){
switch(recordType){
case story:{
DBHandler dbHandler = new DBHandler(this, null, null, 1);
Story story = dbHandler.getStory(recordID);
Toast.makeText(getApplicationContext(), story.toString(), Toast.LENGTH_SHORT ).show();
storyFragment = new StoryFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container, storyFragment);
transaction.addToBackStack(null);
transaction.commit();
storyFragment.loadStory(story);
break;
}
I am getting this error:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.EditText.setText(java.lang.CharSequence)' on a null object reference
at com.maniblett.listtest.StoryFragment.loadStory(StoryFragment.java:60)
at com.maniblett.listtest.MainActivity.onMainListClick(MainActivity.java:104)
The method in the fragment is setting text in an edittext, here's the fragment method I am calling mName and mSummary are references to edit text widgets :
public void loadStory(Story story){
mName.setText(story.get_name());
mSummary.setText(story.get_summary());
}
Is it legal to refer to a fragment like this (calling a method on the same reference I used to add the fragment via the fragment manager)? It seems like I already have a reference to the fragment, so using find fragment by ID would be redundant but when I double checked everything I read seemed to indicate I needed to find the fragment using findFragmentByID or Tag first so changed my code to this...
storyFragment = new StoryFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container, storyFragment, "loadedFragment");
transaction.addToBackStack(null);
transaction.commit();
StoryFragment loadedFragment = (StoryFragment)getFragmentManager().findFragmentByTag("loadedFragment");
loadedFragment.loadStory(story);
break;
But I get a similar error, which is:
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.maniblett.listtest.StoryFragment.loadStory(com.maniblett.listtest.datamodel.Story)' on a null object reference
at com.maniblett.listtest.MainActivity.onMainListClick(MainActivity.java:107)
at com.maniblett.listtest.MainListFragment.onListItemClick(MainListFragment.java:156)
at android.app.ListFragment$2.onItemClick(ListFragment.java:160)
at android.widget.AdapterView.performItemClick(AdapterView.java:300)
I have verified the object I am sending is not null after creating it (the 'story' in the case statement is an enum). Again, the frgament loads and runs fine if I comment out the method call, it is just when I call the emthod on it it fails. so, I guess I don't have the actual fragment that is loaded? Can someone tell me what I'm doing wrong? (I did search many other similar topics but couldn't find anything which helped, I'm pretty new to android). Thanks to any who take the time to help!
StoryFragment class:
public class StoryFragment extends Fragment
{
StoryListener activityCallback;
private EditText mName;
private EditText mSummary;
public interface StoryListener {
public void onAddButtonClick(String text);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_story, container, false);
Button button = (Button)rootView.findViewById(R.id.button);
mName = (EditText)rootView.findViewById(R.id.name);
mSummary = (EditText)rootView.findViewById(R.id.summary);
button.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
DBHandler dbHandler = new DBHandler(getActivity().getBaseContext(), null, null, 1);
Story story = new Story(mName.getText().toString(),mSummary.getText().toString());
dbHandler.addStory(story);
activityCallback.onAddButtonClick("Story"); //use same callback for all record types passing back record type created?
}
} );
return rootView;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try { activityCallback = (StoryListener) activity;
}
catch (ClassCastException e) {
throw new ClassCastException(activity.toString()+ " must implement StoryListener");
}
}
public void loadStory(Story story){
mName.setText(story.get_name());
mSummary.setText(story.get_summary());
}
}
Well, you should understand how android works in the first place. The onCreateView method gets called only when the fragment is going to come visible. So when you call loadstory immediately after the FragmentTransaction method its obvious you'll get an NullPointer Exception
My solution:
Declare two variables in the StoryFragment as name and summary
Change the loadStory method is like this
public void loadStory(Story story){
this.name = story.get_name();
this.summary = story.get_summary();
}
Finally in the OnCreateView method of StoryFragment after change here appropriately
mName = (EditText)rootView.findViewById(R.id.name);
mSummary = (EditText)rootView.findViewById(R.id.summary);
//if your fragment is also gonna be called by some other manner you should check for null in this.name and this.summary before setting it to the `TextView`
mName.setText(this.name);
mSummary.setText(this.summary);
Thank you. That worked perfectly. Actually, what I did was create a private Story type and then in StoryFragment.loadStory I assigned it.
public void loadStory(Story story){
mStory = story;
}
I also was able to then see that it works fine to not have to search for the fragment using findFragmentByID, this part worked:
storyFragment = new StoryFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container, storyFragment);
transaction.addToBackStack(null);
transaction.commit();
storyFragment.loadStory(story);
Thanks very much for pointing me in the right direction here
I wrote Android JUnit test for Activity that instantiates fragments (actually tabs). During the test, when I try to do anything with these tabs, they crash because getActivity() method in them returns null. The actual application (not a test) never shows this behavior and fragment getActivity() always returns the right parent activity there. My test case looks like:
public class SetupPanelTest extends ActivityUnitTestCase<MyAct> {
FSetup s;
public SetupPanelTest() {
super(MyAct.class);
}
protected void setUp() throws Exception {
super.setUp();
startActivity(new Intent(), null, null);
final MyAct act = getActivity();
AllTabs tabs = act.getTabs();
String tabname = act.getResources().getString(R.string.configuration);
// This method instantiates the activity as said below
s = (FSetup) tabs.showTab(tabname);
FragmentManager m = act.getFragmentManager();
// m.beginTransaction().attach(s).commit();
// ... and even this does not help when commented out
assertTrue(s instanceof FSetup); // Ok
assertEquals(act, s.getActivity()); // Failure
}
public void testOnPause() {
// this crashes because s.getActivity == null;
s.onPause();
}
}
The AllTabs creates a fragment, then required, in this way:
FragmentManager manager = getFragmentManager();
Fragment fragment = manager.findFragmentByTag(tabname);
if (fragment == null || fragment.getActivity() == null) {
Log.v(TAG, "Instantiating ");
fragment = new MyFragment();
manager.beginTransaction().replace(R.id.setup_tab, fragment, tabname).commit();
....
Here, all fragments are initially placeholders that are later replaced by the actual fragments:
<FrameLayout
android:id="#+id/setup_tab"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
The logcat shows that the new fragment has been instantiated. In the same layout, there is also the previously mentioned AllTabs fragment that seems not having this problem (where and how it gets FragmentManager otherwise):
<TabWidget
android:id="#android:id/alltabs"
...
Most impressively, when I call attach directly on the fragment manager obtained on the right activity, this still has no effect. I tried to put five seconds delay (I have read that transaction may be delayed), I tried to call the rest of the test through runOnUiThread - nothing helps.
The question is that is need to do so to attach my fragments to the activity also during the test. I have fragment and I have activity, I cannot attach one to another.
Even if you call .commit() on transaction, it is still not done, fragments are attached only lazily.
FragmentManager m = activity.getFragmentManager();
m.executePendingTransactions();
This finally attaches all fragments to the activity. Seems redundant when running the application itself but required in JUnit test case.