Wie verwalte ich startActivityForResult unter Android?

969

In meiner Aktivität rufe ich eine zweite Aktivität aus der Hauptaktivität von auf startActivityForResult. In meiner zweiten Aktivität gibt es einige Methoden, die diese Aktivität beenden (möglicherweise ohne Ergebnis). Nur eine davon gibt jedoch ein Ergebnis zurück.

Zum Beispiel rufe ich von der Hauptaktivität eine zweite an. In dieser Aktivität überprüfe ich einige Funktionen des Mobilteils, z. B. eine Kamera. Wenn dies nicht der Fall ist, werde ich diese Aktivität schließen. Während der Vorbereitung MediaRecorderoder MediaPlayerwenn ein Problem auftritt, werde ich diese Aktivität schließen.

Wenn das Gerät über eine Kamera verfügt und die Aufnahme vollständig abgeschlossen ist, sende ich nach der Aufnahme eines Videos, wenn ein Benutzer auf die Schaltfläche "Fertig" klickt, das Ergebnis (Adresse des aufgenommenen Videos) an die Hauptaktivität zurück.

Wie überprüfe ich das Ergebnis der Hauptaktivität?

Hesam
quelle

Antworten:

2446

Aus Ihrem FirstActivityAufruf die SecondActivityusing- startActivityForResult()Methode

Zum Beispiel:

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

In Ihrem SecondActivitySet die Daten, zu denen Sie zurückkehren möchten FirstActivity. Wenn Sie nicht zurückkehren möchten, stellen Sie keine ein.

Zum Beispiel: In, SecondActivitywenn Sie Daten zurücksenden möchten:

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

Wenn Sie keine Daten zurückgeben möchten:

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

FirstActivitySchreiben Sie nun in Ihrer Klasse den folgenden Code für die onActivityResult()Methode.

@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

Um die Weitergabe von Daten zwischen zwei Aktivitäten in Kotlin viel besser zu implementieren, klicken Sie bitte auf diesen Link " Eine bessere Möglichkeit, Daten zwischen Aktivitäten weiterzugeben ".

Nishant
quelle
1
Was ist der Zweck, eine Absicht zu setzen, wenn RESUT_CANCELLED in setResult (RESULT_CANCELED, returnIntent);
Ismail Sahin
4
@ismail Angenommen, in SecondActivityeinigen Fällen ist eine Ausnahme aufgetreten. In diesem Fall müssen Sie auch das Ergebnis an das zurückgeben FirstActivity, damit Sie das Ergebnis wie "RESULT_CANCELLED"im catch-Block festlegen und zu FirstActivtyund in zurückkehren FirstActivity's' 'onActivityResult()können, um zu überprüfen, ob Sie das Erfolgs- oder Fehlerergebnis erhalten haben.
Nishant
10
Wenn Sie den Grund für den Abbruch nicht kennen müssen, können Sie einfach setResult (RESULT_CANCELED) verwenden. ohne Absicht
Ismail Sahin
2
@Lei Leyba Nach dem Aufruf von startActivityForResult () wird kein finish () aufgerufen. Die erste Aktivität wird in den Pausenzustand versetzt.
Nishant
6
Für mich funktioniert es nicht -.- das ist es, was ich soooo sehr an Android hasse - dieses System ist so unzuverlässig: - /
Martin Pfeffer
50

Wie überprüfe ich das Ergebnis der Hauptaktivität?

Sie müssen Activity.onActivityResult()die Parameter überschreiben und dann überprüfen:

  • requestCodeGibt an, welche App diese Ergebnisse zurückgegeben hat. Dies wird von Ihnen beim Anruf festgelegt startActivityForResult().
  • resultCode Informiert Sie, ob diese App erfolgreich war, fehlgeschlagen ist oder etwas anderes
  • dataenthält alle von dieser App zurückgegebenen Informationen. Das kann sein null.
