OnActivityResult не вызывается в фрагменте

При работе с этим фрагментом onActivityResult когда возвращается активность камеры.

Мой фрагмент запускает действие для результата с намерением, отправленным для камеры, сделать снимок. Приложение изображения загружается отлично, принимает снимок и возвращается. Однако onActivityResult никогда не попадает. Я установил точки останова, но ничего не запускается. Может ли фрагмент иметь onActivityResult ? Я бы так подумал, так как это предоставленная функция. Почему это не срабатывает?

 ImageView myImage = (ImageView)inflatedView.findViewById(R.id.image); myImage.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(cameraIntent, 1888); } }); @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if( requestCode == 1888 ) { Bitmap photo = (Bitmap) data.getExtras().get("data"); ((ImageView)inflatedView.findViewById(R.id.image)).setImageBitmap(photo); } } 

Solutions Collecting From Web of "OnActivityResult не вызывается в фрагменте"

Хостинг onActivityResult , но он не вызывал super.onActivityResult для необработанных кодов результатов. По-видимому, хотя фрагмент является тем, который делает вызов startActivityForResult , действие получает первый снимок при обработке результата. Это имеет смысл, если вы рассматриваете модульность фрагментов. Как только я выполнил super.onActivityResult для всех необработанных результатов, фрагмент получил шанс обработать результат.

А также от @siqing ответ:

Чтобы получить результат в вашем фрагменте, убедитесь, что вы вызываете startActivityForResult(intent,111); Вместо getActivity().startActivityForResult(intent,111); Внутри вашего фрагмента.

Я думаю, вы вызвали getActivity().startActivityForResult(intent,111); , Вы должны вызвать startActivityForResult(intent,111); ,

Опция 1:

Если вы вызываете startActivityForResult() из фрагмента, тогда вы должны вызвать startActivityForResult() , а не getActivity().startActivityForResult() , так как это приведет к фрагменту onActivityResult ().

Если вы не знаете, где вы вызываете startActivityForResult() и как вы будете вызывать методы.

Вариант 2:

Поскольку Activity получает результат onActivityResult() , вам необходимо переопределить активность onActivityResult() и вызвать super.onActivityResult() для распространения на соответствующий фрагмент для необработанных кодов результатов или для всех.

Если выше два параметра не работают, обратитесь к опции 3, так как это определенно будет работать.

Вариант 3:

Явный вызов из фрагмента функции onActivityResult выглядит следующим образом.

В родительском классе Activity переопределите метод onActivityResult () и даже переопределите его в классе Fragment и вызовите в качестве следующего кода.

В родительском классе:

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.dualPane); fragment.onActivityResult(requestCode, resultCode, data); } 

В дочернем классе:

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // In fragment class callback } 

У меня такая же проблема с ChildFragmentManager . Менеджер не передаст результат во вложенный фрагмент, вы должны сделать это вручную в своем базовом фрагменте.

 public void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); Fragment fragment = (Fragment) getChildFragmentManager().findFragmentByTag(childTag); if (fragment != null) { fragment.onActivityResult(requestCode, resultCode, intent); } } 

Если вы не знаете фрагментов в своей деятельности, просто перечислите их все и отправьте аргументы результата деятельности:

 // In your activity @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); for (Fragment fragment : getSupportFragmentManager().getFragments()) { fragment.onActivityResult(requestCode, resultCode, data); } } 

Оригинальный пост.

FragmentActivity заменяет requestCode измененным. После этого, когда onActivityResult() , FragmentActivity анализирует более высокие 16 бит и восстанавливает индекс исходного фрагмента. Посмотрите на эту схему:

Введите описание изображения здесь

Если у вас есть несколько фрагментов на корневом уровне, проблем нет. Но если у вас есть вложенные фрагменты , например Fragment с несколькими вкладками внутри ViewPager , вы гарантированно столкнетесь с проблемой (или уже столкнулись с ней).

Потому что только один индекс хранится внутри requestCode . Это индекс Fragment внутри его FragmentManager . Когда мы используем вложенные фрагменты, есть дочерние FragmentManager s, которые имеют свой собственный список фрагментов. Таким образом, необходимо сохранить целую цепочку индексов, начиная с root FragmentManager .

Введите описание изображения здесь

