Как управлять startActivityForResult на Android?

969

В своей деятельности я называю второе действие из основного действия startActivityForResult. В моем втором задании есть несколько методов, которые завершают это задание (возможно, без результата), однако только один из них возвращает результат.

Например, из основного занятия я называю второе. В этом упражнении я проверяю некоторые функции телефона, такие как наличие камеры. Если этого не произойдет, я закрою это занятие. Кроме того, во время подготовки MediaRecorderили, MediaPlayerесли возникнет проблема, я закрою это действие.

Если на его устройстве есть камера и запись завершена полностью, то после записи видео, если пользователь нажмет кнопку «Готово», я отправлю результат (адрес записанного видео) обратно в основное действие.

Как я могу проверить результат основной деятельности?

Hesam
источник
2
Возможный дубликат Как вернуть результат (startActivityForResult) из действия TabHost?
Ученик по коду

Ответы:

2448

С вашего FirstActivityзвонка SecondActivityиспользуя startActivityForResult()метод

Например:

int LAUNCH_SECOND_ACTIVITY = 1
Intent i = new Intent(this, SecondActivity.class);
startActivityForResult(i, LAUNCH_SECOND_ACTIVITY);

В вашем SecondActivityнаборе данные, которые вы хотите вернуть обратно FirstActivity. Если вы не хотите возвращаться, не устанавливайте ничего.

Например: SecondActivityесли вы хотите отправить данные обратно:

Intent returnIntent = new Intent();
returnIntent.putExtra("result",result);
setResult(Activity.RESULT_OK,returnIntent);
finish();

Если вы не хотите возвращать данные:

Intent returnIntent = new Intent();
setResult(Activity.RESULT_CANCELED, returnIntent);
finish();

Теперь в вашем FirstActivityклассе напишите следующий код для onActivityResult()метода.

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

    if (requestCode == LAUNCH_SECOND_ACTIVITY) {
        if(resultCode == Activity.RESULT_OK){
            String result=data.getStringExtra("result");
        }
        if (resultCode == Activity.RESULT_CANCELED) {
            //Write your code if there's no result
        }
    }
}//onActivityResult

Для более эффективной реализации передачи данных между двумя действиями в Котлине перейдите по этой ссылке « Лучший способ передачи данных между действиями ».

Nishant
источник
1
Какова цель помещения намерения, когда RESUT_CANCELLED в setResult (RESULT_CANCELED, returnIntent);
Исмаил Сахин
4
@ismail Предположим, что SecondActivityпроизошло какое-то исключение, в этом случае вам также нужно вернуть результат в FirstActivity, чтобы вы могли установить результат, как "RESULT_CANCELLED"в блоке catch, и вернуться к, FirstActivtyи FirstActivity's' 'onActivityResult()вы можете проверить, получили ли вы результат успеха или неудачи.
Nishant
10
Так что вам решать, если вам не нужно знать причину отмены, вы можете использовать просто setResult (RESULT_CANCELED); без всякого намерения
Исмаил Сахин
2
@Lei Leyba Никакая функция finish () не вызывается после вызова startActivityForResult (). First Actvity переходит в состояние паузы.
Nishant
6
Для меня это не работает - это то, что я так ненавижу в Android - эта система настолько ненадежна: - /
Мартин Пфеффер
50

Как проверить результат от основной деятельности?

Вам нужно переопределить, а Activity.onActivityResult()затем проверить его параметры:

  • requestCodeопределяет, какое приложение вернуло эти результаты. Это определяется вами, когда вы звоните startActivityForResult().
  • resultCode информирует вас о том, успешно ли это приложение завершилось неудачно или что-то другое
  • dataсодержит любую информацию, возвращенную этим приложением. Это может быть null.
Сэм
источник
Это означает, что requestCode используется только в первом действии, и он никогда не используется для второго действия? Если у 2-го действия есть разные подходы, оно изменится, но на основе дополнительных функций, а не requestCode, верно? Изменить: Да, stackoverflow.com/questions/5104269/…
JCarlosR
44

В дополнение к ответу от @ Nishant, лучший способ вернуть результат активности:

Intent returnIntent = getIntent();
returnIntent.putExtra("result",result);
setResult(RESULT_OK,returnIntent);
finish();

У меня были проблемы с

new Intent();

Тогда я узнал, что правильный путь использует

getIntent();

чтобы получить текущее намерение

