onActivityResult не вызывается во фрагменте - PullRequest
797 голосов
/ 27 мая 2011

Активности, в которой размещен этот фрагмент, вызывается 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);
    }
}

Ответы [ 32 ]

1159 голосов
/ 27 мая 2011

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

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

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

313 голосов
/ 13 июня 2012

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

238 голосов
/ 12 июня 2013

Опция 1:

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

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

Вариант 2:

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

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

Вариант 3:

AnЯвный вызов фрагмента функции 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
}
78 голосов
/ 09 мая 2013

У меня такая же проблема с 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);
    }
}
76 голосов
/ 27 марта 2014

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

// 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);
    }
}
57 голосов
/ 19 июня 2014

Исходное сообщение.

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

Enter image description here

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

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

Enter image description here

Как мы решаем эту проблему? Есть общиеОбходное решение в этом посте .

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

41 голосов
/ 01 сентября 2016

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

Итак, я решил эту проблему, используя это решение.

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

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

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

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

Проблема в следующем:

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

Решение:

1) Запустите Intent в своем фрагменте с помощью следующего кода:

       /** 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) {

       }
}

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

18 голосов
/ 22 января 2016

ДЛЯ МНОГИХ ВСТРОЕННЫХ ФРАГМЕНТОВ (например, при использовании 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
    }
}

Внимание

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

14 голосов
/ 30 декабря 2012

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

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

android:noHistory="false"

Для запуска Действия установите стандартный режим запуска, если есть

android:launchMode="standard"
10 голосов
/ 07 февраля 2018

Я также столкнулся с той же проблемой, когда переместил этот блок кода за пределы Фрагмента в Класс утилит , с parentActivity, переданным как аргумент ,

Intent intent = new Intent(parentActivity, CameraCaptureActivity.class);
parentActivity.startActivityForResult(intent,requestCode);

Тогда я не получил никакого значения в onActivityResult методе этого Фрагмента , Впоследствии я изменил аргумент на Фрагмент, поэтому пересмотренное определение метода выглядело так:

Intent intent = new Intent(fragment.getContext(), CameraCaptureActivity.class);
fragment.startActivityForResult(intent,requestCode);

После этого я смог получить значение в onActivityResult для Фрагмента

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...