为什么 saveStateInstance 在屏幕方向上不起作用?
Why does saveStateInstance not work on screen orientation?
我正在制作一个导游应用程序,它由一个主要 activity 和两个片段组成。顶部片段包含一个城市列表,当您在一个城市打卡时,底部片段会显示对该城市的描述。问题是,当我改变方向时,我收到一条错误消息 "Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference"
这是城市列表片段:
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]);
}
可以在你的xmlAndroidManifest.xml
中使用属性
android:configChanges="keyboardHidden|orientation"
这里会向应用程序表明你将负责处理轮换,不会重新启动你的activity,这样就没有空数据了。
为什么不将状态存储在 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);
}
}
我正在制作一个导游应用程序,它由一个主要 activity 和两个片段组成。顶部片段包含一个城市列表,当您在一个城市打卡时,底部片段会显示对该城市的描述。问题是,当我改变方向时,我收到一条错误消息 "Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference"
这是城市列表片段:
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]);
}
可以在你的xmlAndroidManifest.xml
中使用属性 android:configChanges="keyboardHidden|orientation"
这里会向应用程序表明你将负责处理轮换,不会重新启动你的activity,这样就没有空数据了。
为什么不将状态存储在 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);
}
}