22

У меня есть MainActivity и внутри него я загружаю фрагмент A. Из FragmentA я вызываю активность google placepicker, используя startActivityforResult следующим образом.Android parentActivity не воссоздается после startActivityForResult возвращает

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

Но когда я выбираю место, onActivityResult (либо в Fragmenta или MainActivity) не вызывался. Фактически, мое приложение уничтожается после вызова startActivityForResult.

В соответствии с моим пониманием, андроид должен воссоздать вызывающую деятельность, если она недоступна в памяти. Но этого не происходит. Даже в режиме CreateCreate не вызывается внутри MainActivity.

Может ли кто-нибудь сказать мне причину такого поведения или я ничего не пропустил?

Теперь вместо работы PlacePicker я попытался использовать другое действие в том же приложении.

Скажем, у меня есть MainActivity с FragmentA loaded.I звоню SubActivity с startActivityForResult из FragmentA .Теперь, возвращаясь из SubActivity, выхода из приложения. Я включил Dont keep activities на моем устройстве для проверки этого конкретного сценария. Я вижу, что MainActivity уничтожается, когда я переезжаю на SubActivity. Но при возврате с SubActivity андроид не воссоздает MainActivity (даже onCreate не получает вызов. Приложение просто выходит).

+0

* «Мое приложение уничтожается после вызова startActivityForResult.» * Вы имеете в виду, что он сбой? – codeMagic

+0

Вы предоставили фильтр намерений в файле манифеста? Это необходимо, чтобы ваша деятельность могла быть воссоздана. – Mann

+0

@codeMagic. Это не сбой. После вызова startActivityForResult я могу увидеть метод onDestory в вызове MainActivity. И когда я выбираю место из запущенного действия, он возвращается. Но мое приложение не воссоздает , если я выберем место достаточно быстро (до того, как моя MainActivity) будет уничтожено), onActivityResult будет вызван правильно. – Renjith

ответ

7

Для Android совершенно очевидно, что вы очищаете активность так, как вы описали, но если это так, то ваша деятельность должна быть восстановлена. Android не должен уничтожать активность, если вы специально не назовете finish() или что-то заставляет деятельность досрочно закончиться.

Если вы обратитесь к жизненному циклу активности диаграммы:

В сценарии вы описали первое действие должно вызвать OnStop, но не OnDestroy, а затем, когда вы вернетесь из второй активности он должен вызвать OnStart еще раз.

Я создал очень простое приложение для тестирования сценария вы описали, в котором содержится следующее:

  • Есть 2 мероприятия, FirstActivity и SecondActivity
  • FirstActivity есть кнопка, когда нажата кнопка ее начинается SecondActivity с startActivityForResult()
  • активность жизненного цикла события регистрируются с помощью ActivityLifecycleCallbacks в классе пользовательских приложений
  • в FirstActivity onActivityResult дополнительно выводит на л ог, когда она вызывается

Вот что выводится:

приложение запускается (FirstActivity создан и запущен и виден):

FirstActivity onCreate 
FirstActivity onStart 
FirstActivity onResume 

я нажимаю кнопку, чтобы начать SecondActivity:

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

Примечание: onDestroy не вызывается.

Теперь я нажимаю кнопку назад и вернуться к первому виду деятельности:

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

Кнопка возврата вызывает finish на SecondActivity поэтому он уничтожил

Теперь, если нажать снова FirstActivity также будет закончена, вызывая onDestroy.

FirstActivity onPause 
FirstActivity onStop 
FirstActivity onDestroy 

Вы можете видеть, что этот пример точно соответствует схеме жизненного цикла. Действия уничтожаются только после нажатия кнопки «Назад», что заставляет операцию вызывать finish().

Вы упомянули, что вы пытались включить «Не выполнять действия» в настройках разработчика, мы можем повторить вышеупомянутый эксперимент, который включил эту опцию, и посмотреть, что произойдет. Я только добавил соответствующие события жизненного цикла, чтобы сохранить повторять все, что выше:

После нажатия кнопки в первой активности, чтобы начать вторую активность:

