为啥 saveStateInstance 在屏幕方向上不起作用?

Posted

技术标签:

【中文标题】为啥 saveStateInstance 在屏幕方向上不起作用?【英文标题】:Why does saveStateInstance not work on screen orientation?为什么 saveStateInstance 在屏幕方向上不起作用? 【发布时间】:2020-02-01 06:26:06 【问题描述】:

我正在制作一个由一个主要活动和两个片段组成的导游应用程序。顶部片段包含城市列表,当您在一个城市打卡时,底部片段会显示该城市的描述。问题是,当我更改方向时,我收到一条错误消息“尝试在空对象引用上调用虚拟方法 'void android.widget.TextView.setText(java.lang.CharSequence)'”

这里是城市列表片段:

        package com.example.tourguide;


        import android.os.Bundle;
        import android.support.annotation.NonNull;
        import android.support.v4.app.Fragment;
        import android.view.LayoutInflater;
        import android.view.View;
        import android.view.ViewGroup;
        import android.widget.AdapterView;
        import android.widget.ArrayAdapter;
        import android.widget.ListView;


        /**
         * A simple @link Fragment subclass.
         */
        public class CityFragment extends Fragment 

            View view;
            String[] cities;
            String[] descriptions;
            ListView listView;
            DescriptionFragment text;
            int mPosition;

            public CityFragment() 
                // Required empty public constructor
            


            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                     Bundle savedInstanceState) 
                super.onCreate(savedInstanceState);
                // Check whether we're recreating a previously destroyed instance
                if (savedInstanceState != null) 
                    // Restore value of member from saved state
                    text = (DescriptionFragment) getFragmentManager().getFragment(savedInstanceState, getString(R.string.DESCRIPTION_FRAG));
                    mPosition = savedInstanceState.getInt(getString(R.string.POSITION));
                    cities = savedInstanceState.getStringArray(getString(R.string.CITY_ARRAY));
                    descriptions = savedInstanceState.getStringArray(getString(R.string.DESCRIPTION_ARRAY));
                    text.change(descriptions[mPosition], cities[mPosition]);
                

                    // Get views
                    this.view = inflater.inflate(R.layout.fragment_city, container, false);
                    cities = getResources().getStringArray(R.array.cities);
                    descriptions = getResources().getStringArray(R.array.cities_description);
                    listView = this.view.findViewById(R.id.city_list);

                    // Create an ArrayAdapter
                    ArrayAdapter<String> listViewAdapter = new ArrayAdapter<String>(getActivity(),
                            android.R.layout.simple_list_item_1, cities);

                    // Set adapter on the listView
                    listView.setAdapter(listViewAdapter);

                // Set an item click listener for ListView
                listView.setOnItemClickListener(new AdapterView.OnItemClickListener() 

                    @Override
                    public void onItemClick(AdapterView<?> parent, View view, int position, long id) 
                        // Get the selected item text from ListView
                        text = (DescriptionFragment) getFragmentManager().findFragmentById(R.id.fragmentBottom);
                        text.change(descriptions[Integer.parseInt(String.valueOf(position))], cities[Integer.parseInt(String.valueOf(position))]);
                        mPosition = position;
                    
                );

                // Inflate the layout for this fragment
                return this.view;

            

            @Override
            public void onSaveInstanceState(@NonNull Bundle outState) 
                super.onSaveInstanceState(outState);

                // Save the fragments Instance
                getFragmentManager().putFragment(outState, getString(R.string.DESCRIPTION_FRAG), text);
                outState.putInt(getString(R.string.POSITION), mPosition);
                outState.putStringArray(getString(R.string.CITY_ARRAY), cities);
                outState.putStringArray(getString(R.string.DESCRIPTION_ARRAY), descriptions);
            
        

这里是描述片段:

        package com.example.tourguide;


        import android.os.Bundle;
        import android.support.annotation.NonNull;
        import android.support.v4.app.Fragment;
        import android.view.LayoutInflater;
        import android.view.View;
        import android.view.ViewGroup;
        import android.widget.TextView;


        /**
         * A simple @link Fragment subclass.
         */
        public class DescriptionFragment extends Fragment 

            TextView cityName;
            TextView text;

            public DescriptionFragment() 
                // Required empty public constructor
            


            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                     Bundle savedInstanceState) 

                if (savedInstanceState != null) 

                

                // Inflate the layout for this fragment
                View view = inflater.inflate(R.layout.fragment_description, container, false);
                text = view.findViewById(R.id.city_description);
                cityName = view.findViewById(R.id.city_name);
                return view;
            

            public void change(String description, String city) 
                text.setText(description);
                cityName.setText(city);
            
        

text.change 方法似乎是问题所在,但我还能如何实现它来保存描述状态?

            if (savedInstanceState != null) 
                // Restore value of member from saved state
                text = (DescriptionFragment) getFragmentManager().getFragment(savedInstanceState, getString(R.string.DESCRIPTION_FRAG));
                mPosition = savedInstanceState.getInt(getString(R.string.POSITION));
                cities = savedInstanceState.getStringArray(getString(R.string.CITY_ARRAY));
                descriptions = savedInstanceState.getStringArray(getString(R.string.DESCRIPTION_ARRAY));
                text.change(descriptions[mPosition], cities[mPosition]);
            

【问题讨论】:

【参考方案1】:

为什么不将状态存储在 DescriptionFragment 中。

/**
 * A simple @link Fragment subclass.
 */
public class DescriptionFragment extends Fragment 

    private static final String DESCRIPTION = "DESCRIPTION";
    private static final String CITY = "CITY";

    TextView cityName;
    TextView text;

    public DescriptionFragment() 
        // Required empty public constructor
    


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) 
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_description, container, false);
    

    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) 
        text = view.findViewById(R.id.city_description);
        cityName = view.findViewById(R.id.city_name);

        if (savedInstanceState != null) 
            String description = savedInstanceState.getString(DESCRIPTION);
            String city = savedInstanceState.getString(CITY);
            change(description, city);
        
    

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) 
        super.onSaveInstanceState(outState);

        // Save the fragments Instance
        outState.putString(DESCRIPTION, text.getText().toString());
        outState.putString(CITY, cityName.getText().toString());
    

    public void change(String description, String city) 
        text.setText(description);
        cityName.setText(city);
    

【讨论】:

太棒了。这解决了问题。干杯,感谢帮助!!!!!! @Clancinio 那么你会接受我的回答吗?【参考方案2】:

可以在你的 xml AndroidManifest.xml 中使用该属性

 android:configChanges="keyboardHidden|orientation"

在这里它将向应用程序指示您将负责处理轮换,并且不会重新启动您的活动,因此没有空数据。

【讨论】:

谢谢。有用。但是当我回到纵向时它崩溃了?

以上是关于为啥 saveStateInstance 在屏幕方向上不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 MonthCalendar 在 3rd 方应用程序中看起来不同?

在 Eclipse 中使用 aar - 为啥第 3 方活动在构建时解决而不是运行时解决?

如果启用了环回,为啥发送方收不到它的多播 UDP 数据包?

是否可以在 android TV 中使用 3rd 方应用程序在任何屏幕上绘制叠加层?

为啥不尝试 I/O 就不可能检测到 TCP 套接字已被对等方优雅地关闭?

[Matlab]在信号调幅过程中用方波进行调幅还是正弦波?为啥?