3

我有一个MainActivity, 布局包括两个FrameLayout要加载Fragments,一个用于带有垂直菜单的顶部栏,另一个用于内容。

一切正常,除了当我单击设备的主页按钮并再次启动应用程序时。

例如,当我启动应用程序时,单击菜单选项 2,它将内容片段替换为SomeFragment如下所示的实例,然后单击设备的主页按钮,然后再次启动应用程序,它SomeFragment Fragment按预期重新启动,但我的应用程序崩溃在 中TopBarFragment,返回错误,因为getView()为空。

我想我在搞乱Fragment生命周期,但我找不到解决方案。

注意:为了测试我的应用程序,我检查了Don't keep activities我设备的开发者选项中的选项。

有人可以帮忙吗?

编辑

重新启动应用程序时,onResume不会在TopBarFragment实例中调用。为什么?调用的实例

((TopBarFragment)getActivity().getSupportFragmentManager()
    .findFragmentByTag("top_bar_fragment")).setSelectedButton(1);

似乎是“空的”……为什么?

编辑2:更多实验

当点击设备的 Home 键时,onDetachonDestroyView调用TopBarFragment,为什么onCreateView重启应用时没有再次调用?

编辑 3:更多实验

重新启动应用程序时,MainActivity onCreate会调用 ,所以

fragmentTransaction.replace(R.id.content_container, homeFragment, "");

被执行。但是,它加载了SomeFragment,这很好,因为它是最后一次Fragment加载的content_container,但出乎意料的是因为MainActivity onCreate被调用并且它应该加载HomeFragment......

堆栈跟踪

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();
    }
}

主要的.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;
    }
}

一些片段

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);
    }
}
4

2 回答 2

0

根据文档,您按照正确的顺序执行此操作,在onActivityCreated之后onCreateView。我知道我在 SO 上看到了很多用户使用的工作示例getView(),但我一直使用它getActivity()并将我的声明放在我的文件中onStart,它对我来说总是很好。您可以尝试以下代码:

@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             

        }
    });
}
于 2013-04-30T16:00:50.183 回答
0

从发布的堆栈跟踪看来,在其内容视图构建之前调用setSelectedButton(1)TopBarFragment您最有可能更新/使用其视图的位置)上的方法是完成的。将TopBarFragment替换事务移到替换内容视图的事务之前,以便在内容片段尝试访问它之前构建它的视图。

于 2013-05-01T10:23:12.087 回答