如果应用程序仍在运行onCreate方法,为什么方法onResume会被执行两次?

7
我正在开发一个Android应用程序,在其中一个活动中,我使用MapsActivity来显示地图。 我发现在2.2(API8)模拟器上加载地图需要一些时间,我有时间按菜单按钮然后回到应用程序,它仍在setContentView()上加载,当进入onResume()时就会出问题,这将被调用两次。
根据Android活动的生命周期,在一个onPause()->[onRestart()-->onStart()]-->再次进入前台时,将调用onResume(),并且在启动时会调用onCreate()->[onStart()]。
但为什么在onCreate()的setContentView上仍在加载时不只调用一次?
这是一件让我感兴趣的事情,因为我不想每次使用地图时都使用布尔值,认为它可能会执行两次以避免问题,即计数器的双重递增。
我不知道这是否是模拟器的问题,就像我看到的关于横向 - 纵向方向http://code.google.com/p/android/issues/detail?id=2423的问题。
请看这个:
  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>

您可以重新创建该问题:

  1. 在setContentView处设置断点,另一个在super.OnResume()处设置断点。
  2. 执行并打开调试视图。
  3. 将应用程序发送到后台并再次运行它。
  4. 完成执行,您应该看到一个显示值为2的对话框。


请阅读Geobits和G. Blake Meike的评论,这部分是为了澄清我是否错误地理解了问题。
也许用地图的例子不太合适,因为地图的异步加载。我将MapsActivity更改为Activity,假设手机负载过重,因此onCreate将执行8秒的循环(不足以导致Android无响应)。
以下是使用轻量级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));
}
}

如果我在日志仍在打印“睡眠…”时最小化应用程序,并快速重新运行应用程序,我可以看到“睡眠…”,onResume将检查两次连接性(这是检查网络连接的正确方式)。
以下是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): 睡眠中...
  • 02-28 20:02:49.655: W/LocationActivity(651): 睡眠中...
  • 02-28 20:02:50.678: W/LocationActivity(651): 睡眠中...
  • 02-28 20:02:51.673: W/LocationActivity(651): 睡眠中...
  • 02-28 20:02:52.674: W/LocationActivity(651): 睡眠中...
  • 02-28 20:02:53.738: W/LocationActivity(651): 睡眠中...
  • 02-28 20:02:54.773: W/LocationActivity(651): 睡眠中...
  • 02-28 20:02:55.795: W/LocationActivity(651): 睡眠中...
  • 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): 检查移动连接性
  • 02-28 20:02:57.134: W/LocationActivity(651): 显示提示信息
  • 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): 检查移动连接性
  • 02-28 20:02:57.324: W/LocationActivity(651): 显示提示信息

Toast将显示两次消息。

查看logCat,生命周期是正确的,但我想考虑到有时由于系统负载过重而延迟了onCreate,如果onResume执行两次,那么我必须注意一些初始化,所以我不得不使用布尔值,我认为我不应该使用,因为onCreate仍在运行。

如果不是Toast而是对话框,则从用户的角度来看,不欢迎两个对话框。

请像我一样执行代码,我够固执,不会放弃: P


有一个单独的线程执行onCreate,然后执行onResume。在onCreate返回之前,不能调用onResume。如果您排队一堆事件,它们会在onCreate退出时按顺序发生。Android确切地执行了您告诉它要做的事情:每次启动时弹出对话框。您启动了它两次。另外,8秒钟足以引起ANR(应用程序无响应)。 - G. Blake Meike
好的,现在我明白了,谢谢大家。 - AlexBcn
1个回答

5
这是有意设计的。如果您将活动发送到后台,则在返回时必须调用onResume()方法。
根据文档
请注意,系统每次将您的活动带回前台时都会调用此方法,包括第一次创建时。因此,您应该实现onResume()来初始化在onPause()期间释放的组件,并执行任何其他必须在每次活动进入已恢复状态时发生的初始化(例如开始动画和仅在活动具有用户焦点时使用的组件)。
同时,请注意,setContentView()可能已经返回。即使对于MapView,它也不应该花费太长时间。地图可能在异步加载,因此不会占用UI线程。

嗨@Geobits,你说的一切都是对的。但如果你按照我提到的步骤操作,你会看到双重调用。如果你在setContentView处设置断点,当你的活动进入前台时,系统应该检测到它,并在恢复执行后调用onResume一次。没有调试的情况下也会发生这种情况。我的笔记本电脑需要将地图传递给setContentView花费近15秒的时间,足够时间让我最小化并重新运行应用程序,然后突然弹出一个值为2的对话框。 - AlexBcn
@AlexBcn:Geobits说得完全正确。你似乎认为因为视图的内容没有完全显示,setContentView就没有返回。这是不正确的!如果它是这样工作的,每次加载地图时都会出现ANR。你的应用程序已经正确地暂停和恢复了。地图加载是异步发生的,你的应用程序仍然在onCreate中。 - G. Blake Meike
嗨,@G. Blake Meike,我已经添加了一些文字到问题中,请您查看一下。谢谢。 - AlexBcn
试图与 Android 生命周期对抗每次都会失败。如果您必须设置状态标志以确保正确的流程,请这样做。 - Geobits

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接