Как решить эту проблему? В этом посте есть общее решение.

GitHub: https://github.com/shamanland/nested-fragment-issue

Это одна из самых популярных проблем. Мы можем найти много сообщений об этой проблеме. Но ни один из них не полезен для меня.

Поэтому я решил эту проблему с помощью этого решения.

Давайте сначала поймем, почему это происходит.

Мы можем вызвать startActivityForResult непосредственно из Фрагмента, но на самом деле механика позади обрабатываются Activity.

После того, как вы вызове startActivityForResult из фрагмента, requestCode будет изменен, чтобы привязать идентификатор Fragment к коду. Это позволит Activity отслеживать, кто отправляет этот запрос после получения результата.

После того, как активность была перенесена обратно, результат будет отправлен в Activity atActivityResult Activity с измененным кодом запроса, который будет декодирован в исходный идентификатор requestCode + Fragment. После этого Activity отправит результат активности на этот фрагмент через onActivityResult. И все это сделано.

Проблема в:

Активность может отправить результат только фрагменту, который был прикреплен непосредственно к Activity, но не к вложенному. Вот почему onActivityResult вложенного фрагмента никогда не вызывался ни на что.

Решение:

1) Начните Намерение в своем фрагменте по нижнему коду:

  /** Pass your fragment reference **/ frag.startActivityForResult(intent, REQUEST_CODE); // REQUEST_CODE = 12345 

2) Теперь в вашей родительской активности переопределите ** onActivityResult() : **

  @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); } 

Вы должны вызвать это в родительской деятельности, чтобы заставить его работать.

3) При вызове фрагмента:

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == Activity.RESULT_OK) { } } 

Вот и все. С помощью этого решения он может применяться для любого отдельного фрагмента, является ли он вложенным или нет. И да, это также охватывает весь случай! Кроме того, коды также хороши и чисты.

ДЛЯ МНОГООБРАЗОВАННЫХ ФРАГМЕНТОВ (например, при использовании ViewPager в фрагменте)

В вашей основной деятельности :

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); } 

В вашем фрагменте:

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { for (Fragment fragment : getChildFragmentManager().getFragments()) { fragment.onActivityResult(requestCode, resultCode, data); } } 

В вашем вложенном фрагменте

Активность вызова

 getParentFragment().startActivityForResult(intent, uniqueInstanceInt); 

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

