在startActivityForResult返回之后,Android parentActivity不会被重新创build

我有一个MainActivity,在里面,我加载一个片段A.从FragmentA,我打电话谷歌placepicker活动使用startActivityforResult如下。

PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder(); Intent intent = builder.build(getActivity()); getActivity().startActivityForResult(intent,PLACE_PICKER_REQUEST); 

但是当我select的地方,onActivityResult(无论是在FragmentA或MainActivity)没有得到调用。 实际上,我的应用程序在startActivityForResult调用之后被破坏。

根据我的理解,android应该重新创build调用活动,如果它不是在内存中可用,但它不会发生。即使onCreate没有被调用内MainActivity。

谁能告诉我这种行为背后的原因还是我错过了什么?

现在,而不是PlacePicker活动,我已经尝试在同一个应用程序中使用另一个活动。

比方说我有MainActivity FragmentA loaded.I从FragmentA调用SubActivitystartActivityForResult 。现在,从SubActivity返回时,应用程序退出。 我已经启用Dont keep activities在我的设备Dont keep activities来testing这个特定的情况。 当我移动到SubActivity时,我可以看到MainActivity被破坏。但从SubActivity返回时,android并没有重新创buildMainActivity (即使onCreate没有被调用,应用程序刚刚退出)。

Solutions Collecting From Web of "在startActivityForResult返回之后,Android parentActivity不会被重新创build"

Android以您描述的方式清理活动似乎非常不寻常,但是如果是这样的话,您的活动仍应该恢复。 Android不应该破坏活动,除非你专门调用finish()或者什么东西导致活动提前结束。

如果您参考了活动生命周期图:

在你描述的场景中,第一个活动应该调用onStop,而不是onDestroy,然后当你从第二个活动返回时,它应该再次调用onStart。

我创build了一个非常简单的应用程序来testing您描述的情况,其中包含以下内容:

  • 有2个活动,FirstActivity和SecondActivity
  • FirstActivity有一个button,当button被点击时,它启动SecondActivity与startActivityForResult()
  • 活动生命周期事件使用自定义应用程序类中的ActivityLifecycleCallbacks进行logging
  • 在FirstActivity中, onActivityResult会在调用日志时输出到日志中

这是什么输出:

应用程序已启动(FirstActivity已创build并启动并可见):

 FirstActivity onCreate FirstActivity onStart FirstActivity onResume 

我按下button启动SecondActivity:

 FirstActivity onPause SecondActivity onCreate SecondActivity onStart SecondActivity onResume FirstActivity onSaveInstanceState FirstActivity onStop 

请注意,onDestroy不会被调用。

现在我按下后退button并返回到第一个活动:

 SecondActivity onPause FirstActivity onStart FirstActivity onActivityResult FirstActivity onResume SecondActivity onStop SecondActivity onDestroy 

后退button在SecondActivity上调用finish ,因此被销毁

现在,如果我再次按回FirstActivity也将完成,导致onDestroy被调用。

 FirstActivity onPause FirstActivity onStop FirstActivity onDestroy 

你可以看到这个例子完全遵循了生命周期图。 只有按下后退button才会销毁活动,这会导致活动调用finish()

您提到您尝试在开发人员选项中打开“不要保留活动”,我们可以重复上述启用此选项的实验,看看会发生什么。 我刚刚添加了相关的生命周期事件来保存重复以上的所有内容:

在第一个活动中按下button以启动第二个活动:

 ... SecondActivity onResume FirstActivity onSaveInstanceState FirstActivity onStop FirstActivity onDestroy 

不出所料,这次活动已经被摧毁了。 当您再次导航回到第一个活动时,会发生这种情况:

 SecondActivity onPause FirstActivity onCreate FirstActivity onStart FirstActivity onActivityResult FirstActivity onResume ... 

这次onCreate再次被调用,因为系统没有重新启动的第一个活动的停止版本。 另外onActivityResult()仍然被调用,不pipe事件是否必须被重新创build。

这进一步支持你的第一个活动中的东西必须调用finish()或导致它崩溃。 但是,没有看到你的实际代码,这是猜测。

最后,如果您的活动由于某种原因需要重新创build而维护状态,则可以覆盖onSaveInstanceState()并将任何状态信息添加到该包中:

 protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString(MY_STRING_KEY, "my string value"); } 

