Reputation: 37474
I have a MainActivity
, with a layout including two FrameLayout
to load Fragments
, one for a top bar with a vertical menu, another one for the content.
Everything works properly, excepted when I click the device's Home button and start the app again.
For instance when I start the app, click the menu option 2, which replaces the content fragment by an instance of the SomeFragment
shown below, then click the device's Home button, then start the app again, it restarts the SomeFragment
Fragment
as expected, but my app crashes in the TopBarFragment
, returning an error because the getView()
is null.
I guess I'm messing with the Fragment
lifecycle, but I can't find the solution.
Note: in order to test my app I checked the option Don't keep activities
in my device's developer options.
Anybody can help?
EDIT
When restarting the app, onResume
is not called in the TopBarFragment
instance. Why?
The instance called by
((TopBarFragment)getActivity().getSupportFragmentManager()
.findFragmentByTag("top_bar_fragment")).setSelectedButton(1);
seems to be 'empty'... Why?
EDIT 2: more experiments
When clicking on the device's Home button, onDetach
and onDestroyView
are called in TopBarFragment
, so why is onCreateView
not called again when restarting the app?
EDIT 3: more experiments
When restarting the app, the MainActivity
onCreate
is called, so
fragmentTransaction.replace(R.id.content_container, homeFragment, "");
is executed. However, it loads SomeFragment
, which is nice because it was the last Fragment
loaded in the content_container
, but unexpected because MainActivity
onCreate
is called and it should load HomeFragment
...
stacktrace
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.my.package/com.my.package.MainActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1967)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1992)
at android.app.ActivityThread.access$600(ActivityThread.java:127)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1158)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4511)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:980)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:747)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.my.package.TopBarFragment.setSelectedButton(TopBarFragment.java:345)
at com.my.package.SomeFragment.onCreateView(SomeFragment.java:50)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1460)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:911)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1070)
at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1861)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:547)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1136)
at android.app.Activity.performStart(Activity.java:4480)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1940)
... 11 more
MainActivity.java
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
Fragment homeFragment = new HomeFragment();
fragmentTransaction.replace(R.id.content_container, homeFragment, "");
Fragment topBarFragment = new TopBarFragment();
fragmentTransaction.replace(R.id.top_bar_container, topBarFragment, "top_bar_fragment");
fragmentTransaction.commit();
}
}
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" >
<FrameLayout
android:id="@+id/content_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="44dp" />
<FrameLayout
android:id="@+id/top_bar_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false" />
</RelativeLayout>
TopBarFragment.java
public class TopBarFragment extends Fragment{
private int mSelectedMenuOption = 0;
private LinearLayout mVerticalMenu;
private Boolean mMenuIsOpen = true;
private ImageButton btn_01, btn_02; // there are more
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.top_bar, container, false);
}
@Override
public void onActivityCreated (Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
btn_01 = (ImageButton) getView().findViewById(R.id.btn_01);
btn_02 = (ImageButton) getView().findViewById(R.id.btn_02);
btn_01.setOnClickListener(mButtonClickListener);
btn_02.setOnClickListener(mButtonClickListener);
mVerticalMenu = (LinearLayout) getView().findViewById(R.id.vertical_menu);
toggleMenu(0);
Button btn_menu = (Button) getView().findViewById(R.id.btn_menu);
btn_menu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// toggle vertical menu
}
});
}
private OnClickListener mButtonClickListener = new OnClickListener()
{
@Override
public void onClick(View v) {
/* ... */
if(!v.isSelected()){
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
switch(v.getId()){
case R.id.btn_01:
Fragment homeFragment = new HomeFragment();
fragmentTransaction.replace(R.id.content_container,homeFragment, "");
fragmentTransaction.commit();
break;
case R.id.btn_02:
Fragment someFragment = new SomeFragment();
fragmentTransaction.replace(R.id.content_container, someFragment, "");
fragmentTransaction.commit();
break;
}
}
}
};
public void setSelectedButton(int i){
// Crashes when starting the app, clicking on btn_02 to load a SomeFragment instance, clicking on the
// device's Home button, and starting the app again: getView() is null
// why?
/* ... */
mSelectedMenuOption = i;
}
}
SomeFragment
public class SomeFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
((TopBarFragment)getActivity().getSupportFragmentManager().findFragmentByTag("top_bar_fragment")).setSelectedButton(1);
return inflater.inflate(R.layout.some_fragment, container, false);
}
}
Upvotes: 3
Views: 7677
Reputation: 87064
From the stacktrace posted it seems that calling the setSelectedButton(1)
method on the TopBarFragment
(where you most likely update/work with its views) is done before its content view is built. Move the TopBarFragment
replace transaction before the transaction to replace the content view so its view its built before the content fragment try to access it.
Upvotes: 1
Reputation: 8747
You are doing this in the correct order according to the docs, onActivityCreated
is after onCreateView
. I know I have seen lots of working examples on SO where users use getView()
, but I have always used getActivity()
instead and put my declarations in my onStart
and it always works fine for me. You could try the following code:
@Override
public void onActivityCreated (Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
btn_01 = (ImageButton) getActivity().findViewById(R.id.btn_01);
btn_02 = (ImageButton) getActivity().findViewById(R.id.btn_02);
btn_01.setOnClickListener(mButtonClickListener);
btn_02.setOnClickListener(mButtonClickListener);
mVerticalMenu = (LinearLayout) getActivity().findViewById(R.id.vertical_menu);
toggleMenu(0);
Button btn_menu = (Button) getActivity().findViewById(R.id.btn_menu);
btn_menu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// toggle vertical menu
}
});
}
Upvotes: 0