Sam
quelle
Dies bedeutet, dass der requestCode nur in der ersten Aktivität verwendet wird und niemals für die zweite Aktivität verwendet wird. Wenn die 2. Aktivität unterschiedliche Ansätze hat, würde sie sich ändern, aber basierend auf den Absichts-Extras und nicht auf dem requestCode, oder? Bearbeiten: Ja, stackoverflow.com/questions/5104269/…
JCarlosR
44

Ergänzend zur Antwort von @ Nishant können Sie das Aktivitätsergebnis am besten zurückgeben:

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

Ich hatte ein Problem mit

new Intent();

Dann fand ich heraus, dass der richtige Weg verwendet wird

getIntent();

um die aktuelle Absicht zu bekommen

Julian Alberto
quelle
Es fühlt sich etwas seltsam an, eine neue zu erstellen Intent, die nur für a existiert Bundleund nicht die normalen Werte wie eine Aktion oder Komponente aufweist. Es fühlt sich aber auch etwas seltsam (und möglicherweise gefährlich?) An, das zu ändern Intent, mit dem die aktuelle Aktivität gestartet wurde. Also habe ich die Quelle nach Android selbst durchsucht und festgestellt, dass sie immer eine neue erstellen Intent, um sie als Ergebnis zu verwenden. Zum Beispiel github.com/aosp-mirror/platform_frameworks_base/blob/…
spaaarky21
Hallo spaaarky21, danke für deinen Kommentar. Es tut mir leid, dass ich nicht so klar erklärt habe, wie ich zu dieser Lösung gekommen bin. Es war vor drei Jahren und ich kann mich nur daran erinnern, dass meine App wegen "new Intent" abgestürzt ist. Das habe ich gemeint, als ich sagte "Ich hatte ein Problem mit". Eigentlich habe ich es nur mit "getIntent" versucht, weil es damals Sinn machte und es funktionierte! Aus diesem Grund habe ich beschlossen, meine Lösung zu teilen. Vielleicht nicht die beste Wortwahl, um "bester Weg" oder "richtiger Weg" zu sagen, aber ich stehe zu meiner Lösung. Es ist das, was mein Problem und offenbar auch andere Menschen gelöst hat. Vielen Dank
Julian Alberto
1
Beeindruckend! funktioniert super. getIntent()scheint eine perfekte Möglichkeit zu sein, Daten an unbekannte Aktivitäten zurückzugeben, von denen aus die Aktivität aufgerufen wurde. Vielen Dank!
Sam
43

Beispiel

Um den gesamten Prozess im Kontext zu sehen, finden Sie hier eine ergänzende Antwort. Weitere Erklärungen finden Sie in meiner ausführlicheren Antwort .

Geben Sie hier die Bildbeschreibung ein

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
quelle
Kann dies von zwei verschiedenen Apps A und App b durchgeführt werden? stackoverflow.com/questions/52975645/…
Jerry Abraham
12

Für diejenigen, die Probleme mit dem falschen requestCode in onActivityResult haben

Wenn Sie startActivityForResult()von Ihrem aus anrufen Fragment, wird der requestCode von der Aktivität geändert, der das Fragment gehört.

Wenn Sie den richtigen resultCode in Ihrer Aktivität erhalten möchten, versuchen Sie Folgendes:

Veränderung:

startActivityForResult(intent, 1); Zu:

getActivity().startActivityForResult(intent, 1);

Tomasz Mularczyk
quelle
10