Получать ответ

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == uniqueInstanceInt ) { // TODO your code } } 

Внимание

Числовое число от 0 до 65536 должно использоваться в uniqueInstanceInt для исключения ошибки: «Может использовать только младшие 16 бит для requestCode».

Я могу добавить два совета, если кто-то еще не сможет это сделать. В файле Manifest.xml убедитесь, что активность хостинга не завершилась при обратном вызове, и для запуска активности в качестве стандартного режима запуска. Подробнее см. Ниже:

Для активности хостинга установите для свойства history значение false, если

 android:noHistory="false" 

Чтобы начать работу, установите режим запуска в качестве стандартного, если

 android:launchMode="standard" 

Я также встретил эту проблему во Фрагменте. И я вызвал startActivityForResult в DialogFragment .

Но теперь эта проблема решена:
FragmentClassname.this.startActivityForResult .

Решение 1:

Вызов startActivityForResult(intent, REQUEST_CODE); Вместо getActivity().startActivityForResult(intent, REQUEST_CODE); ,

Решение 2:

Когда startActivityForResult(intent, REQUEST_CODE); Называется активностью onActivityResult(requestCode,resultcode,intent) , и вы можете вызывать здесь fragments onActivityResult() , передавая requestCode, resultCode and intent .

Внутри фрагмента вызовите

 this.startActivityForResult(intent, REQUEST_CODE); 

Где this относится к фрагменту. В противном случае, как @Clevester сказал:

 Fragment fragment = this; .... fragment.startActivityForResult(intent, REQUEST_CODE); 

Мне также пришлось позвонить

 super.onActivityResult(requestCode, resultCode, data); 

В родительской активности onActivityResult чтобы заставить его работать.

(Я адаптировал этот ответ из ответа @ Clevester).

Вкратце,

В фрагменте объявите Fragment fragment = this ;

После этого используйте fragment.startActivityForResult .

Результат будет возвращен в activityResult.

 public class takeimage extends Fragment { private Uri mImageCaptureUri; private static final int PICK_FROM_CAMERA = 1; private static final int PICK_FROM_FILE = 2; private String mPath; private ImageView mImageView; Bitmap bitmap = null; View view; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { view = inflater.inflate(R.layout.activity_send_image, container, false); final String[] items = new String[] { "From Camera", "From SD Card" }; mImageView = (ImageView)view.findViewById(R.id.iv_pic); ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.select_dialog_item, items); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setTitle("Select Image"); builder.setAdapter(adapter, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { if (item == 0) { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File file = new File(Environment.getExternalStorageDirectory(), "tmp_avatar_" + String.valueOf(System.currentTimeMillis()) + ".jpg"); mImageCaptureUri = Uri.fromFile(file); try { intent.putExtra( android.provider.MediaStore.EXTRA_OUTPUT, mImageCaptureUri); intent.putExtra("return-data", true); getActivity().startActivityForResult(intent, PICK_FROM_CAMERA); } catch (Exception e) { e.printStackTrace(); } dialog.cancel(); } else { Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); getActivity().startActivityForResult( Intent.createChooser(intent, "Complete action using"), PICK_FROM_FILE); } } }); final AlertDialog dialog = builder.create(); Button show = (Button) view.findViewById(R.id.btn_choose); show.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // Switch the tab content to display the list view. dialog.show(); } }); return view; } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode != Activity.RESULT_OK) return; if (requestCode == PICK_FROM_FILE) { mImageCaptureUri = data.getData(); // mPath = getRealPathFromURI(mImageCaptureUri); //from Gallery if (mPath == null) mPath = mImageCaptureUri.getPath(); // from File Manager if (mPath != null) bitmap = BitmapFactory.decodeFile(mPath); } else { mPath = mImageCaptureUri.getPath(); bitmap = BitmapFactory.decodeFile(mPath); } mImageView.setImageBitmap(bitmap); } public String getRealPathFromURI(Uri contentUri) { String [] proj = {MediaStore.Images.Media.DATA}; Cursor cursor = managedQuery(contentUri, proj, null, null,null); if (cursor == null) return null; int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); return cursor.getString(column_index); } } 
  1. Вы можете просто переопределить BaseActivity onActivityResult на фрагменте baseActivity.startActivityForResult .

  2. В BaseActivity добавьте интерфейс и переопределите onActivityResult.

     private OnBaseActivityResult baseActivityResult; public static final int BASE_RESULT_RCODE = 111; public interface OnBaseActivityResult{ void onBaseActivityResult(int requestCode, int resultCode, Intent data); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(getBaseActivityResult() !=null && requestCode == BASE_RESULT_RCODE){ getBaseActivityResult().onBaseActivityResult(requestCode, resultCode, data); setBaseActivityResult(null); } 
  3. On Fragment реализует OnBaseActivityResult

     @Override public void onBaseActivityResult(int requestCode, int resultCode, Intent data) { Log.d("RQ","OnBaseActivityResult"); if (data != null) { Log.d("RQ","OnBaseActivityResult + Data"); Bundle arguments = data.getExtras(); } } 

Это обходное решение сделает трюк.

Если вышеуказанная проблема возникает при входе в Facebook, вы можете использовать приведенный ниже код в родительской активности вашего фрагмента, например:

 Fragment fragment = getFragmentManager().findFragmentById(android.R.id.tabcontent); fragment.onActivityResult(requestCode, resultCode, data); 

Или:

 Fragment fragment = getFragmentManager().findFragmentById("fragment id here"); fragment.onActivityResult(requestCode, resultCode, data); 

И добавьте следующий вызов в свой фрагмент …

 callbackManager.onActivityResult(requestCode, resultCode, data); 

ДЛЯ НАЗНАЧЕННЫХ ФРАГМЕНТОВ (например, при использовании ViewPager)

В вашей основной деятельности:

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); } 