Джулиан Альберто
источник
Немного странно создавать новый, Intentкоторый существует только для хранения a Bundleи не имеет нормальных значений, таких как действие или компонент. Но также немного странно (и потенциально опасно?) Изменять то, Intentчто использовалось для запуска текущего действия. Поэтому я искал источник для самого Android и обнаружил, что они всегда создают новый Intentдля использования в качестве результата. Например, github.com/aosp-mirror/platform_frameworks_base/blob/…
spaaarky21
Здравствуйте spaaarky21, спасибо за ваш комментарий. Извините, я не совсем ясно объяснил, как именно я оказался с этим решением. Это было три года назад, и я могу только вспомнить, что мое приложение зависало из-за «нового намерения», именно это я имел в виду, когда говорил «у меня проблемы с». На самом деле я только что попробовал с «getIntent», потому что это имело смысл в то время, и это работало! Из-за этого я решил поделиться своим решением. Возможно, не лучший выбор слов, чтобы сказать «лучший путь» или «правильный путь», но я поддерживаю свое решение. Это то, что решило мою проблему и, видимо, других людей. Спасибо
Джулиан Альберто
1
Вот Это Да! работает отлично. getIntent()кажется идеальным способом вернуть данные в неизвестное действие, откуда оно было вызвано. Спасибо!
Сэм
43

пример

Чтобы увидеть весь процесс в контексте, вот дополнительный ответ. Смотрите мой более полный ответ для более подробного объяснения.

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

MainActivity.java

public class MainActivity extends AppCompatActivity {

    // Add a different request code for every activity you are starting from here
    private static final int SECOND_ACTIVITY_REQUEST_CODE = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    // "Go to Second Activity" button click
    public void onButtonClick(View view) {

        // Start the SecondActivity
        Intent intent = new Intent(this, SecondActivity.class);
        startActivityForResult(intent, SECOND_ACTIVITY_REQUEST_CODE);
    }

    // This method is called when the second activity finishes
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // check that it is the SecondActivity with an OK result
        if (requestCode == SECOND_ACTIVITY_REQUEST_CODE) {
            if (resultCode == RESULT_OK) { // Activity.RESULT_OK

                // get String data from Intent
                String returnString = data.getStringExtra("keyName");

                // set text view with string
                TextView textView = (TextView) findViewById(R.id.textView);
                textView.setText(returnString);
            }
        }
    }
}

SecondActivity.java

public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
    }

    // "Send text back" button click
    public void onButtonClick(View view) {

        // get the text from the EditText
        EditText editText = (EditText) findViewById(R.id.editText);
        String stringToPassBack = editText.getText().toString();

        // put the String to pass back into an Intent and close this activity
        Intent intent = new Intent();
        intent.putExtra("keyName", stringToPassBack);
        setResult(RESULT_OK, intent);
        finish();
    }
}
Suragch
источник
Можно ли это сделать двумя разными приложениями A и B? stackoverflow.com/questions/52975645/…
Джерри Абрахам
12

Для тех, у кого проблема с неправильным requestCode в onActivityResult

Если вы звоните startActivityForResult()со своего Fragment, код запроса изменяется Деятельностью, которой принадлежит Фрагмент.

Если вы хотите получить правильный код результата в вашей деятельности, попробуйте это:

Изменить:

startActivityForResult(intent, 1); Для того, чтобы:

getActivity().startActivityForResult(intent, 1);

Томаш Муларчик
источник
10

Если вы хотите обновить пользовательский интерфейс с результатом активности, вы не можете использовать. В this.runOnUiThread(new Runnable() {} этом случае пользовательский интерфейс не обновится с новым значением. Вместо этого вы можете сделать это:

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

    if (resultCode == RESULT_CANCELED) {
        return;
    }

    global_lat = data.getDoubleExtra("LATITUDE", 0);
    global_lng = data.getDoubleExtra("LONGITUDE", 0);
    new_latlng = true;
}

@Override
protected void onResume() {
    super.onResume();

    if(new_latlng)
    {
        PhysicalTagProperties.this.setLocation(global_lat, global_lng);
        new_latlng=false;
    }
}

Это кажется глупым, но работает довольно хорошо.

DaviF
источник
2

Сначала вы используете startActivityForResult()сначала параметры, Activityа если вы хотите отправить данные со второго Activityна первое, Activityто передайте значение с Intentпомощью setResult()метода и получите эти данные внутри onActivityResult()метода первым Activity.

Дхармендра Пратап
источник
1

Очень распространенная проблема в Android
Это может быть разбито на 3 части
1) начать действие B (происходит в упражнении A)
2) установить запрашиваемые данные (происходит в упражнении B)
3) получить запрошенные данные (происходит в упражнении A)

1) начало деятельности Б

Intent i = new Intent(A.this, B.class);
startActivity(i);

2) Установите запрашиваемые данные

