Come gestire startActivityForResult su Android?


969

Nella mia attività, sto chiamando una seconda attività dall'attività principale di startActivityForResult. Nella mia seconda attività, ci sono alcuni metodi che finiscono questa attività (forse senza un risultato), tuttavia, solo uno di essi restituisce un risultato.

Ad esempio, dall'attività principale, ne chiamo una seconda. In questa attività, sto controllando alcune funzionalità del telefono, ad esempio se ha una fotocamera. In caso contrario, chiuderò questa attività. Inoltre, durante la preparazione di MediaRecordero MediaPlayerse si verifica un problema, chiuderò questa attività.

Se il suo dispositivo ha una videocamera e la registrazione è completa, dopo aver registrato un video se un utente fa clic sul pulsante Fine, rispedirò il risultato (indirizzo del video registrato) all'attività principale.

Come posso controllare il risultato dall'attività principale?


Risposte:


2447

Dalla tua FirstActivitychiamata il metodo SecondActivityusing startActivityForResult()

Per esempio:

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

Nel tuo SecondActivityset i dati a cui vuoi tornare FirstActivity. Se non vuoi tornare indietro, non impostarne nessuno.

Ad esempio: In SecondActivityse si desidera inviare nuovamente i dati:

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

Se non si desidera restituire dati:

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

Ora nella tua FirstActivityclasse scrivi il seguente codice per il onActivityResult()metodo.

@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

Per implementare il passaggio di dati tra due attività in modo molto migliore a Kotlin, seguire questo link " Un modo migliore per passare i dati tra attività "


1
Qual è lo scopo di mettere un intento quando RESUT_CANCELLED in setResult (RESULT_CANCELED, returnIntent);
Ismail Sahin,

4
@ismail Supponiamo che si sia SecondActivityverificata un'eccezione, in quel caso anche tu devi restituire il risultato a FirstActivity, in modo da poter impostare il risultato come "RESULT_CANCELLED"nel blocco catch e tornare a FirstActivtye in FirstActivity's' 'onActivityResult()puoi verificare se hai ottenuto il risultato positivo o negativo.
Nishant,

10
Quindi dipende da te, se non hai bisogno di conoscere il motivo dell'annullamento, puoi usare solo setResult (RESULT_CANCELED); senza alcuna intenzione
Ismail Sahin,

2
@Lei Leyba No finish () non viene chiamato dopo aver chiamato startActivityForResult (). First Actvity si sposterà nello stato di pausa.
Nishant,

6
Per me non funziona -.- Questo è ciò che odio moltissimo di Android - questo sistema è così inaffidabile: - /
Martin Pfeffer

50

Come controllare il risultato dall'attività principale?

Devi sovrascrivere Activity.onActivityResult()quindi controllare i suoi parametri:

  • requestCodeidentifica quale app ha restituito questi risultati. Questo è definito da te quando chiami startActivityForResult().
  • resultCode ti informa se questa app ha avuto successo, non è riuscita o qualcosa di diverso
  • datacontiene tutte le informazioni restituite da questa app. Questo potrebbe essere null.

Significa che il requestCode viene utilizzato solo nella prima attività e non viene mai utilizzato per la seconda attività? Se la seconda attività ha approcci diversi, cambierebbe, ma basandosi sugli extra intenti e non dal requestCode, giusto? Edit: Sì, stackoverflow.com/questions/5104269/...
JCarlosR

44

Completando la risposta di @ Nishant, il modo migliore per restituire il risultato dell'attività è:

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

Ho avuto problemi con

new Intent();

Poi ho scoperto che sta usando il modo corretto

getIntent();

per ottenere l'intento attuale


È strano creare un nuovo Intentche esiste solo per contenere un Bundlee che non ha i valori normali come un'azione o un componente. Ma sembra anche un po 'strano (e potenzialmente pericoloso?) Modificare quello Intentche è stato utilizzato per avviare l'attività corrente. Così ho cercato la fonte per Android stesso e ho scoperto che ne creano sempre uno nuovo Intentda utilizzare come risultato. Ad esempio, github.com/aosp-mirror/platform_frameworks_base/blob/…
spaaarky21

Ciao spaaarky21, grazie per il tuo commento. Mi dispiace non essere stato così chiaro nello spiegare esattamente come sono finito con quella soluzione. Sono passati tre anni e ricordo solo che la mia app si stava arrestando in modo anomalo a causa del "nuovo intento", questo è ciò che intendevo quando ho detto "stavo avendo problemi con". In realtà ho provato con "getIntent", perché all'epoca aveva senso e ha funzionato! Per questo motivo ho deciso di condividere la mia soluzione. Forse non è la scelta migliore di parole per dire "modo migliore" o "modo corretto", ma io sostengo la mia soluzione. È ciò che ha risolto il mio problema e anche con altre persone. Grazie
Julian Alberto,

