为什么按设置 Activity 工具栏上的向上按钮会破坏前一个 Activity?
Why previous Activity get destroyed pressing up button on Setting Activity Toolbar?
目标: 当用户在 SettingsActivity
工具栏上按回键时,上一个 Activity 应该从用户离开的地方恢复。
问题: 来自 android 开发者网站上报告的 Activity 生命周期 我了解到之前的 Activity 应该恢复调用 OnResume
方法,而不是在我的例子中 MainActivity
再次开始调用 OnCreate
方法。
具体流程如下:
1) 用户点击图标开始SettingsActivity
2)MapsActivity
调用 onPause
,然后调用 onSaveInstanceState
,然后调用 onStop
3) 用户在 SettingsActivity
上单击后退按钮
4)MapsActivity
调用 onDestroy
然后 onCreate
(我在第 2 点用 saveInstanceState
尝试保存的所有内容都丢失了,因为 Bundle
总是空)
代码
地图Activity(主要activity)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// .... other initialization code ... //
// If location permission is granted initialize Map
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
mapSync();
} else {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSION_FINE_LOCATION);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("prova", true);
}
// Where I start the second activity
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.connection_type:
// .... handle this case ... //
case R.id.settings:
Intent intent = new Intent(MapsActivity.this, SettingsActivity.class);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
设置Activity(调用activity)
public class SettingsActivity extends AppCompatActivity
{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.settings);
// Set the toolbar
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
myToolbar.setTitle("Settings");
myToolbar.setNavigationIcon(R.drawable.ic_baseline_arrow_back_24px);
myToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
setSupportActionBar(myToolbar);
}
public static class MainSettingsFragment extends PreferenceFragmentCompat {
public final static String KEY_ENABLE_BACKGROUND_UPDATE = "enable_background_update";
public final static String KEY_ENABLE_LAST_KNOWN_LOCATION = "enable_last_known_location";
public final static String KEY_DELETE_DB_DATA = "delete_db_data";
public final static String KEY_CHANGE_MAP_COLOR ="change_map_color";
private SharedPreferences.OnSharedPreferenceChangeListener preferenceChangeListener;
@Override
public void onCreatePreferences(Bundle bundle, String s) {
// Load the Preferences from the XML file
addPreferencesFromResource(R.xml.preferences);
preferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(key.equals(KEY_DELETE_DB_DATA))
{
String connectivityType = sharedPreferences.getString(key, null);
new DeleteAreaAsync(SignalAreaDatabase.getDatabase(getContext()), connectivityType).execute();
} else if(key.equals(KEY_CHANGE_MAP_COLOR)){
String gradientColor = sharedPreferences.getString(key, null);
SignalAreaDrawer signalAreaDrawer = SignalAreaDrawer.getSignalAreaDrawer();
signalAreaDrawer.setGradientColor( gradientColor);
}
}
};
}
@Override
public void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(preferenceChangeListener);
}
@Override
public void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
}
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
Google Maps Android API v2, but you must specify either coarse or fine
location permissions for the 'MyLocation' functionality.
-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Less accurate location: telephony manager and location requests -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Access to wifi network information -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- Change wifi connectivity state -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<!--
The API key for Google Maps-based APIs is defined as a string resource.
(See the file "res/values/google_maps_api.xml").
Note that the API key is linked to the encryption key used to sign the APK.
You need a different API key for each encryption key, including the release key that is used to
sign the APK for publishing.
You can define the keys for the debug and release targets in src/debug/ and src/release/.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />
<activity
android:name=".MapsActivity"
android:label="@string/title_activity_maps">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SettingsActivity"
android:parentActivityName=".MapsActivity"
android:theme="@style/PreferenceScreen" />
</application>
问题: 我怎样才能恢复以前的 Activity 状态并向用户准确显示他在打开第二个 Activity 时看到的内容?
编辑#1:
我试图覆盖 oonDestroy()
, onSaveInstance()
, onRestoreInstance()
,结果是这样的:
当我开始设置 activity 时,主要 activity 进入 onPause()
,如我所料。
当我按下设置 activity 上的后退按钮时,主要 activity 在 onDestroy()
之前和 onCreate()
之后立即移动,而不是调用onSaveInstance()
或 onRestoreInstance()
。
编辑 #2: 应用程序未通过 onSaveInstanceState(Bundle outState)
可能是因为我声明了它 public。现在应用程序调用它。所以我试图保存一些信息,比如 outState.putBoolean("prova", true);
但是当 mainActivity 被销毁时,在新的 onCreate(Bundle savedInstanceState)
调用中 Bundle savedInstanceState
总是空的。
编辑 #3: 正如@SherifelKhatib 建议的那样,我尝试从 MapsActivity
中删除所有 finish()
语句,并尝试替换 MapsActivity
用最小的 EmptyActivity
来查看问题是否在 MapsActivity
中。不幸的是,该应用程序具有相同的行为。
当用户按下后退按钮时,之前的应用程序总是会被销毁。无法恢复其状态。
编辑 #4: 我试过但仍然无效。修改 SettingsActivity
:
第一种方法
@Override
public void onBackPressed(){
moveTaskToBack(true);
}
第二种方法
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
第三种方法
@Override
public void onBackPressed() {
Intent backIntent = new Intent(this, MapsActivity.class);
backIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(backIntent);
}
并在 MainActivity
中添加:
Intent intent = new Intent(MapsActivity.this, SettingsActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
解决方案:
将此属性添加到清单中的 MainActivity
。
android:launchMode="singleTop"
说明
The "standard" and "singleTop" modes differ from each other in just
one respect: Every time there's a new intent for a "standard"
activity, a new instance of the class is created to respond to that
intent. Each instance handles a single intent. Similarly, a new
instance of a "singleTop" activity may also be created to handle a new
intent. However, if the target task already has an existing instance
of the activity at the top of its stack, that instance will receive
the new intent (in an onNewIntent() call); a new instance is not
created.
目标: 当用户在 SettingsActivity
工具栏上按回键时,上一个 Activity 应该从用户离开的地方恢复。
问题: 来自 android 开发者网站上报告的 Activity 生命周期 我了解到之前的 Activity 应该恢复调用 OnResume
方法,而不是在我的例子中 MainActivity
再次开始调用 OnCreate
方法。
具体流程如下:
1) 用户点击图标开始SettingsActivity
2)MapsActivity
调用 onPause
,然后调用 onSaveInstanceState
,然后调用 onStop
3) 用户在 SettingsActivity
4)MapsActivity
调用 onDestroy
然后 onCreate
(我在第 2 点用 saveInstanceState
尝试保存的所有内容都丢失了,因为 Bundle
总是空)
代码
地图Activity(主要activity)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// .... other initialization code ... //
// If location permission is granted initialize Map
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
mapSync();
} else {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSION_FINE_LOCATION);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("prova", true);
}
// Where I start the second activity
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.connection_type:
// .... handle this case ... //
case R.id.settings:
Intent intent = new Intent(MapsActivity.this, SettingsActivity.class);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
设置Activity(调用activity)
public class SettingsActivity extends AppCompatActivity
{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.settings);
// Set the toolbar
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
myToolbar.setTitle("Settings");
myToolbar.setNavigationIcon(R.drawable.ic_baseline_arrow_back_24px);
myToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
setSupportActionBar(myToolbar);
}
public static class MainSettingsFragment extends PreferenceFragmentCompat {
public final static String KEY_ENABLE_BACKGROUND_UPDATE = "enable_background_update";
public final static String KEY_ENABLE_LAST_KNOWN_LOCATION = "enable_last_known_location";
public final static String KEY_DELETE_DB_DATA = "delete_db_data";
public final static String KEY_CHANGE_MAP_COLOR ="change_map_color";
private SharedPreferences.OnSharedPreferenceChangeListener preferenceChangeListener;
@Override
public void onCreatePreferences(Bundle bundle, String s) {
// Load the Preferences from the XML file
addPreferencesFromResource(R.xml.preferences);
preferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(key.equals(KEY_DELETE_DB_DATA))
{
String connectivityType = sharedPreferences.getString(key, null);
new DeleteAreaAsync(SignalAreaDatabase.getDatabase(getContext()), connectivityType).execute();
} else if(key.equals(KEY_CHANGE_MAP_COLOR)){
String gradientColor = sharedPreferences.getString(key, null);
SignalAreaDrawer signalAreaDrawer = SignalAreaDrawer.getSignalAreaDrawer();
signalAreaDrawer.setGradientColor( gradientColor);
}
}
};
}
@Override
public void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(preferenceChangeListener);
}
@Override
public void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
}
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
Google Maps Android API v2, but you must specify either coarse or fine
location permissions for the 'MyLocation' functionality.
-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Less accurate location: telephony manager and location requests -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Access to wifi network information -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- Change wifi connectivity state -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<!--
The API key for Google Maps-based APIs is defined as a string resource.
(See the file "res/values/google_maps_api.xml").
Note that the API key is linked to the encryption key used to sign the APK.
You need a different API key for each encryption key, including the release key that is used to
sign the APK for publishing.
You can define the keys for the debug and release targets in src/debug/ and src/release/.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />
<activity
android:name=".MapsActivity"
android:label="@string/title_activity_maps">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SettingsActivity"
android:parentActivityName=".MapsActivity"
android:theme="@style/PreferenceScreen" />
</application>
问题: 我怎样才能恢复以前的 Activity 状态并向用户准确显示他在打开第二个 Activity 时看到的内容?
编辑#1:
我试图覆盖 oonDestroy()
, onSaveInstance()
, onRestoreInstance()
,结果是这样的:
当我开始设置 activity 时,主要 activity 进入
onPause()
,如我所料。当我按下设置 activity 上的后退按钮时,主要 activity 在
onDestroy()
之前和onCreate()
之后立即移动,而不是调用onSaveInstance()
或onRestoreInstance()
。
编辑 #2: 应用程序未通过 onSaveInstanceState(Bundle outState)
可能是因为我声明了它 public。现在应用程序调用它。所以我试图保存一些信息,比如 outState.putBoolean("prova", true);
但是当 mainActivity 被销毁时,在新的 onCreate(Bundle savedInstanceState)
调用中 Bundle savedInstanceState
总是空的。
编辑 #3: 正如@SherifelKhatib 建议的那样,我尝试从 MapsActivity
中删除所有 finish()
语句,并尝试替换 MapsActivity
用最小的 EmptyActivity
来查看问题是否在 MapsActivity
中。不幸的是,该应用程序具有相同的行为。
当用户按下后退按钮时,之前的应用程序总是会被销毁。无法恢复其状态。
编辑 #4: 我试过但仍然无效。修改 SettingsActivity
:
第一种方法
@Override
public void onBackPressed(){
moveTaskToBack(true);
}
第二种方法
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
第三种方法
@Override
public void onBackPressed() {
Intent backIntent = new Intent(this, MapsActivity.class);
backIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(backIntent);
}
并在 MainActivity
中添加:
Intent intent = new Intent(MapsActivity.this, SettingsActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
解决方案:
将此属性添加到清单中的 MainActivity
。
android:launchMode="singleTop"
说明
The "standard" and "singleTop" modes differ from each other in just one respect: Every time there's a new intent for a "standard" activity, a new instance of the class is created to respond to that intent. Each instance handles a single intent. Similarly, a new instance of a "singleTop" activity may also be created to handle a new intent. However, if the target task already has an existing instance of the activity at the top of its stack, that instance will receive the new intent (in an onNewIntent() call); a new instance is not created.