Як керувати startActivityForResult на Android?


969

Свою діяльність я називаю другою діяльністю від основної діяльності startActivityForResult. У моїй другій діяльності є деякі методи, які закінчують цю діяльність (можливо, без результату), проте лише один з них повертає результат.

Наприклад, з основної діяльності я називаю другий. У цій діяльності я перевіряю деякі функції телефону, такі як у неї камера. Якщо його немає, я закрию цю діяльність. Крім того, під час підготовки MediaRecorderабо MediaPlayerякщо виникне проблема, я закрию цю діяльність.

Якщо на його пристрої є камера, а запис зроблений повністю, то після запису відео, якщо користувач натисне кнопку "Зроблено", я поверну результат (адресу записаного відео) назад до основної діяльності.

Як перевірити результат від основної діяльності?


Відповіді:


2446

З вашого 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

Щоб набагато краще реалізувати передачу даних між двома видами діяльності в Котліні, перейдіть за цим посиланням " Кращий спосіб передачі даних між видами діяльності "


1
Яка мета введення наміру, коли RESUT_CANCELLED у setResult (RESULT_CANCELED, returnIntent);
Ісмаїл Сахін

4
@ismail Припустимо, SecondActivityвиникла певна виняток, і в цьому випадку вам також потрібно повернути результат в FirstActivity, щоб ви могли встановити результат як "RESULT_CANCELLED"у блоці вилову, і повернутися до FirstActivtyта вFirstActivity's' 'onActivityResult() ви зможете перевірити, чи отримали ви результат успіху чи невдачі.
Нішант

10
Тож вирішувати вам, якщо вам не потрібно знати причину скасування, ви можете використовувати просто setResult (RESULT_CANCELED); без жодного наміру
Ісмаїл Сахін

2
@Lei Leyba Без виклику завершення () не викликається після виклику startActivityForResult (). Перша активність перейде до стану паузи.
Нішант

6
Для мене це не працює -.- це те, що я дуже ненавиджу Soooo щодо Android - ця система настільки ненадійна: - /
Мартін Пфеффер

50

Як перевірити результат від основної діяльності?

Вам потрібно переозначити, Activity.onActivityResult()а потім перевірити його параметри:

  • requestCodeвизначає, яке додаток повернуло ці результати. Це визначається вами під час дзвінка startActivityForResult().
  • resultCode повідомляє, чи вдалося це програму, не вдалося чи щось інше
  • dataмістить будь-яку інформацію, повернуту цим додатком. Це може бути null.

Це означає, що codeCode використовується тільки в першій активності, і ніколи не використовується для 2-ї активності? Якщо у 2-й діяльності є різні підходи, вона змінилася б, але грунтуючись на додатках у намірах, а не на коді request, правда? Edit: Так, stackoverflow.com/questions/5104269 / ...
JCarlosR

44

Доповнюючи відповідь від @ Nishant, найкращий спосіб повернути результат діяльності:

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

У мене були проблеми з

new Intent();

Тоді я з’ясував, що правильний спосіб - це використання

getIntent();

щоб отримати поточний намір


Дещо дивно створювати нове, Intentяке існує лише для утримання а 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();
    }
}

Чи можна це зробити двома різними програмами A та додатком b? stackoverflow.com/questions/52975645/…
Джеррі Авраам

12

Для тих, хто має проблеми неправильним запитомCode в 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;
    }
}

Це здається дурним, але працює досить добре.


2

Спочатку ви використовуєте startActivityForResult()з параметрами по-перше, Activityі якщо ви хочете відправляти дані з другого Activityв перше, Activityтоді передайте значення за Intentдопомогою setResult()методу і отримуйте ці дані в onActivityResult()методі спочатку Activity.


1

Дуже поширена проблема в андроїді.
Її можна розділити на 3 частини
1) запуск діяльності B (трапляється в діяльності A)
2) встановлення запитуваних даних (трапляється в діяльності B)
3) отримання запитуваних даних (трапляється в діяльності A)

1) стартАктивність B

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 API, введені в 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. Візьміть відео
  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 як Вхідний і повертає Рядок, який вимагає Діяльність, повертається в результаті Намір результату.

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

Перегляньте цю офіційну документацію для отримання додаткової інформації.


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{

}
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.