1
Wow! funziona alla grande. getIntent()sembra essere un modo perfetto per restituire i dati ad attività sconosciute, da dove l'attività è stata chiamata. Grazie!
sam,

43

Esempio

Per vedere l'intero processo nel contesto, ecco una risposta supplementare. Vedi la mia risposta più completa per ulteriori spiegazioni.

inserisci qui la descrizione dell'immagine

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

Questo può essere fatto da due diverse app A e app b? stackoverflow.com/questions/52975645/…
Jerry Abraham,

12

Per coloro che hanno problemi con requestCode errato in onActivityResult

Se chiami startActivityForResult()dal tuo Fragment, il requestCode viene modificato dall'attività proprietaria del frammento.

Se vuoi ottenere il risultato correttoCodice nella tua attività prova questo:

Modificare:

startActivityForResult(intent, 1); Per:

getActivity().startActivityForResult(intent, 1);


10

Se si desidera aggiornare l'interfaccia utente con il risultato dell'attività, non è possibile utilizzare this.runOnUiThread(new Runnable() {} In questo modo l'interfaccia utente non verrà aggiornata con un nuovo valore. Invece, puoi farlo:

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

Sembra sciocco ma funziona abbastanza bene.


2

In primo luogo si utilizza startActivityForResult()con i parametri in primo luogo Activitye se si desidera inviare i dati dal secondo Activityal primo, Activityquindi passare il valore utilizzando Intentcon il setResult()metodo e ottenere i dati all'interno del onActivityResult()metodo in primo luogo Activity.


1

Problema molto comune in Android
Può essere suddiviso in 3 pezzi
1) avviare l'attività B (accade nell'attività A)
2) impostare i dati richiesti (succede nell'attività B)
3) ricevere i dati richiesti (succede nell'attività A)

1) startActivity B

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

2) Impostare i dati richiesti

In questa parte, decidi se inviare o meno i dati quando si verifica un evento particolare.
Ad esempio: nell'attività B sono presenti un testo di modifica e due pulsanti b1, b2.
Facendo clic sul pulsante b1, i dati ritornano all'attività A
Facendo clic sul pulsante b2 non vengono inviati dati.

Invio di dati

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

Non inviare dati

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

l'utente fa clic sul pulsante Indietro
Per impostazione predefinita, il risultato è impostato con il codice di risposta Activity.RESULT_CANCEL

3) Recupera risultato

Per tale override del metodo 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 è l'approccio consigliato

ComponentActivityfornisce ora una ActivityResultRegistryche consente di gestire il startActivityForResult()+ onActivityResult()e requestPermissions()+ onRequestPermissionsResult()scorre senza sostituire i metodi nel vostro Activityo Fragment, porta maggiore sicurezza tipo via ActivityResultContracte fornisce ganci per testare questi flussi.

Si consiglia vivamente di utilizzare le API dei risultati delle attività introdotte in AndroidX Activity 1.2.0-alpha02 e Fragment 1.3.0-alpha02.

Aggiungi questo al tuo 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"

Come utilizzare il contratto pre-costruito?

Questa nuova API ha le seguenti funzionalità predefinite

  1. TakeVideo
  2. PickContact
  3. getContent
  4. getContents
  5. OpenDocument
  6. OpenDocuments
  7. OpenDocumentTree
  8. CreateDocument
  9. Comporre
  10. Fare una foto
  11. Richiesta di permesso
  12. RequestPermissions

Un esempio che utilizza il contratto 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() }
       }

Quindi cosa sta succedendo qui? Analizziamolo leggermente. takePictureè solo un callback che restituisce un Bitmap nullable - che sia nullo dipende dal fatto che il onActivityResultprocesso abbia avuto successo o meno . prepareCallquindi registra questa chiamata in una nuova funzione ComponentActivitychiamata ActivityResultRegistry- torneremo su questo più tardi. ActivityResultContracts.TakePicture()è uno degli helper integrati che Google ha creato per noi e infine invocare in takePicturerealtà attiva l'intento nello stesso modo in cui lo faresti in precedenza Activity.startActivityForResult(intent, REQUEST_CODE).

Come scrivere un contratto personalizzato?

Il contratto semplice che accetta un Int come input e restituisce una stringa che ha richiesto l'attività restituisce il risultato Intento.

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

Controlla questa documentazione ufficiale per maggiori informazioni.


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{

}
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.