В вашем основном фрагменте верхнего уровня (фрагмент ViewPager):

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { YourFragment frag = (YourFragment) getChildFragmentManager().getFragments().get(viewPager.getCurrentItem()); frag.yourMethod(data); // Method for callback in YourFragment super.onActivityResult(requestCode, resultCode, data); } 

В YourFragment (вложенный фрагмент):

 public void yourMethod(Intent data){ // Do whatever you want with your data } 

В моем случае это была ошибка Android ( http://technet.weblineindia.com/mobile/onactivityresult-not-getting-called-in-nested-fragments-android/ ), если вы используете поддерживаемый FragmentActivity , вместо этого вы должны использовать getSupportFragmentManager getChildFragmentManager :

 List<Fragment> fragments = getSupportFragmentManager().getFragments(); if (fragments != null) { for (Fragment fragment : fragments) { if(fragment instanceof UserProfileFragment) { fragment.onActivityResult(requestCode, resultCode, data); } } } 

Большинство из этих ответов продолжают говорить, что вам нужно вызвать super.onActivityResult(...) в вашем хосте. Activity для вашего Fragment . Но, похоже, это не работало для меня.

Итак, в вашей Activity хоста вы должны называть свои Fragments onActivityResult(...) . Вот пример.

 public class HostActivity extends Activity { private MyFragment myFragment; protected void onActivityResult(...) { super.onActivityResult(...); this.myFragment.onActivityResult(...); } } 

В какой-то момент вашего HostActivity вам нужно будет присвоить this.myFragment Fragment вы используете. Или используйте FragmentManager чтобы получить Fragment вместо того, чтобы ссылаться на него в HostActivity . Кроме того, проверьте значение null прежде чем пытаться вызвать this.myFragment.onActivityResult(...); ,

Как упоминал Ollie C, в библиотеке поддержки есть активная ошибка с использованием возвращаемых значений onActivityResult, когда вы используете вложенные фрагменты. Я просто ударил его :-(.

См. Fragment.onActivityResult не вызывается, когда requestCode! = 0 .

У меня есть сильное подозрение, что все ответы здесь – не что иное, как хаки. Я пробовал их всех и многих других, но без какого-либо надежного вывода, поскольку всегда есть какая-то глупая проблема. Я не могу полагаться на непоследовательные результаты. Если вы посмотрите официальную документацию по API Android для фрагментов, вы увидите, что Google четко заявляет следующее:

Вызовите startActivityForResult (Intent, int) из связанной с фрагментом Activity.

См. API Android Fragment

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

Ваш код имеет вложенный фрагмент. Вызов super.onActivityForResult не работает

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

Вот одно из многих рабочих решений. Создать фрагмент «на лету» и связать его непосредственно с активностью с помощью менеджера фрагментов поддержки. Затем вызовите startActivityForResult из вновь созданного фрагмента.

 private void get_UserEmail() { if (view == null) { return; } ((TextView) view.findViewById(R.id.tvApplicationUserName)) .setText("Searching device for user accounts..."); final FragmentManager fragManager = getActivity().getSupportFragmentManager(); Fragment f = new Fragment() { @Override public void onAttach(Activity activity) { super.onAttach(activity); startActivityForResult(AccountPicker.newChooseAccountIntent(null, null, new String[]{"com.google"}, false, null, null, null, null), REQUEST_CODE_PICK_ACCOUNT); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_PICK_ACCOUNT) { String mEmail = ""; if (resultCode == Activity.RESULT_OK) { if (data.hasExtra(AccountManager.KEY_ACCOUNT_NAME)) { mEmail = data .getStringExtra(AccountManager.KEY_ACCOUNT_NAME); } } if (mActivity != null) { GoPreferences.putString(mActivity, SettingApplication.USER_EMAIL, mEmail); } doUser(); } super.onActivityResult(requestCode, resultCode, data); fragManager.beginTransaction().remove(this).commit(); } }; FragmentTransaction fragmentTransaction = fragManager .beginTransaction(); fragmentTransaction.add(f, "xx" + REQUEST_CODE_PICK_ACCOUNT); fragmentTransaction.commit(); } что private void get_UserEmail() { if (view == null) { return; } ((TextView) view.findViewById(R.id.tvApplicationUserName)) .setText("Searching device for user accounts..."); final FragmentManager fragManager = getActivity().getSupportFragmentManager(); Fragment f = new Fragment() { @Override public void onAttach(Activity activity) { super.onAttach(activity); startActivityForResult(AccountPicker.newChooseAccountIntent(null, null, new String[]{"com.google"}, false, null, null, null, null), REQUEST_CODE_PICK_ACCOUNT); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_PICK_ACCOUNT) { String mEmail = ""; if (resultCode == Activity.RESULT_OK) { if (data.hasExtra(AccountManager.KEY_ACCOUNT_NAME)) { mEmail = data .getStringExtra(AccountManager.KEY_ACCOUNT_NAME); } } if (mActivity != null) { GoPreferences.putString(mActivity, SettingApplication.USER_EMAIL, mEmail); } doUser(); } super.onActivityResult(requestCode, resultCode, data); fragManager.beginTransaction().remove(this).commit(); } }; FragmentTransaction fragmentTransaction = fragManager .beginTransaction(); fragmentTransaction.add(f, "xx" + REQUEST_CODE_PICK_ACCOUNT); fragmentTransaction.commit(); } 

Моя проблема была с android:launchMode="standard" я нашел его с установленным android:launchMode="standard" Я удалил его временно, и он работает!

Я справился с проблемой, написав базовый класс, который расширяет фрагмент, и в onactivityresult из активности я идентифицировал текущий исполняемый фрагмент с использованием фрагмента фрагмента и назвал определяемый пользователем метод в классе фрагментарной базы. Это приведет к событию в текущем фрагменте.

Один из самых простых способов – начать работу с вашего фрагмента.

 startActivity(ActivityName); 

Затем добавьте вам вызов startActivityForResult(intent,"1"); От вашей деятельности и добавьте onActivityResult в свою деятельность

 startActivityForResult(intent,"1"); @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.dualPane); fragment.onActivityResult(requestCode, resultCode, data); // perform other activity result like fetching from Uris or handling cursors finish(); // finish the activity will get to back to your fragment. } 

Я просто использую метод обхода:

 public static Fragment _tempFragment = null; @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(_tempFragment != null) _tempFragment.onActivityResult(requestCode, resultCode, data); } 