... 
SecondActivity onResume 
FirstActivity onSaveInstanceState 
FirstActivity onStop 
FirstActivity onDestroy 

Как и ожидалось, активность была уничтожена эта время. Это то, что происходит, когда вы переходите к первой активности снова:

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

На этот раз OnCreate был вызван снова, так как система не имеет остановленный версию первого действия для перезапуска. Также был вызван onActivityResult(), независимо от того, что деятельность должна была быть воссоздана.

Это также подтверждает, что что-то в вашем первом действии должно быть вызвано finish() или причиной его сбоя. Однако, не видя своего фактического кода, это гипотеза.

Наконец, чтобы поддерживать состояние, если ваша деятельность действительно по какой-то причине нужно получить заново, вы можете переопределить onSaveInstanceState() и добавить любую информацию о состоянии в пачке:

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

Когда активность воссоздан, вы будете получить пучок обратно в OnCreate, который должен содержать все, что вы спасены:

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

Я точно тестирую один и тот же случай воссоздания активности (см. Мое редактирование). Проблема даже в том, что метод onCreate не вызывается при возврате. – Renjith

+2

Почему это принятый ответ? Он не отвечает на вопрос imo. –

+0

Как насчет того, когда onDestroy вызывается в вызывающей активности ??? –

18

Это может произойти из-за многих причин, но мы надеемся, что это редкое явление. ОС будет уничтожать Activity, если это необходимо, для восстановления ресурсов, что, скорее всего, произойдет на устройствах с меньшей памятью и вычислительной мощностью.

Использование параметра Do not keep Activities - хороший способ протестировать этот сценарий, и в этом случае возникают другие проблемы, даже если активность/фрагмент действительно воссоздаются. Если этот параметр включен, активность и фрагмент будут уничтожены, когда будет показан PlacePicker, а затем, когда появится onActivityResult(), нет действительного контекста, потому что активность и фрагмент все еще находятся в процессе создания.

Я узнал об этом, выполняя контролируемое испытание с отключенной установкой, а затем с включенным параметром, а затем, глядя на результатах

я положить лесосечные в каждом жизненном цикл обратного вызова для деятельности и фрагмент в порядке чтобы получить представление о том, что происходит во время этих вызовов.

Вот полный класс я использовал, что включает в себя как активность и фрагмент:

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))); 

     } 
    } 
} 

Вот результирующие журналы, которые дают понимание того, что обратные вызовы жизненного цикла называются в процессе при нормальных условиях:

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() призваны как активность и фрагмент.

Вот результат визуально:

PlacePicker

Затем после выбора места:

place shown on map

Затем я включил Do not keep Activities в разделе Параметры разработчика в настройках, и запускал тот же самый тест ,

Эти результирующие журналы:

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 

Таким образом, вы можете увидеть, как активность и Fragment разрушаются, когда PlacePicker показано, и после того, как место выбрали в PlacePicker, выполнение кода никогда не к записи журнала Fragment processActivityResult, и приложение никогда не показывало выбранное место на карте.

То есть из-за нулевой проверки Context:

if (getActivity() == null) return; 

Log.d("PlacePickerTest", "Fragment processActivityResult"); 

//process Intent...... 
Place place = PlacePicker.getPlace(data, getActivity()); 

Таким образом, призыв к onActivityResult() приходит в, но делает это в то же самое время, что активность и фрагмент становятся воссозданной, и вам нужен действительный контекст для совершения звонка PlacePicker.getPlace(data, getActivity());.

Хорошей новостью является то, что большинство конечных пользователей не включили параметр Do not keep Activities, и большую часть времени ваша деятельность не будет уничтожена ОС.

+0

Это может произойти, если ОС удаляет действие, вызывающее startActivityForResult. –

+0

@JawadLeWywadi Вы правы, читая это снова, я понял, что у этого ответа были некоторые проблемы. Просто отредактированный, я думаю, теперь это лучше. Благодаря! –

+0

Это должен быть правильный ответ, особенно для подсказки к настройкам «Не держите деятельность в живых» .... – Opiatefuchs

Смежные вопросы