Wenn Sie die Benutzeroberfläche mit dem Aktivitätsergebnis aktualisieren möchten, können Sie sie nicht verwenden. Dadurch wird this.runOnUiThread(new Runnable() {} die Benutzeroberfläche nicht mit einem neuen Wert aktualisiert . Stattdessen können Sie Folgendes tun:

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

Das scheint albern, funktioniert aber ziemlich gut.

DaviF
quelle
2

Zuerst verwenden Sie startActivityForResult()mit Parametern in first Activityund wenn Sie Daten von second Activitynach first senden möchten, Activityübergeben Sie den Wert mit Intentwith setResult()method und erhalten diese Daten innerhalb von onActivityResult()method in first Activity.

Dharmendra Pratap
quelle
1

Sehr häufiges Problem bei Android
Es kann in 3 Teile unterteilt werden
1) Starten Sie Aktivität B (passiert in Aktivität A)
2) Setzen Sie die angeforderten Daten (passiert in Aktivität B)
3) Empfangen Sie angeforderte Daten (passiert in Aktivität A)

1) startActivity B.

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

2) Stellen Sie die angeforderten Daten ein

In diesem Teil entscheiden Sie, ob Sie Daten zurücksenden möchten oder nicht, wenn ein bestimmtes Ereignis eintritt.
Beispiel: In Aktivität B gibt es einen EditText und zwei Schaltflächen b1, b2.
Durch Klicken auf die Schaltfläche b1 werden Daten an Aktivität A zurückgesendet. Durch
Klicken auf die Schaltfläche b2 werden keine Daten gesendet.

Daten senden

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

Keine Daten senden

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

Benutzer klickt auf die Schaltfläche Zurück
Standardmäßig wird das Ergebnis mit dem Antwortcode Activity.RESULT_CANCEL festgelegt

3) Ergebnis abrufen

Überschreiben Sie dazu die onActivityResult-Methode

@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 
}
}
Rohit Singh
quelle
1

Die ActivityResultRegistry ist der empfohlene Ansatz

ComponentActivitybietet jetzt eine Funktion ActivityResultRegistry, mit der Sie sowohl die startActivityForResult()+ onActivityResult()als auch die requestPermissions()+ onRequestPermissionsResult()Flows verarbeiten können, ohne die Methoden in Ihrem Activityoder zu überschreiben Fragment, erhöht die Typensicherheit über ActivityResultContractund bietet Hooks zum Testen dieser Flows.

Es wird dringend empfohlen, die in AndroidX Activity 1.2.0-alpha02 und Fragment 1.3.0-alpha02 eingeführten APIs für Aktivitätsergebnisse zu verwenden.

Fügen Sie dies Ihrem hinzu 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"

Wie verwende ich den vorgefertigten Vertrag?

Diese neue API verfügt über die folgenden vorgefertigten Funktionen

  1. Video aufnehmen
  2. PickContact
  3. GetContent
  4. GetContents
  5. OpenDocument
  6. OpenDocuments
  7. OpenDocumentTree
  8. CreateDocument
  9. Wählen
  10. Ein Bild machen
  11. Um Erlaubnis bitten
  12. RequestPermissions

Ein Beispiel, das den takePicture-Vertrag verwendet:

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

Also, was ist hier los? Lassen Sie es uns etwas aufschlüsseln. takePictureist nur ein Rückruf, der eine nullfähige Bitmap zurückgibt - ob sie null ist oder nicht, hängt davon ab, ob der onActivityResultProzess erfolgreich war oder nicht . prepareCallregistriert dann diesen Anruf in einer neuen Funktion ComponentActivitynamens the ActivityResultRegistry- wir werden später darauf zurückkommen. ActivityResultContracts.TakePicture()ist einer der integrierten Helfer, die Google für uns erstellt hat, und das endgültige Aufrufen takePicturelöst die Absicht auf dieselbe Weise aus, wie Sie es zuvor getan haben Activity.startActivityForResult(intent, REQUEST_CODE).

Wie schreibe ich einen benutzerdefinierten Vertrag?

Einfacher Vertrag, der ein Int als Eingabe verwendet und einen String zurückgibt, der die angeforderte Aktivität im Ergebnis Intent zurückgibt.

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

Weitere Informationen finden Sie in dieser offiziellen Dokumentation.

Darish
quelle
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{

}
}
Nitesh Dev Kunwar
quelle