В своем фрагменте, перед startActivityResult, установите

 MainActivity._tempFragment = this; 

После onActivityResult <- in Fragment

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // Do your job { } MainActivity._tempFragment = null; } 

Просто используйте приведенный ниже код для фрагмента.

 @Override public void onOtherButtonClick(ActionSheet actionSheet, int index) { if (index == 1) { Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); intent.setType("image/*"); startActivityForResult(Intent.createChooser(intent, "Select Picture"), 1); } } public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == 1) { if (requestCode == 1) { Uri selectedImageUri = data.getData(); //selectedImagePath = getPath(selectedImageUri); } } } 

OnActivityResult будет вызывать без вызова своего родителя.

В одном случае никто не mention что убедитесь, что режим запуска хост-активности не должен быть установлен на singleInstance или singleTask .

OnActivityResult не будет работать, если ваш режим запуска установлен на SingleInstance или SingleTask. Или вы вызываете свою деятельность с помощью этих IntentFilters

standard или singleTop режим запуска будет работать нормально.

Если существует проблема с методом onActivityResult который находится внутри класса фрагмента, и вы хотите обновить что-то, что находится внутри класса фрагмента, используйте:

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if(resultCode == Activity.RESULT_OK) { // If the user had agreed to enabling Bluetooth, // populate the ListView with all the paired devices. this.arrayDevice = new ArrayAdapter<String>(this.getContext(), R.layout.device_item); for(BluetoothDevice bd : this.btService.btAdapater.getBondedDevices()) { this.arrayDevice.add(bd.getAddress()); this.btDeviceList.setAdapter(this.arrayDevice); } } super.onActivityResult(requestCode, resultCode, data); } 

Просто добавьте this.variable как показано в приведенном выше коде. В противном случае метод будет вызван внутри родительского действия, и переменная не будет обновляться текущего экземпляра.

Я также протестировал его, поставив этот блок кода в MainActivity , заменив HomeFragment классом HomeFragment и имея переменные static. Я получил результаты, как я ожидал.

Поэтому, если вы хотите, чтобы класс фрагмента имел свою собственную реализацию onActivityResult , приведенный выше пример кода является ответом.

Если вы используете вложенные фрагменты, это также работает:

 getParentFragment().startActivityForResult(intent, RequestCode); 

В дополнение к этому вы должны вызвать super.onActivityResult из родительской активности и заполнить метод onActivityResult фрагмента.