Jak zarządzać startActivityForResult na Androidzie?


969

W mojej aktywności nazywam drugą aktywność z aktywności głównej przez startActivityForResult. W mojej drugiej aktywności są metody, które kończą tę aktywność (być może bez wyniku), jednak tylko jedna z nich zwraca wynik.

Na przykład z głównej działalności nazywam drugą. W tym ćwiczeniu sprawdzam niektóre funkcje telefonu, takie jak aparat. Jeśli nie, to zamknę tę aktywność. Również podczas przygotowywania MediaRecorderlub w MediaPlayerprzypadku wystąpienia problemu zamknę to działanie.

Jeśli jego urządzenie ma kamerę, a nagrywanie zostało zakończone całkowicie, to po nagraniu wideo, jeśli użytkownik kliknie przycisk Gotowe, wyślę wynik (adres nagranego wideo) z powrotem do głównej czynności.

Jak sprawdzić wynik z głównej aktywności?


Odpowiedzi:


2446

Z twojego FirstActivitywywołania za SecondActivitypomocą startActivityForResult()metody

Na przykład:

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

W twoim SecondActivityzestawie dane, do których chcesz wrócić FirstActivity. Jeśli nie chcesz wracać, nie ustawiaj żadnych.

Na przykład: W, SecondActivityjeśli chcesz odesłać dane:

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

Jeśli nie chcesz zwracać danych:

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

Teraz w swojej FirstActivityklasie napisz następujący kod dla onActivityResult()metody.

@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
Jaki jest cel wprowadzenia zamiaru, gdy RESUT_CANCELLED w setResult (RESULT_CANCELED, returnIntent);
Ismail Sahin

4
@ismail Załóżmy, że w SecondActivityjakimś wyjątku wystąpił, w takim przypadku musisz również zwrócić wynik do FirstActivity, abyś mógł ustawić wynik jak "RESULT_CANCELLED"w bloku catch i powrócić do FirstActivtyi FirstActivity's' 'onActivityResult()można sprawdzić, czy uzyskałeś wynik sukcesu lub niepowodzenia.
Nishant

10
Więc to zależy od Ciebie, jeśli nie musisz znać przyczyny anulowania, możesz użyć po prostu setResult (RESULT_CANCELED); bez żadnego zamiaru
Ismail Sahin

2
@Lei Leyba Nie wywoływano zakończenia () po wywołaniu startActivityForResult (). Pierwszy Actvity przejdzie w stan pauzy.
Nishant

6
Dla mnie to nie działa -.- tego właśnie tak bardzo nienawidzę w Androidzie - ten system jest tak zawodny: - /
Martin Pfeffer

50

Jak sprawdzić wynik z głównej aktywności?

Musisz zastąpić, Activity.onActivityResult()a następnie sprawdzić jego parametry:

  • requestCodeokreśla, która aplikacja zwróciła te wyniki. Jest to definiowane przez Ciebie podczas rozmowy startActivityForResult().
  • resultCode informuje, czy ta aplikacja się powiodła, czy nie, czy coś innego
  • dataprzechowuje wszelkie informacje zwrócone przez tę aplikację. To może być null.

Oznacza to, że requestCode jest używany tylko w pierwszym działaniu i nigdy nie jest używany w drugim działaniu? Jeśli 2. działanie ma inne podejście, zmieniłoby się, ale w oparciu o zamierzone dodatki, a nie według kodu żądania, prawda? Edycja: Tak, stackoverflow.com/questions/5104269/…
JCarlosR

44

Uzupełniając odpowiedź z @ Nishant, najlepszym sposobem na zwrócenie wyniku działania jest:

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

Miałem problem

new Intent();

Potem dowiedziałem się, że używa prawidłowego sposobu

getIntent();

uzyskać aktualne zamiary


To trochę dziwne, aby utworzyć nowy, Intentktóry istnieje tylko do przechowywania a Bundlei nie ma normalnych wartości, takich jak akcja lub komponent. Ale modyfikowanie tego, Intentktóry został użyty do uruchomienia bieżącej aktywności, wydaje się nieco dziwne (i potencjalnie niebezpieczne?) . Przeszukałem więc źródło dla samego Androida i stwierdziłem, że zawsze tworzą nowy, którego Intentmożna użyć w rezultacie. Na przykład github.com/aosp-mirror/platform_frameworks_base/blob/…
spaaarky21

Witaj spaaarky21, dziękuję za komentarz. Przepraszam, że nie wyjaśniłem dokładnie, jak skończyłem z tym rozwiązaniem. To było trzy lata temu i pamiętam tylko, że moja aplikacja uległa awarii z powodu „nowej intencji”, to miałem na myśli, mówiąc „miałem problem”. Właśnie próbowałem z „getIntent”, ponieważ miało to wtedy sens i działało! Z tego powodu postanowiłem podzielić się moim rozwiązaniem. Może nie najlepszy wybór słów na „najlepszy sposób” lub „poprawny sposób”, ale trzymam się mojego rozwiązania. To rozwiązało mój problem, a także prawdopodobnie innych ludzi. Dzięki
Julian Alberto,

