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

Ответ 1

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

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

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

Ответ 2

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

Ответ 3

Вариант 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
}

Ответ 4

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

Ответ 5

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

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

Ответ 6

Оригинальное сообщение.

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

Enter image description here

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

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

Enter image description here

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

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

Ответ 7

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

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

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

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

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

После того, как операция была перенесена обратно, результат будет отправлен в Activity onActivityResult с измененным кодом запроса, который будет декодирован до исходного идентификатора 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) {

       }
}

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

Ответ 8

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

Внимание

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

Ответ 9

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

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

android:noHistory="false"

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

android:launchMode="standard"

Ответ 10

Я также столкнулся с той же проблемой, как только я переместил этот блок кода за пределы фрагмента в класс Utility, причем 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 на фрагменте

Ответ 11

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

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

Ответ 12

Решение 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.

Ответ 13

В моем случае это была ошибка 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);
        }
    }
}

Ответ 14

Короче говоря,

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

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

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

Ответ 15

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

this.startActivityForResult(intent, REQUEST_CODE);

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

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

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

super.onActivityResult(requestCode, resultCode, data);

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

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

Ответ 16

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

Ответ 17

В большинстве этих ответов вы говорите, что вы должны называть 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(...);.

Ответ 18

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

Ответ 19

  • Вы можете просто переопределить BaseActivity onActivityResult на фрагменте baseActivity.startActivityForResult.

  • В 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);
    }
    
  • В 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();
      }
    }
    

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

Ответ 20

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

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

Ответ 21

Версия Kotlin (в вашей активности onActivityResult())

 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    //add following lines in your activity
    if(supportFragmentManager?.fragments!=null && supportFragmentManager?.fragments!!.size>0)
     for (i in 0..supportFragmentManager?.fragments!!.size-1) {
         val fragment= supportFragmentManager?.fragments!!.get(i)
         fragment.onActivityResult(requestCode, resultCode, data)
    }
 }

Ответ 22

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

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

Ответ 23

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

Вызвать startActivityForResult (Intent, int) из фрагмента, содержащего Activity.

Смотрите: Android Fragment API

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

Ответ 24

Ваш код имеет вложенный фрагмент. Вызов 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();
}

Ответ 25

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

getParentFragment().startActivityForResult(intent, RequestCode);

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

Ответ 26

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

Ответ 27

Другой вариант использования, который еще не описан в других ответах:

onActivityResult(), объявленный во фрагменте, не вызывается при использовании exception.startResolutionForResult():

if (exception is ResolvableApiException) {
    exception.startResolutionForResult(activity!!, MY_REQUEST_CODE)
}

В этом случае замените exception.startResolutionForResult() фрагментом startIntentSenderForResult():

if (exception is ResolvableApiException) {
    startIntentSenderForResult(exception.resolution.intentSender, MY_REQUEST_CODE, null, 0, 0, 0, null)
}

Ответ 28

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

Ответ 29

Я просто создаю метод обхода:

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

Ответ 30

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

@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 будет вызывать без вызова своего родителя.