当活动被重新创build时,你会在onCreate中得到一个包含你保存的所有东西的包:

 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... if (savedInstanceState != null) { // Restore previous state } } 

这可能由于许多原因而发生,但是希望这是罕见的事情。 如果需要回收资源,操作系统会在后台运行时破坏活动,这种情况很可能发生在内存和处理能力较低的设备上。

使用Do not keep Activities设置是testing此场景的好方法,在这种情况下,即使“活动/片段”重新创build也存在其他问题。 启用此设置后,当显示PlacePicker时Activity和Fragment会被破坏,然后当onActivityResult()进入时,由于Activity和Fragment仍然处于重新创build的过程中,因此没有有效的Context。

我通过禁用设置进行受控testing,然后启用设置,然后查看结果,发现了这一点

我把活动和片段的每个生命周期callback中的日志logging,以便了解这些调用过程中发生了什么。

以下是我使用的完整课程,包括活动和片段:

 public class MainActivity extends AppCompatActivity { MyFragment myFrag; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d("PlacePickerTest", "Activity onCreate"); myFrag = new MyFragment(); setContentView(R.layout.activity_main); if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() .add(R.id.container, myFrag) .commit(); } } @Override protected void onResume() { super.onResume(); Log.d("PlacePickerTest", "Activity onResume"); } @Override protected void onPause() { super.onPause(); Log.d("PlacePickerTest", "Activity onPause"); } @Override protected void onDestroy() { Log.d("PlacePickerTest", "Activity onDestroy"); super.onDestroy(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public void onActivityResult (int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Log.d("PlacePickerTest", "Activity onActivityResult requestCode:" + requestCode); if (requestCode == 199){ //process result of PlacePicker in the Fragment myFrag.processActivityResult(data); } } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { //open PlacePicker from menu item myFrag.startPlacePicker(); return true; } return super.onOptionsItemSelected(item); } /** * Fragment containing a map and PlacePicker functionality */ public static class MyFragment extends Fragment { private GoogleMap mMap; Marker marker; public MyFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container, false); Log.d("PlacePickerTest", "Fragment onCreateView"); return rootView; } @Override public void onResume() { super.onResume(); Log.d("PlacePickerTest", "Fragment onResume"); setUpMapIfNeeded(); } @Override public void onPause() { super.onPause(); Log.d("PlacePickerTest", "Fragment onPause"); } @Override public void onDestroy() { Log.d("PlacePickerTest", "Fragment onDestroy"); super.onDestroy(); } private void setUpMapIfNeeded() { // Do a null check to confirm that we have not already instantiated the map. if (mMap == null) { // Try to obtain the map from the SupportMapFragment. mMap = ((SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map)) .getMap(); // Check if we were successful in obtaining the map. if (mMap != null) { setUpMap(); } } } private void setUpMap() { // Enable MyLocation Layer of Google Map mMap.setMyLocationEnabled(true); mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID); mMap.getUiSettings().setZoomControlsEnabled(true); mMap.getUiSettings().setMyLocationButtonEnabled(true); mMap.getUiSettings().setCompassEnabled(true); mMap.getUiSettings().setRotateGesturesEnabled(true); mMap.getUiSettings().setZoomGesturesEnabled(true); } public void startPlacePicker(){ int PLACE_PICKER_REQUEST = 199; PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder(); //Context context = getActivity(); try { Log.d("PlacePickerTest", "Fragment startActivityForResult"); getActivity().startActivityForResult(builder.build(getActivity()), PLACE_PICKER_REQUEST); } catch (GooglePlayServicesRepairableException e) { e.printStackTrace(); } catch (GooglePlayServicesNotAvailableException e) { e.printStackTrace(); } } public void processActivityResult ( Intent data) { if (getActivity() == null) return; Log.d("PlacePickerTest", "Fragment processActivityResult"); //process Intent...... Place place = PlacePicker.getPlace(data, getActivity()); String placeName = String.format("Place: %s", place.getName()); String placeAddress = String.format("Address: %s", place.getAddress()); LatLng toLatLng = place.getLatLng(); // Show the place location in Google Map mMap.moveCamera(CameraUpdateFactory.newLatLng(toLatLng)); mMap.animateCamera(CameraUpdateFactory.zoomTo(15)); if (marker != null) { marker.remove(); } marker = mMap.addMarker(new MarkerOptions().position(toLatLng) .title(placeName).snippet(placeAddress) .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA))); } } } 

以下是生成的日志,可以深入了解在正常情况下在此过程中调用的生命周期callback:

  D/PlacePickerTest﹕ Activity onCreate D/PlacePickerTest﹕ Fragment onCreateView D/PlacePickerTest﹕ Activity onResume D/PlacePickerTest﹕ Fragment onResume D/PlacePickerTest﹕ Fragment startActivityForResult D/PlacePickerTest﹕ Fragment onPause D/PlacePickerTest﹕ Activity onPause D/PlacePickerTest﹕ Activity onActivityResult requestCode:199 D/PlacePickerTest﹕ Fragment processActivityResult D/PlacePickerTest﹕ Activity onResume D/PlacePickerTest﹕ Fragment onResume 

所以,你可以看到onDestroy()永远不会被调用, onPause()onResume()同时在Activity和Fragment上被调用。

这是视觉效果:

PlacePicker

然后挑选一个地方:

地图上显示的地方

然后,我在“设置”中启用了“ Do not keep Activities在开发者选项下Do not keep Activities ”,并运行相同的testing。

这些是生成的日志:

  D/PlacePickerTest﹕ Activity onCreate D/PlacePickerTest﹕ Fragment onCreateView D/PlacePickerTest﹕ Activity onResume D/PlacePickerTest﹕ Fragment onResume D/PlacePickerTest﹕ Fragment startActivityForResult D/PlacePickerTest﹕ Fragment onPause D/PlacePickerTest﹕ Activity onPause D/PlacePickerTest﹕ Activity onDestroy D/PlacePickerTest﹕ Fragment onDestroy D/PlacePickerTest﹕ Activity onCreate D/PlacePickerTest﹕ Fragment onCreateView D/PlacePickerTest﹕ Activity onActivityResult requestCode:199 D/PlacePickerTest﹕ Activity onResume D/PlacePickerTest﹕ Fragment onResume 

所以,当PlacePicker被显示时,你可以看到Activity和Fragment都被销毁了,在PlacePicker中select了这个地方之后,代码执行永远不会到达Fragment processActivityResult日志条目,并且应用程序从来没有显示地图。

那是因为空的上下文检查:

  if (getActivity() == null) return; Log.d("PlacePickerTest", "Fragment processActivityResult"); //process Intent...... Place place = PlacePicker.getPlace(data, getActivity()); 

所以对onActivityResult()的调用确实进入了,但是它同时又重新创build了Activity和Fragment,并且需要一个有效的Context来调用PlacePicker.getPlace(data, getActivity());

好消息是,大多数最终用户不会启用Do not keep Activities设置,并且大部分时间您的活动不会被操作系统破坏。