1
Łał! działa świetnie. getIntent()wydają się być doskonałym sposobem na powrót danych do nieznanej aktywności, skąd ta aktywność została wywołana. Dzięki!
sam

43

Przykład

Aby zobaczyć cały proces w kontekście, oto dodatkowa odpowiedź. Zobacz moją pełniejszą odpowiedź, aby uzyskać więcej wyjaśnień.

wprowadź opis zdjęcia tutaj

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

Czy można to zrobić za pomocą dwóch różnych aplikacji A i aplikacji b? stackoverflow.com/questions/52975645/…
Jerry Abraham

12

Dla tych, którzy mają problem ze złym requestCode w onActivityResult

Jeśli dzwonisz startActivityForResult()ze swojego Fragment, requestCode jest zmieniany przez działanie, które jest właścicielem fragmentu.

Jeśli chcesz uzyskać poprawny wynikKod swojej aktywności, spróbuj tego:

Zmiana:

startActivityForResult(intent, 1); Do:

getActivity().startActivityForResult(intent, 1);


10

Jeśli chcesz zaktualizować interfejs użytkownika o wynik działania, nie możesz użyć. Po wykonaniu this.runOnUiThread(new Runnable() {} tej czynności interfejs użytkownika nie odświeży się z nową wartością. Zamiast tego możesz to zrobić:

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

To wydaje się głupie, ale działa całkiem dobrze.


2

Najpierw używasz startActivityForResult()z parametrami na początku, Activitya jeśli chcesz wysyłać dane od drugiej Activitydo pierwszej, Activitynastępnie przekaż wartość za Intentpomocą setResult()metody i onActivityResult()najpierw pobierz te dane do metody Activity.


1

Bardzo częsty problem w Androidzie
Można go podzielić na 3 części
1) rozpocząć działanie B (dzieje się w działaniu A)
2) ustawić żądane dane (dzieje się w działaniu B)
3) otrzymywać wymagane dane (dzieje się w działaniu A)

1) startActivity B

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

2) Ustaw żądane dane

W tej części decydujesz, czy chcesz odesłać dane z powrotem, gdy wystąpi określone zdarzenie.
Np .: W ćwiczeniu B znajduje się EditText i dwa przyciski b1, b2.
Kliknięcie przycisku b1 odsyła dane z powrotem do działania.
Kliknięcie przycisku b2 nie powoduje wysłania żadnych danych.

Wysyłanie danych

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

Nie wysyłam danych

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

użytkownik klika przycisk Wstecz
Domyślnie wynik jest ustawiany za pomocą kodu odpowiedzi Activity.RESULT_CANCEL

3) Odzyskaj wynik

Do tego zastąpienia metody 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 jest zalecanym podejściem

ComponentActivityteraz zapewnia opcję, ActivityResultRegistryktóra pozwala obsługiwać zarówno przepływy startActivityForResult()+, onActivityResult()jak i requestPermissions()+ onRequestPermissionsResult()bez nadpisywania metod w twoim Activitylub Fragment, zapewnia zwiększone bezpieczeństwo typu poprzez ActivityResultContract, i zapewnia zaczepy do testowania tych przepływów.

Zdecydowanie zaleca się stosowanie interfejsów API wyników wyników wprowadzonych w AndroidX Activity 1.2.0-alpha02 i Fragment 1.3.0-alpha02.

Dodaj to do swojego 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"

Jak korzystać z gotowej umowy?

Ten nowy interfejs API ma następujące wstępnie zbudowane funkcje

  1. Weź film
  2. PickContact
  3. Pobierz zawartość
  4. GetContents
  5. OpenDocument
  6. OpenDocuments
  7. OpenDocumentTree
  8. CreateDocument
  9. Wybierz
  10. Zrób zdjęcie
  11. Prośba o pozwolenie
  12. RequestPermissions

Przykład wykorzystujący umowę 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() }
       }

Co się tu dzieje? Rozbijmy to lekko. takePicturejest tylko wywołaniem zwrotnym, które zwraca zerowalną bitmapę - to, czy jest ona pusta, zależy od tego, czy onActivityResultproces się powiódł, czy nie . prepareCallnastępnie rejestruje to wywołanie w nowej funkcji o ComponentActivitynazwie ActivityResultRegistry- wrócimy do tego później. ActivityResultContracts.TakePicture()jest jednym z wbudowanych pomocników, które Google dla nas stworzyło, a wreszcie wywołanie takePicturefaktycznie wyzwala zamiar w taki sam sposób, jak wcześniej Activity.startActivityForResult(intent, REQUEST_CODE).

Jak napisać niestandardową umowę?

Prosty kontrakt, który przyjmuje Int jako dane wejściowe i zwraca ciąg znaków, który zażądał działania, zwraca wynik 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)
        }
    }
}

Sprawdź oficjalną dokumentację, aby uzyskać więcej informacji.


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{

}
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.