Issue
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);
}
}
Solution
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.
Answered By - user
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.