Why will the onResume method be run twice if the application still uses the onCreate method?

I am developing an Android application and in one of the activities that I use MapsActivity to show a map. I saw that on emulator 2.2 (API8) it takes some time to load the map, and I have time to press the menu button and then return to the application and still load setContentView (), the problem comes when it goes to onResume ( ), which will be called twice.

According to the Android activity life cycle, after onPause () β†’ [onRestart () β†’ onStart ()] β†’ onResume () will be called if the application reappears in the foreground and onResume () is called after onCreate () β†’ [onStart ()] at startup.

But why isn't it called once if it still loads on setContentView in onCreate ()?

This is what interests me, because I would not want to use a boolean every time I use cards, thinking that it can be executed twice to avoid problems, i.e. double increase counter.

I don’t know if the emulator problem is a problem that I saw in the landscape portrait orientation http://code.google.com/p/android/issues/detail?id=2423 .

Please take a look at this:

public class LocationActivity extends MapActivity { private static final String TAG = "LocationActivity"; private static int i; protected void onCreate(Bundle savedInstanceState) { i = 0; super.onCreate(savedInstanceState); setContentView(R.layout.activity_location); } protected void onResume(){ super.onResume(); i++; Log.w(TAG,String.valueOf(i)); showDialogSettings(); } private void showDialogSettings() { AlertDialog.Builder dialog = new AlertDialog.Builder(this); String title = "I-Value:" + String.valueOf(i); String positiveButton = "OK"; final Intent intent = new Intent(Settings.ACTION_SETTINGS); dialog.setTitle(title); dialog.setPositiveButton(positiveButton, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Intent settingsIntent = intent; startActivity(settingsIntent); } }); dialog.show(); } @Override protected boolean isRouteDisplayed() { return false; } } 

activity_location.xml

  <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.google.android.maps.MapView android:id="@+id/locationactivity" android:layout_width="match_parent" android:layout_height="match_parent" android:apiKey="XXXXXXXXXXXXXXX" android:clickable="false" android:enabled="true" /> </LinearLayout> 

You can re-create the problem:

  • If you set a breakpoint in setContentView another in super.OnResume ().
  • Run and view debugging.
  • Put the app in the background and run it again.
  • Complete the execution, you will see a dialog box showing the value: 2.


Read the comments made by Geobits and G. Blake Meike, this part is only an answer to clarify if I am wrong.

Perhaps the map example was bad due to the asynchronous loading of the map. I changed MapsActivity for Activity, let's say that the phone is overloaded, so onCreate will execute a cycle of 8 seconds (no latency for Android does not respond).

And here is the new code using the lightweight layout for Android:

  public class LocationActivity extends Activity { private static final String TAG = "LocationActivity"; private static int i; protected void onCreate(Bundle savedInstanceState) { i = 0; Log.w(TAG,"onCreate"); super.onCreate(savedInstanceState); setContentView(android.R.layout.simple_spinner_item); Log.w(TAG,"beforeLoop"); try { for(int j = 0; j < 8; j++){ Log.w(TAG,"Sleeping..."); Thread.sleep(1000); } } catch (InterruptedException e) { } Log.w(TAG,"afterLoop"); } protected void onResume(){ super.onResume(); Log.w(TAG,"onResume" + String.valueOf(i)); i++; Log.w(TAG,"check Mobile Connectivity"); ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); if(networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_MOBILE && networkInfo.isAvailable()){ Toast.makeText(this, "Network available!", Toast.LENGTH_LONG).show(); Log.w(TAG,"showingToast"); } } protected void onPause(){ super.onPause(); Log.w(TAG,"onPause:" + String.valueOf(i)); } protected void onStop(){ super.onResume(); Log.w(TAG,"onStop:" + String.valueOf(i)); } } 

If I hide the application when the log still prints "Sleeping ..." and I quickly launch the application, I can see "Sleeping ...", onResume will check the connection twice (this is the correct way to check the network connection).

Here goes logCat:

  • 2-28 20: 02: 48.643: W / LocationActivity (651): onCreate
  • 2-28 20: 02: 48.646: W / LocationActivity (651): beforeLoop
  • 02-28 20: 02: 48.646: W / LocationActivity (651): Sleeping ...
  • 02-28 20: 02: 49.655: W / LocationActivity (651): Sleeping ...
  • 02-28 20: 02: 50.678: W / LocationActivity (651): Sleeping ...
  • 02-28 20: 02: 51.673: W / LocationActivity (651): Sleeping ...
  • 02-28 20: 02: 52.674: W / LocationActivity (651): Sleeping ...
  • 02-28 20: 02: 53.738: W / LocationActivity (651): Sleeping ...
  • 02-28 20: 02: 54.773: W / LocationActivity (651): Sleeping ...
  • 02-28 20: 02: 55.795: W / LocationActivity (651): Sleeping ...
  • 02-28 20: 02: 56.816: W / LocationActivity (651): afterLoop
  • 02-28 20: 02: 56.824: W / LocationActivity (651): onResume0
  • 02-28 20: 02: 56.824: W / LocationActivity (651): check your mobile connection
  • 02-28 20: 02: 57.134: W / LocationActivity (651): showToast
  • 02-28 20: 02: 57.234: W / LocationActivity (651): onPause: 1
  • 02-28 20: 02: 57.253: W / LocationActivity (651): onStop: 1
  • 02-28 20: 02: 57.264: W / LocationActivity (651): onResume1
  • 02-28 20: 02: 57.264: W / LocationActivity (651): check your mobile connection
  • 02-28 20: 02: 57.324: W / LocationActivity (651): showToast

The toast will show the message twice.

Looking at logCat, the life cycle is correct, but I just want to take into account that sometimes onCreate can be delayed due to an overloaded system, and if onResume is executed twice, then I have to take care of some initializations, so I have to use boolean elements, which, in my opinion, I should not use, because onCreate still works.

If instead of Toast this is a dialog, from the user's POV two dialogs are not welcome.

Please execute the code just like me, I'm stubborn enough not to give up: P

+6
source share
1 answer

This is by design. If you send the operation in the background, it should call onResume() when it returns.

From the documentation :

Remember that the system calls this method every time your activity comes to the fore, including when you create it for the first time. Therefore, you must implement onResume () to initialize the components that you publish during onPause (), and perform any other initializations that should occur each time the action enters the resume state (for example, start animating and initialize the components used only during user action focus).

Also note that setContentView() may already have returned. This should not last long, even with a MapView . The map probably loads asynchronously, so it does not bind the UI thread.

+5
source

All Articles