В этой части вы решаете, хотите ли вы отправлять данные обратно или нет, когда происходит определенное событие.
Например: в действии B есть EditText и две кнопки b1, b2.
Нажатие на кнопку b1 отправляет данные обратно в действие.
Нажатие на кнопку b2 не отправляет никаких данных.

Отправка данных

b1......clickListener
{
   Intent resultIntent = new Intent();
   resultIntent.putExtra("Your_key","Your_value");
   setResult(RES_CODE_A,resultIntent);
   finish();
}

Не отправка данных

b2......clickListener
    {
       setResult(RES_CODE_B,new Intent());
       finish();
    }

пользователь нажимает кнопку «назад».
По умолчанию результат устанавливается с кодом ответа Activity.RESULT_CANCEL.

3) Получить результат

Для этого переопределить метод onActivityResult

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

if (resultCode == RES_CODE_A) {

     // b1 was clicked 
   String x = data.getStringExtra("RES_CODE_A");

}
else if(resultCode == RES_CODE_B){

   // b2 was clicked

}
else{
   // back button clicked 
}
}
Рохит Сингх
источник
1

ActivityResultRegistry - рекомендуемый подход

ComponentActivityтеперь предоставляет, ActivityResultRegistryкоторый позволяет вам обрабатывать потоки startActivityForResult()+, onActivityResult()а также requestPermissions()+ onRequestPermissionsResult()без переопределения методов в вашем Activityили Fragment, обеспечивает повышенную безопасность типов через ActivityResultContractи предоставляет ловушки для тестирования этих потоков.

Настоятельно рекомендуется использовать API Result Activity, представленные в AndroidX Activity 1.2.0-alpha02 и Fragment 1.3.0-alpha02.

Добавьте это к вашему build.gradle

def activity_version = "1.2.0-alpha03"

// Java language implementation
implementation "androidx.activity:activity:$activity_version"
// Kotlin
implementation "androidx.activity:activity-ktx:$activity_version"

Как использовать готовый договор?

Этот новый API имеет следующие встроенные функции

  1. TakeVideo
  2. PickContact
  3. GetContent
  4. GetContents
  5. OpenDocument
  6. OpenDocuments
  7. OpenDocumentTree
  8. CreateDocument
  9. Набирать номер
  10. Сделать фотографию
  11. Просить разрешения
  12. RequestPermissions

Пример, использующий контракт takePicture:

private val takePicture = prepareCall(ActivityResultContracts.TakePicture()) 
     { bitmap: Bitmap? ->
        // Do something with the Bitmap, if present
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button.setOnClickListener { takePicture() }
       }

Так что здесь происходит? Давайте разберемся с этим немного. takePictureэто просто обратный вызов, который возвращает обнуляемое растровое изображение - независимо от того, является ли оно пустым, зависит от того, был ли onActivityResultпроцесс успешным. prepareCallзатем регистрирует этот вызов в новой функции ComponentActivityпод названием ActivityResultRegistry- мы вернемся к этому позже. ActivityResultContracts.TakePicture()является одним из встроенных помощников, которые Google создал для нас, и, наконец, вызов на takePictureсамом деле запускает Намерение так же, как ранееActivity.startActivityForResult(intent, REQUEST_CODE) .

Как написать заказной договор?

Простой контракт, который принимает Int в качестве входных данных и возвращает строку, запрошенную Activity, возвращается в результате Intent.

    class MyContract : ActivityResultContract<Int, String>() {

    companion object {
        const val ACTION = "com.myapp.action.MY_ACTION"
        const val INPUT_INT = "input_int"
        const val OUTPUT_STRING = "output_string"
    }

    override fun createIntent(input: Int): Intent {
        return Intent(ACTION)
            .apply { putExtra(INPUT_INT, input) }
    }

    override fun parseResult(resultCode: Int, intent: Intent?): String? {
        return when (resultCode) {
            Activity.RESULT_OK -> intent?.getStringExtra(OUTPUT_STRING)
            else -> null
        }
    }
}



    class MyActivity : AppCompatActivity() {

    private val myActionCall = prepareCall(MyContract()) { result ->
        Log.i("MyActivity", "Obtained result: $result")
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        button.setOnClickListener {
            myActionCall(500)
        }
    }
}

Проверьте эту официальную документацию для получения дополнительной информации.

Darish
источник
0
You need to override Activity.onActivityResult()

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

if (resultCode == RESULT_CODE_ONE) {


   String a = data.getStringExtra("RESULT_CODE_ONE");

}
else if(resultCode == RESULT_CODE_TWO){

   // b was clicked

}
else{

}
}
Нитеш Дев Кунвар
источник