Bagaimana cara mengelola startActivityForResult di Android?

969

Dalam aktivitas saya, saya menelepon aktivitas kedua dari aktivitas utama oleh startActivityForResult. Dalam aktivitas kedua saya, ada beberapa metode yang menyelesaikan aktivitas ini (mungkin tanpa hasil), namun, hanya satu dari mereka yang mengembalikan hasilnya.

Misalnya, dari aktivitas utama, saya memanggil yang kedua. Dalam kegiatan ini, saya memeriksa beberapa fitur handset seperti apakah ia memiliki kamera. Jika tidak, maka saya akan menutup kegiatan ini. Juga, selama persiapan MediaRecorderatau MediaPlayerjika masalah terjadi maka saya akan menutup kegiatan ini.

Jika perangkatnya memiliki kamera dan perekaman selesai, maka setelah merekam video jika pengguna mengklik tombol selesai maka saya akan mengirim hasilnya (alamat video yang direkam) kembali ke aktivitas utama.

Bagaimana saya memeriksa hasil dari kegiatan utama?

Hesam
sumber

Jawaban:

2447

Dari FirstActivitypanggilan Anda metode SecondActivitymenggunakan startActivityForResult()

Sebagai contoh:

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

Di SecondActivityset Anda , data yang ingin Anda kembalikan FirstActivity. Jika Anda tidak ingin kembali, jangan atur apa pun.

Misalnya: Di SecondActivityjika Anda ingin mengirim kembali data:

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

Jika Anda tidak ingin mengembalikan data:

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

Sekarang di FirstActivitykelas Anda tulis kode berikut untuk onActivityResult()metode ini.

@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

Untuk menerapkan pengiriman data di antara dua aktivitas dengan cara yang jauh lebih baik di Kotlin, silakan kunjungi tautan ini ' Cara yang lebih baik untuk mengirimkan data di antara Aktivitas '

Nishant
sumber
1
Apa maksud dari meletakkan maksud saat RESUT_CANCELLED di setResult (RESULT_CANCELED, returnIntent);
Ismail Sahin
4
@ismail Misalkan dalam SecondActivitybeberapa pengecualian terjadi, dalam hal ini Anda juga harus mengembalikan hasilnya ke FirstActivity, sehingga Anda dapat mengatur hasilnya seperti "RESULT_CANCELLED"di blok tangkap dan kembali ke FirstActivtydan di FirstActivity's' 'onActivityResult()Anda dapat memeriksa apakah Anda mendapatkan hasil keberhasilan atau kegagalan.
Nishant
10
Jadi terserah Anda, jika Anda tidak perlu tahu alasan pembatalan, Anda bisa menggunakan setResult saja (RESULT_CANCELED); tanpa maksud apa pun
Ismail Sahin
2
@Lei Leyba No finish () tidak dipanggil setelah memanggil startActivityForResult (). Actvity Pertama akan pindah ke kondisi jeda.
Nishant
6
Bagi saya itu tidak bekerja -.- ini adalah apa yang saya benci soooo banyak tentang Android - sistem ini sangat tidak dapat diandalkan: - /
Martin Pfeffer
50

Bagaimana cara memeriksa hasil dari kegiatan utama?

Anda perlu mengganti Activity.onActivityResult()lalu memeriksa parameternya:

  • requestCodemengidentifikasi aplikasi mana yang mengembalikan hasil ini. Ini ditentukan oleh Anda saat Anda menelepon startActivityForResult().
  • resultCode memberi tahu Anda apakah aplikasi ini berhasil, gagal, atau sesuatu yang berbeda
  • datamenyimpan informasi apa pun yang dikembalikan oleh aplikasi ini. Ini mungkin null.
Sam
sumber
Ini berarti bahwa requestCode hanya digunakan dalam aktivitas pertama, dan tidak pernah digunakan untuk aktivitas kedua? Jika aktivitas ke-2 memiliki pendekatan yang berbeda, itu akan berubah, tetapi didasarkan pada ekstra maksud dan bukan oleh requestCode, kan? Sunting: Ya, stackoverflow.com/questions/5104269/…
JCarlosR
44

Melengkapi jawaban dari @ Nishant, cara terbaik untuk mengembalikan hasil aktivitas adalah:

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

Saya mengalami masalah dengan

new Intent();

Kemudian saya menemukan bahwa cara yang benar adalah menggunakan

getIntent();

untuk mendapatkan maksud saat ini

Julian Alberto
sumber
Rasanya agak aneh untuk membuat yang baru Intentyang hanya ada untuk menampung Bundledan tidak memiliki nilai normal seperti tindakan atau komponen. Tetapi juga terasa agak aneh (dan berpotensi berbahaya?) Untuk memodifikasi Intentyang digunakan untuk meluncurkan aktivitas saat ini. Jadi saya mencari sumber untuk Android itu sendiri dan menemukan bahwa mereka selalu membuat yang baru Intentuntuk digunakan sebagai hasilnya. Misalnya, github.com/aosp-mirror/platform_frameworks_base/blob/…
spaaarky21
Halo spaaarky21, terima kasih atas komentar Anda. Saya minta maaf saya tidak begitu jelas dalam menjelaskan bagaimana saya berakhir dengan solusi itu. Itu tiga tahun yang lalu, dan saya hanya dapat mengingat bahwa aplikasi saya mogok karena "Maksud baru", itulah yang saya maksud ketika saya berkata "Saya mengalami masalah dengan". Sebenarnya saya hanya mencoba dengan "getIntent", karena itu masuk akal pada saat itu, dan itu berhasil! Karena itu saya memutuskan untuk membagikan solusi saya. Mungkin bukan pilihan kata terbaik untuk mengatakan "cara terbaik" atau "cara yang benar", tetapi saya mendukung solusi saya. Itulah yang memecahkan masalah saya dan juga orang lain. Terima kasih
Julian Alberto
1
Wow! bekerja dengan baik. getIntent()tampaknya menjadi cara sempurna untuk mengembalikan data ke aktivitas yang tidak dikenal, dari mana aktivitas tersebut dipanggil. Terima kasih!
sam
43

