多次调用 OnResume / OnPause
OnResume / OnPause called multiple times
我的 MainActivity 正在加载不同的片段。此外,可以从 MainActivity.
打开 Settings-Activity
如果用户只是在片段之间切换,一切都很好。
打开设置-Activity 并返回主Activity 时,onResume 和 onPause 被调用两次。如果用户打开 Settings-Activity 并再次返回 MainActivity,onResume 和 onPause 将被调用 3 次。每次用户打开 Settings-Activity 并返回 MainActivity.
时都会增加
主要Activity
public class MainActivity extends AppCompatActivity implements MyFragment.OnListFragmentInteractionListener, AsyncResponse {
private FragmentA fragmentA = new FragmentA();
private DatabaseHandler databaseHandler = new DatabaseHandler(this);
private NavigationView navigationView;
private DrawerLayout drawer;
private Toolbar toolbar;
// index to identify current nav menu item
private static int navItemIndex = 0;
public static String CURRENT_TAG = MyConstants.TAG_FRAGMENT_A;
// toolbar titles respected to selected nav menu item
private String[] activityTitles;
// flag to load home fragment when user presses back key
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentA.setDatabaseHandler(this.databaseHandler);
// Init UI
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mHandler = new Handler();
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
navigationView = (NavigationView) findViewById(R.id.nav_view);
fabSendButton = (FloatingActionButton) findViewById(R.id.fab);
// Navigation view header
navHeader = navigationView.getHeaderView(0);
// load toolbar titles from string resources
activityTitles = getResources().getStringArray(R.array.sliding_menu_item_activity_titles);
// initializing navigation menu
setUpNavigationView();
if (savedInstanceState == null) {
navItemIndex = 0;
CURRENT_TAG = MyConstants.TAG_FRAGMENT_A;
loadHomeFragment();
}
}
/***
* Returns respected fragment that user
* selected from navigation menu
*/
private void loadHomeFragment() {
// set toolbar title
setToolbarTitle();
// if user select the current navigation menu again, don't do anything
// just close the navigation drawer
if (getSupportFragmentManager().findFragmentByTag(CURRENT_TAG) != null) {
drawer.closeDrawers();
return;
}
// Sometimes, when fragment has huge data, screen seems hanging
// when switching between navigation menus
// So using runnable, the fragment is loaded with cross fade effect
// This effect can be seen in GMail app
Runnable mPendingRunnable = new Runnable() {
@Override
public void run() {
// update the activity_main_header_with_item content by replacing fragments
Fragment fragment = getFragment();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
fragmentTransaction.replace(R.id.frame, fragment, CURRENT_TAG);
fragmentTransaction.commit();
}
};
// If mPendingRunnable is not null, then add to the message queue
if (mPendingRunnable != null) {
mHandler.post(mPendingRunnable);
}
//Closing drawer on item click
drawer.closeDrawers();
// refresh toolbar menu
invalidateOptionsMenu();
}
private Fragment getFragment() {
switch (navItemIndex) {
case 0:
return this.fragmentA;
case 1:
Fragment B fragmentB = new FragmentB();
fragmentB.setDatabaseHandler(this.databaseHandler);
return fragmentB;
default:
return this.fragmentA;
}
}
private void setToolbarTitle() {
getSupportActionBar().setTitle(activityTitles[navItemIndex]);
}
private void setUpNavigationView() {
//Setting Navigation View Item Selected Listener to handle the item click of the navigation menu
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
// This method will trigger on item Click of navigation menu
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
//Check to see which item was being clicked and perform appropriate action
switch (menuItem.getItemId()) {
//Replacing the activity_main_header_with_item content with ContentFragment Which is our Inbox View;
case R.id.nav_A:
navItemIndex = 0;
CURRENT_TAG = MyConstants.TAG_FRAGMENT_A;
break;
case R.id.nav_B:
navItemIndex = 1;
CURRENT_TAG = MyConstants.TAG_FRAGMENT_B;
break;
default:
navItemIndex = 0;
}
loadHomeFragment();
return true;
}
});
ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.openDrawer, R.string.closeDrawer) {
@Override
public void onDrawerClosed(View drawerView) {
// Code here will be triggered once the drawer closes as we dont want anything to happen so we leave this blank
super.onDrawerClosed(drawerView);
}
@Override
public void onDrawerOpened(View drawerView) {
// Code here will be triggered once the drawer open as we dont want anything to happen so we leave this blank
super.onDrawerOpened(drawerView);
}
};
//Setting the actionbarToggle to drawer layout
drawer.setDrawerListener(actionBarDrawerToggle);
//calling sync state is necessary or else your hamburger icon wont show up
actionBarDrawerToggle.syncState();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main_header_with_item, menu);
return true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main_header_with_item, menu);
// Disable Player Icon in case no player is found on device
Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, ScrobblOrDroidConstants.MUSIC_APP);
List<ResolveInfo> activities = getPackageManager().queryIntentActivities(intent, 0);
if(activities == null || activities.size() <= 0) {
MenuItem player = menu.findItem(R.id.player);
if(player != null){
player.setVisible(false);
}
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.player) {
Timber.i( "Added onClick listener to ImageView ivPlayer.");
Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, ScrobblOrDroidConstants.MUSIC_APP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
return true;
} else if (id == R.id.settings) {
// launch settings activity
startActivity(new Intent(MainActivity.this, SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onResume() {
Timber.i("MainActivity.onResume-called.");
activityVisible = true;
updateHomeFragment();
callLongUserOperation();
super.onResume();
}
@Override
public void onPause() {
Timber.i("MainActivity.onPause-called.");
activityVisible = false;
super.onPause();
}
}
public void updateHomeFragment() {
if (CURRENT_TAG == MyConstants.TAG_HOME) {
Timber.i( "updating HomeFragment");
fragmentA.swap();
}
}
设置Activity
public class SettingsActivity extends AppCompatPreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupActionBar();
getFragmentManager().beginTransaction().replace(android.R.id.content, new MainPreferenceFragment()).commit();
}
private void setupActionBar() {
ViewGroup rootView = (ViewGroup)findViewById(R.id.action_bar_root);
View view = getLayoutInflater().inflate(R.layout.pref_toolbar, rootView, false);
rootView.addView(view, 0);
Toolbar toolbar = (Toolbar)findViewById(R.id.pref_toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
// Show the Up button in the action bar.
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
public static class MainPreferenceFragment extends PreferenceFragment {
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_main);
// gallery EditText change listener
bindPreferenceSummaryToValue(findPreference(MyConstants.RECENTLY_SCROBBLED_KEY));
bindPreferenceSummaryToValue(findPreference(MyConstants.SCROBBLE_DURATION_KEY));
// feedback preference click listener
Preference myPref = findPreference("key_send_feedback");
myPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
sendFeedback(getActivity());
return true;
}
});
// rating preference click listener
Preference myPrefRate = findPreference("key_send_rate");
myPrefRate.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
sendRating(getActivity());
return true;
}
});
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
}
return super.onOptionsItemSelected(item);
}
private static void bindPreferenceSummaryToValue(Preference preference) {
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager.getDefaultSharedPreferences(preference.getContext()).getString(preference.getKey(), ""));
}
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String stringValue = newValue.toString();
if(preference.getKey().equalsIgnoreCase(MyConstants.RECENTLY_SCROBBLED_KEY)){
preference.setSummary(stringValue + " " + preference.getContext().getResources().getString(R.string.pref_recently_scrobbled_summary));
}
if(preference.getKey().equalsIgnoreCase(MyConstants.SCROBBLE_DURATION_KEY)){
preference.setSummary(preference.getContext().getResources().getString(R.string.pref_scrobble_percentage_summary, stringValue));
}
return true;
}
};
/**
* Email client intent to send support mail
* Appends the necessary device information to email body
* useful when providing support
*/
public static void sendFeedback(Context context) {
String body = null;
try {
body = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
body = "\n\n-----------------------------\nPlease don't remove this information\n Device OS: Android \n Device OS version: " +
Build.VERSION.RELEASE + "\n App Version: " + body + "\n Device Brand: " + Build.BRAND +
"\n Device Model: " + Build.MODEL + "\n Device Manufacturer: " + Build.MANUFACTURER;
} catch (PackageManager.NameNotFoundException e) {
}
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("message/rfc822");
intent.putExtra(Intent.EXTRA_EMAIL, new String[]{MyConstants.E_MAIL_ADDRESS});
intent.putExtra(Intent.EXTRA_SUBJECT, "Feedback for " + context.getResources().getString(R.string.app_name));
intent.putExtra(Intent.EXTRA_TEXT, body);
context.startActivity(Intent.createChooser(intent, context.getString(R.string.pref_choose_email_client)));
}
public static void sendRating(Context context) {
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(MyConstants.PLAY_STORE_URL));
context.startActivity(i);;
}
@Override
public void onResume() {
super.onResume();
PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).registerOnSharedPreferenceChangeListener(this);
super.onPause();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(key.equalsIgnoreCase(MyConstants.NOTIFICATION_ENABLED_KEY)){
EventBus.getDefault().post(new NotificationEvent());
Timber.i( "NotificationEvent Posted");
}
}
}
AppCompatPreferenceActivity
public class AppCompatPreferenceActivity extends PreferenceActivity {
private AppCompatDelegate mDelegate;
@Override
protected void onCreate(Bundle savedInstanceState) {
getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getDelegate().onPostCreate(savedInstanceState);
}
public ActionBar getSupportActionBar() {
return getDelegate().getSupportActionBar();
}
public void setSupportActionBar(@Nullable Toolbar toolbar) {
getDelegate().setSupportActionBar(toolbar);
}
@Override
public MenuInflater getMenuInflater() {
return getDelegate().getMenuInflater();
}
@Override
public void setContentView(@LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
@Override
public void setContentView(View view) {
getDelegate().setContentView(view);
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().setContentView(view, params);
}
@Override
public void addContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().addContentView(view, params);
}
@Override
protected void onPostResume() {
super.onPostResume();
getDelegate().onPostResume();
}
@Override
protected void onTitleChanged(CharSequence title, int color) {
super.onTitleChanged(title, color);
getDelegate().setTitle(title);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getDelegate().onConfigurationChanged(newConfig);
}
@Override
protected void onStop() {
super.onStop();
getDelegate().onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
getDelegate().onDestroy();
}
public void invalidateOptionsMenu() {
getDelegate().invalidateOptionsMenu();
}
private AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, null);
}
return mDelegate;
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ordroid.My"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="25" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:name=".ui.activity.MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.activity.LoginActivity"
android:excludeFromRecents="true"
android:label="@string/app_name"
android:screenOrientation="portrait"></activity>
<activity
android:name=".ui.activity.SettingsActivity"
android:label="@string/settings">
<!-- Parent activity meta-data to support 4.0 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ui.activity.MainActivity" />
</activity>
<!-- start service on device boot complete -->
<receiver
android:name=".util.receiver.MyBroadcastReceiver"
android:enabled="true"
android:exported="true"
android:label="StartMyServiceAtBootReceiver">
<intent-filter>
<action android:name="com.android.music.metachanged" />
<action android:name="com.android.music.playstatechanged" />
<!-- <action android:name="android.intent.action._BOOT_COMPLETED" /> -->
</intent-filter>
</receiver>
<receiver android:name=".util.receiver.MyInternetConnectionBroadcastReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
</application>
</manifest>
如何避免这些多次调用?
似乎是 Android SDK 构建工具中的错误。更新后效果很好!
我遇到了同样的问题,其中一个活动的 onResume() 被调用了三次。
我通过将相应 activity 的 onCreate() 中的布尔值设置为 false 来修复它。例如:
boolean onResumeCalled = false
并且每次创建 activity 时,我都会将 onResumeCalled 保持为 false。
在onResume()中,我设置了一个检查
if(!onResumeCalled)
在 onResume() 的开始。
现在,当创建 activity 时,onResumeCalled 为 false。然后,一旦onResume()里面的方法被调用,我把onResumeCalled的值改成true,这样第二次调用onResume()的时候,onResume()里面的方法就不会被访问了,因为onResumeCalled的值现在是是的。
我在 Android 上发现 here 这种行为的某些原因。对我来说,这就是原因。
onPause-onResume-onPause-onResume just happens every time, when app is
starting first time after installation. You can simply invoke this
behavior by doing any change in code and rerunning (which includes
recompiling) the app from your IDE.
No matter if you use AppCompat libs or not.
我的 MainActivity 正在加载不同的片段。此外,可以从 MainActivity.
打开 Settings-Activity如果用户只是在片段之间切换,一切都很好。
打开设置-Activity 并返回主Activity 时,onResume 和 onPause 被调用两次。如果用户打开 Settings-Activity 并再次返回 MainActivity,onResume 和 onPause 将被调用 3 次。每次用户打开 Settings-Activity 并返回 MainActivity.
时都会增加主要Activity
public class MainActivity extends AppCompatActivity implements MyFragment.OnListFragmentInteractionListener, AsyncResponse {
private FragmentA fragmentA = new FragmentA();
private DatabaseHandler databaseHandler = new DatabaseHandler(this);
private NavigationView navigationView;
private DrawerLayout drawer;
private Toolbar toolbar;
// index to identify current nav menu item
private static int navItemIndex = 0;
public static String CURRENT_TAG = MyConstants.TAG_FRAGMENT_A;
// toolbar titles respected to selected nav menu item
private String[] activityTitles;
// flag to load home fragment when user presses back key
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentA.setDatabaseHandler(this.databaseHandler);
// Init UI
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mHandler = new Handler();
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
navigationView = (NavigationView) findViewById(R.id.nav_view);
fabSendButton = (FloatingActionButton) findViewById(R.id.fab);
// Navigation view header
navHeader = navigationView.getHeaderView(0);
// load toolbar titles from string resources
activityTitles = getResources().getStringArray(R.array.sliding_menu_item_activity_titles);
// initializing navigation menu
setUpNavigationView();
if (savedInstanceState == null) {
navItemIndex = 0;
CURRENT_TAG = MyConstants.TAG_FRAGMENT_A;
loadHomeFragment();
}
}
/***
* Returns respected fragment that user
* selected from navigation menu
*/
private void loadHomeFragment() {
// set toolbar title
setToolbarTitle();
// if user select the current navigation menu again, don't do anything
// just close the navigation drawer
if (getSupportFragmentManager().findFragmentByTag(CURRENT_TAG) != null) {
drawer.closeDrawers();
return;
}
// Sometimes, when fragment has huge data, screen seems hanging
// when switching between navigation menus
// So using runnable, the fragment is loaded with cross fade effect
// This effect can be seen in GMail app
Runnable mPendingRunnable = new Runnable() {
@Override
public void run() {
// update the activity_main_header_with_item content by replacing fragments
Fragment fragment = getFragment();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
fragmentTransaction.replace(R.id.frame, fragment, CURRENT_TAG);
fragmentTransaction.commit();
}
};
// If mPendingRunnable is not null, then add to the message queue
if (mPendingRunnable != null) {
mHandler.post(mPendingRunnable);
}
//Closing drawer on item click
drawer.closeDrawers();
// refresh toolbar menu
invalidateOptionsMenu();
}
private Fragment getFragment() {
switch (navItemIndex) {
case 0:
return this.fragmentA;
case 1:
Fragment B fragmentB = new FragmentB();
fragmentB.setDatabaseHandler(this.databaseHandler);
return fragmentB;
default:
return this.fragmentA;
}
}
private void setToolbarTitle() {
getSupportActionBar().setTitle(activityTitles[navItemIndex]);
}
private void setUpNavigationView() {
//Setting Navigation View Item Selected Listener to handle the item click of the navigation menu
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
// This method will trigger on item Click of navigation menu
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
//Check to see which item was being clicked and perform appropriate action
switch (menuItem.getItemId()) {
//Replacing the activity_main_header_with_item content with ContentFragment Which is our Inbox View;
case R.id.nav_A:
navItemIndex = 0;
CURRENT_TAG = MyConstants.TAG_FRAGMENT_A;
break;
case R.id.nav_B:
navItemIndex = 1;
CURRENT_TAG = MyConstants.TAG_FRAGMENT_B;
break;
default:
navItemIndex = 0;
}
loadHomeFragment();
return true;
}
});
ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.openDrawer, R.string.closeDrawer) {
@Override
public void onDrawerClosed(View drawerView) {
// Code here will be triggered once the drawer closes as we dont want anything to happen so we leave this blank
super.onDrawerClosed(drawerView);
}
@Override
public void onDrawerOpened(View drawerView) {
// Code here will be triggered once the drawer open as we dont want anything to happen so we leave this blank
super.onDrawerOpened(drawerView);
}
};
//Setting the actionbarToggle to drawer layout
drawer.setDrawerListener(actionBarDrawerToggle);
//calling sync state is necessary or else your hamburger icon wont show up
actionBarDrawerToggle.syncState();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main_header_with_item, menu);
return true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main_header_with_item, menu);
// Disable Player Icon in case no player is found on device
Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, ScrobblOrDroidConstants.MUSIC_APP);
List<ResolveInfo> activities = getPackageManager().queryIntentActivities(intent, 0);
if(activities == null || activities.size() <= 0) {
MenuItem player = menu.findItem(R.id.player);
if(player != null){
player.setVisible(false);
}
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.player) {
Timber.i( "Added onClick listener to ImageView ivPlayer.");
Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, ScrobblOrDroidConstants.MUSIC_APP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
return true;
} else if (id == R.id.settings) {
// launch settings activity
startActivity(new Intent(MainActivity.this, SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onResume() {
Timber.i("MainActivity.onResume-called.");
activityVisible = true;
updateHomeFragment();
callLongUserOperation();
super.onResume();
}
@Override
public void onPause() {
Timber.i("MainActivity.onPause-called.");
activityVisible = false;
super.onPause();
}
}
public void updateHomeFragment() {
if (CURRENT_TAG == MyConstants.TAG_HOME) {
Timber.i( "updating HomeFragment");
fragmentA.swap();
}
}
设置Activity
public class SettingsActivity extends AppCompatPreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupActionBar();
getFragmentManager().beginTransaction().replace(android.R.id.content, new MainPreferenceFragment()).commit();
}
private void setupActionBar() {
ViewGroup rootView = (ViewGroup)findViewById(R.id.action_bar_root);
View view = getLayoutInflater().inflate(R.layout.pref_toolbar, rootView, false);
rootView.addView(view, 0);
Toolbar toolbar = (Toolbar)findViewById(R.id.pref_toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
// Show the Up button in the action bar.
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
public static class MainPreferenceFragment extends PreferenceFragment {
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_main);
// gallery EditText change listener
bindPreferenceSummaryToValue(findPreference(MyConstants.RECENTLY_SCROBBLED_KEY));
bindPreferenceSummaryToValue(findPreference(MyConstants.SCROBBLE_DURATION_KEY));
// feedback preference click listener
Preference myPref = findPreference("key_send_feedback");
myPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
sendFeedback(getActivity());
return true;
}
});
// rating preference click listener
Preference myPrefRate = findPreference("key_send_rate");
myPrefRate.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
sendRating(getActivity());
return true;
}
});
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
}
return super.onOptionsItemSelected(item);
}
private static void bindPreferenceSummaryToValue(Preference preference) {
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager.getDefaultSharedPreferences(preference.getContext()).getString(preference.getKey(), ""));
}
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String stringValue = newValue.toString();
if(preference.getKey().equalsIgnoreCase(MyConstants.RECENTLY_SCROBBLED_KEY)){
preference.setSummary(stringValue + " " + preference.getContext().getResources().getString(R.string.pref_recently_scrobbled_summary));
}
if(preference.getKey().equalsIgnoreCase(MyConstants.SCROBBLE_DURATION_KEY)){
preference.setSummary(preference.getContext().getResources().getString(R.string.pref_scrobble_percentage_summary, stringValue));
}
return true;
}
};
/**
* Email client intent to send support mail
* Appends the necessary device information to email body
* useful when providing support
*/
public static void sendFeedback(Context context) {
String body = null;
try {
body = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
body = "\n\n-----------------------------\nPlease don't remove this information\n Device OS: Android \n Device OS version: " +
Build.VERSION.RELEASE + "\n App Version: " + body + "\n Device Brand: " + Build.BRAND +
"\n Device Model: " + Build.MODEL + "\n Device Manufacturer: " + Build.MANUFACTURER;
} catch (PackageManager.NameNotFoundException e) {
}
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("message/rfc822");
intent.putExtra(Intent.EXTRA_EMAIL, new String[]{MyConstants.E_MAIL_ADDRESS});
intent.putExtra(Intent.EXTRA_SUBJECT, "Feedback for " + context.getResources().getString(R.string.app_name));
intent.putExtra(Intent.EXTRA_TEXT, body);
context.startActivity(Intent.createChooser(intent, context.getString(R.string.pref_choose_email_client)));
}
public static void sendRating(Context context) {
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(MyConstants.PLAY_STORE_URL));
context.startActivity(i);;
}
@Override
public void onResume() {
super.onResume();
PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).registerOnSharedPreferenceChangeListener(this);
super.onPause();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(key.equalsIgnoreCase(MyConstants.NOTIFICATION_ENABLED_KEY)){
EventBus.getDefault().post(new NotificationEvent());
Timber.i( "NotificationEvent Posted");
}
}
}
AppCompatPreferenceActivity
public class AppCompatPreferenceActivity extends PreferenceActivity {
private AppCompatDelegate mDelegate;
@Override
protected void onCreate(Bundle savedInstanceState) {
getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getDelegate().onPostCreate(savedInstanceState);
}
public ActionBar getSupportActionBar() {
return getDelegate().getSupportActionBar();
}
public void setSupportActionBar(@Nullable Toolbar toolbar) {
getDelegate().setSupportActionBar(toolbar);
}
@Override
public MenuInflater getMenuInflater() {
return getDelegate().getMenuInflater();
}
@Override
public void setContentView(@LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
@Override
public void setContentView(View view) {
getDelegate().setContentView(view);
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().setContentView(view, params);
}
@Override
public void addContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().addContentView(view, params);
}
@Override
protected void onPostResume() {
super.onPostResume();
getDelegate().onPostResume();
}
@Override
protected void onTitleChanged(CharSequence title, int color) {
super.onTitleChanged(title, color);
getDelegate().setTitle(title);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getDelegate().onConfigurationChanged(newConfig);
}
@Override
protected void onStop() {
super.onStop();
getDelegate().onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
getDelegate().onDestroy();
}
public void invalidateOptionsMenu() {
getDelegate().invalidateOptionsMenu();
}
private AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, null);
}
return mDelegate;
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ordroid.My"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="25" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:name=".ui.activity.MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.activity.LoginActivity"
android:excludeFromRecents="true"
android:label="@string/app_name"
android:screenOrientation="portrait"></activity>
<activity
android:name=".ui.activity.SettingsActivity"
android:label="@string/settings">
<!-- Parent activity meta-data to support 4.0 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ui.activity.MainActivity" />
</activity>
<!-- start service on device boot complete -->
<receiver
android:name=".util.receiver.MyBroadcastReceiver"
android:enabled="true"
android:exported="true"
android:label="StartMyServiceAtBootReceiver">
<intent-filter>
<action android:name="com.android.music.metachanged" />
<action android:name="com.android.music.playstatechanged" />
<!-- <action android:name="android.intent.action._BOOT_COMPLETED" /> -->
</intent-filter>
</receiver>
<receiver android:name=".util.receiver.MyInternetConnectionBroadcastReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
</application>
</manifest>
如何避免这些多次调用?
似乎是 Android SDK 构建工具中的错误。更新后效果很好!
我遇到了同样的问题,其中一个活动的 onResume() 被调用了三次。
我通过将相应 activity 的 onCreate() 中的布尔值设置为 false 来修复它。例如:
boolean onResumeCalled = false
并且每次创建 activity 时,我都会将 onResumeCalled 保持为 false。
在onResume()中,我设置了一个检查
if(!onResumeCalled)
在 onResume() 的开始。
现在,当创建 activity 时,onResumeCalled 为 false。然后,一旦onResume()里面的方法被调用,我把onResumeCalled的值改成true,这样第二次调用onResume()的时候,onResume()里面的方法就不会被访问了,因为onResumeCalled的值现在是是的。
我在 Android 上发现 here 这种行为的某些原因。对我来说,这就是原因。
onPause-onResume-onPause-onResume just happens every time, when app is starting first time after installation. You can simply invoke this behavior by doing any change in code and rerunning (which includes recompiling) the app from your IDE.
No matter if you use AppCompat libs or not.