【问题标题】:Why the method onResume is going to be executed twice if the app is still running the onCreate method?如果应用程序仍在运行 onCreate 方法,为什么 onResume 方法会被执行两次?
【发布时间】:2013-02-14 21:31:30
【问题描述】:

我正在开发一个 Android 应用程序,并且在其中一个活动中我使用 MapsActivity 来显示地图。 我所看到的是,在 2.2 (API8) 模拟器上加载地图需要一些时间,我有时间按下菜单按钮然后返回应用程序,它仍在 setContentView() 上加载,问题当它进入将被调用两次的 onResume() 时。

根据Android活动的生命周期,如果应用再次进入前台,将调用onPause()->[onRestart()-->onStart()]-->onResume(),并且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 完成的 cmets,这部分只是为了澄清我是否错了。

也许地图的例子很糟糕,因为地图的异步加载。 我将 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));
}
}

如果我在日志仍在打印“Sleeping...”时最小化应用程序并快速重新运行应用程序,我可以看到“Sleeping...”,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):showingToast
  • 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):showingToast

Toast 将显示两次消息。

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

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

请按照和我一样的方式执行代码,我很固执不放弃:P

【问题讨论】:

  • 有一个线程执行onCreate,然后执行onResume。在 onCreate 返回之前,无法调用 onResume。如果您将一堆事件排队,它们将在 onCreate 退出时按顺序发生。 Android 完全按照您的要求做:每次启动时都会弹出一个对话框。你启动了两次。而且,顺便说一句,8 秒方式足以导致 ANR...
  • 好的,我明白了,谢谢大家。

标签: android google-maps android-emulator


【解决方案1】:

这是设计使然。如果您将活动发送到后台,它必须在返回时调用onResume()

来自the documentation

请注意,每次您的活动进入前台时系统都会调用此方法,包括首次创建活动时。因此,您应该实现 onResume() 来初始化您在 onPause() 期间释放的组件,并执行每次活动进入 Resumed 状态时必须发生的任何其他初始化(例如开始动画和初始化仅在活动有用户时使用的组件焦点)。

另请注意,setContentView() 可能已经返回。即使是MapView,也不应该花很长时间。地图可能是异步加载的,因此不会占用 UI 线程。

【讨论】:

  • 嗨@Geobits 是的,您说的一切都是正确的但是如果您按照我提到的步骤进行操作,您会看到双重呼叫。如果您在 setContentView 设置断点并且您的活动进入前台,系统应该检测到它,并且在恢复执行后应该调用一次 onResume。没有调试我发生了。我的笔记本电脑需要将近 15 秒的时间来传递 setContentView 地图,有足够的时间最小化并重新运行应用程序,然后突然出现一个值为 2 的对话框。
  • @AlexBcn:Geobits 完全正确。你似乎认为是因为视图的内容还没有完全显示出来,所以 setContentView 没有返回。那不是真的!如果它以这种方式工作,那么每次加载地图时都会收到 ANR。您的应用已正确暂停和恢复。地图加载是异步发生的,您的应用仍在 onCreate 中。
  • 嗨@G。 Blake Meike,我在问题中添加了一些文字,请查看。谢谢。
  • 试图在整个生命周期内与 Android 抗衡,每次都会导致失败。如果您必须设置状态标志以确保正常流动,请执行此操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-28
  • 2013-06-07
  • 1970-01-01
  • 2020-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多