Contoh

Untuk melihat keseluruhan proses dalam konteks, berikut ini adalah jawaban tambahan. Lihat jawaban lengkap saya untuk penjelasan lebih lanjut.

masukkan deskripsi gambar di sini

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
sumber
Bisakah ini dilakukan oleh dua aplikasi A dan aplikasi b yang berbeda? stackoverflow.com/questions/52975645/…
Jerry Abraham
12

Bagi mereka yang memiliki masalah dengan requestCode yang salah di onActivityResult

Jika Anda menelepon startActivityForResult()dari Anda Fragment, requestCode diubah oleh Activity yang memiliki Fragment.

Jika Anda ingin mendapatkan kode hasil yang benar dalam aktivitas Anda, coba ini:

Perubahan:

startActivityForResult(intent, 1); Untuk:

getActivity().startActivityForResult(intent, 1);

Tomasz Mularczyk
sumber
10

Jika Anda ingin memperbarui antarmuka pengguna dengan hasil aktivitas, Anda tidak dapat menggunakan this.runOnUiThread(new Runnable() {} Melakukan ini, UI tidak akan menyegarkan dengan nilai baru. Sebagai gantinya, Anda dapat melakukan ini:

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

Ini terlihat konyol tetapi bekerja cukup baik.

DaviF
sumber
2

Pertama Anda menggunakan startActivityForResult()dengan parameter di pertama Activitydan jika Anda ingin mengirim data dari kedua Activityke pertama Activitykemudian melewati nilai menggunakan Intentdengan setResult()metode dan mendapatkan data di dalam onActivityResult()metode terlebih dahulu Activity.

Dharmendra Pratap
sumber
1

Masalah yang sangat umum di android
Ini dapat dipecah menjadi 3 Buah
1) mulai Kegiatan B (Terjadi dalam Kegiatan A)
2) Tetapkan data yang diminta (Terjadi dalam kegiatan B)
3) Menerima data yang diminta (Terjadi dalam kegiatan A)

1) startActivity B

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

2) Mengatur data yang diminta

Di bagian ini, Anda memutuskan apakah Anda ingin mengirim kembali data atau tidak ketika peristiwa tertentu terjadi.
Misalnya: Dalam aktivitas B ada EditText dan dua tombol b1, b2.
Mengklik Tombol b1 mengirim data kembali ke aktivitas A
Mengklik Tombol b2 tidak mengirim data apa pun.

Mengirim data

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

Tidak mengirim data

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

pengguna mengklik tombol kembali
Secara default, hasilnya ditetapkan dengan kode respons Activity.RESULT_CANCEL

3) Ambil hasil

Untuk itu timpa metode 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 
}
}
Rohit Singh
sumber
1

ActivityResultRegistry adalah pendekatan yang direkomendasikan

ComponentActivitysekarang menyediakan ActivityResultRegistryyang memungkinkan Anda menangani startActivityForResult()+ onActivityResult()serta requestPermissions()+ onRequestPermissionsResult()mengalir tanpa mengesampingkan metode di Activityatau Fragment, membawa peningkatan keamanan jenis melaluiActivityResultContract , dan menyediakan kait untuk menguji aliran ini.

Sangat disarankan untuk menggunakan API Hasil Aktivitas yang diperkenalkan di AndroidX Activity 1.2.0-alpha02 dan Fragment 1.3.0-alpha02.

Tambahkan ini ke 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"

Bagaimana cara menggunakan kontrak pra-bangun?

API baru ini memiliki fungsionalitas pra dibangun berikut

  1. TakeVideo
  2. PickContact
  3. GetContent
  4. GetContents
  5. OpenDocument
  6. OpenDocuments
  7. OpenDocumentTree
  8. Buat Dokumen
  9. Panggil
  10. Mengambil gambar
  11. PermintaanPermission
  12. RequestPermissions

Contoh yang menggunakan kontrak 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() }
       }

Jadi apa yang terjadi di sini? Mari kita memecahnya sedikit. takePicturehanyalah panggilan balik yang mengembalikan Bitmap yang dapat dibatalkan - apakah atau tidak itu null tergantung pada apakah onActivityResultprosesnya berhasil atau tidak . prepareCallkemudian daftarkan panggilan ini ke fitur baru yang ComponentActivitydisebut ActivityResultRegistry- kami akan kembali ke sini nanti. ActivityResultContracts.TakePicture()adalah salah satu pembantu bawaan yang dibuat Google untuk kami, dan akhirnya memohon takePicturesebenarnya memicu Intent dengan cara yang sama seperti sebelumnya Activity.startActivityForResult(intent, REQUEST_CODE).

Bagaimana cara menulis kontrak khusus?

Kontrak sederhana yang menggunakan Int sebagai Input dan mengembalikan String yang meminta Aktivitas mengembalikan pada Intent hasil.

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

Periksa dokumentasi resmi ini untuk informasi lebih lanjut.

Sayang
sumber
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
sumber