Làm cách nào để quản lý startActivityForResult trên Android?


969

Trong hoạt động của mình, tôi đang gọi một hoạt động thứ hai từ hoạt động chính bằng startActivityForResult. Trong hoạt động thứ hai của tôi, có một số phương pháp kết thúc hoạt động này (có thể không có kết quả), tuy nhiên, chỉ một trong số chúng trả về một kết quả.

Ví dụ, từ hoạt động chính, tôi gọi một hoạt động thứ hai. Trong hoạt động này, tôi đang kiểm tra một số tính năng của thiết bị cầm tay, chẳng hạn như nó có camera không. Nếu nó không có thì tôi sẽ đóng hoạt động này. Ngoài ra, trong quá trình chuẩn bị MediaRecorderhoặc MediaPlayernếu có vấn đề xảy ra thì tôi sẽ đóng hoạt động này.

Nếu thiết bị của nó có camera và ghi âm được thực hiện hoàn toàn, thì sau khi quay video nếu người dùng nhấp vào nút thực hiện thì tôi sẽ gửi kết quả (địa chỉ của video đã ghi) trở lại hoạt động chính.

Làm cách nào để kiểm tra kết quả từ hoạt động chính?


Câu trả lời:


2447

Từ FirstActivitycuộc gọi của bạn , phương thức SecondActivitysử dụng startActivityForResult()

Ví dụ:

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

Trong SecondActivitytập hợp của bạn , dữ liệu mà bạn muốn quay trở lại FirstActivity. Nếu bạn không muốn quay lại, đừng đặt bất kỳ.

Ví dụ: Trong SecondActivitynếu bạn muốn gửi lại dữ liệu:

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

Nếu bạn không muốn trả lại dữ liệu:

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

Bây giờ trong FirstActivitylớp của bạn viết mã sau đây cho onActivityResult()phương thức.

@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

Để triển khai truyền dữ liệu giữa hai hoạt động theo cách tốt hơn nhiều trong Kotlin, vui lòng đi qua liên kết này ' Cách tốt hơn để truyền dữ liệu giữa các Hoạt động '


1
Mục đích của việc đưa ra một ý định khi RESUT_CANCELLED trong setResult (RESULT_CANCELED, returnIntent);
Ismail Sahin

4
@ismail Giả sử trong SecondActivitytrường hợp ngoại lệ nào đó xảy ra, trong trường hợp đó bạn cũng cần trả kết quả về FirstActivity, vì vậy bạn có thể đặt kết quả như "RESULT_CANCELLED"trong khối bắt và quay lại FirstActivtyvà trong đó FirstActivity's' 'onActivityResult()bạn có thể kiểm tra xem bạn có kết quả thành công hay thất bại hay không.
Nishant

10
Vì vậy, tùy thuộc vào bạn, nếu bạn không cần biết lý do hủy, bạn có thể sử dụng chỉ setResult (RESULT_CANCELED); không có bất kỳ ý định nào
Ismail Sahin

2
@Lei Leyba Không kết thúc () không được gọi sau khi gọi startActivityForResult (). First Actvity sẽ chuyển sang trạng thái tạm dừng.
Nishant

6
Đối với tôi nó không hoạt động -.- đây là điều tôi ghét rất nhiều về Android - hệ thống này rất không đáng tin cậy: - /
Martin Pfeffer

50

Làm thế nào để kiểm tra kết quả từ hoạt động chính?

Bạn cần ghi đè Activity.onActivityResult()sau đó kiểm tra các tham số của nó:

  • requestCodexác định ứng dụng nào trả về những kết quả này. Điều này được xác định bởi bạn khi bạn gọi startActivityForResult().
  • resultCode thông báo cho bạn biết ứng dụng này đã thành công, thất bại hay có gì đó khác biệt
  • datagiữ bất kỳ thông tin nào được trả về bởi ứng dụng này. Đây có thể là null.

Nó có nghĩa là requestCode chỉ được sử dụng trong hoạt động đầu tiên và nó không bao giờ được sử dụng cho hoạt động thứ 2? Nếu hoạt động thứ 2 có các cách tiếp cận khác nhau, nó sẽ thay đổi, nhưng dựa trên các bổ sung ý định chứ không phải bởi requestCode, phải không? Chỉnh sửa: Có, stackoverflow.com/questions/5104269/
Mạnh

44

Bổ sung câu trả lời từ @ Nishant, cách tốt nhất để trả về kết quả hoạt động là:

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

Tôi đã có vấn đề với

new Intent();

Sau đó tôi phát hiện ra rằng cách sử dụng đúng

getIntent();

để có được ý định hiện tại


Cảm thấy hơi kỳ quặc khi tạo một cái mới Intentchỉ tồn tại để giữ Bundlevà không có các giá trị bình thường như một hành động hoặc thành phần. Nhưng nó cũng cảm thấy một chút kỳ lạ (và có khả năng nguy hiểm?) Để sửa đổi Intentcái đã được sử dụng để khởi chạy hoạt động hiện tại. Vì vậy, tôi đã tìm kiếm nguồn cho chính Android và thấy rằng họ luôn tạo một cái mới Intentđể sử dụng làm kết quả. Ví dụ: github.com/aosp-mirror/pl
platform_frameworks_base / blog /

Xin chào spaaarky21, cảm ơn bạn đã bình luận. Tôi xin lỗi tôi đã không rõ ràng trong việc giải thích chính xác làm thế nào tôi kết thúc với giải pháp đó. Đó là ba năm trước và tôi chỉ có thể nhớ rằng ứng dụng của mình đã bị sập vì "Ý định mới", đó là điều tôi muốn nói khi tôi nói "Tôi gặp vấn đề với". Thật ra tôi chỉ thử với "getIntent", bởi vì nó có ý nghĩa vào thời điểm đó, và nó đã hoạt động! Vì nó tôi quyết định chia sẻ giải pháp của mình. Có thể không phải là lựa chọn tốt nhất để nói "cách tốt nhất" hay "cách chính xác", nhưng tôi đứng trước giải pháp của mình. Đó là những gì đã giải quyết vấn đề của tôi và cả những người khác. Cảm ơn
Julian Alberto

1
Ồ làm việc tuyệt vời getIntent()dường như là một cách hoàn hảo để trả lại dữ liệu cho hoạt động không được biết đến, từ đó hoạt động được gọi. Cảm ơn!
sam

43

Thí dụ

Để xem toàn bộ quá trình trong bối cảnh, đây là một câu trả lời bổ sung. Xem câu trả lời đầy đủ hơn của tôi để giải thích thêm.

nhập mô tả hình ảnh ở đây

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

Thứ haiActivity.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();
    }
}

Điều này có thể được thực hiện bởi hai ứng dụng A và ứng dụng b khác nhau không? stackoverflow.com/questions/52975645/
Jerry Abraham

12

Đối với những người có vấn đề với sai trong onActivityResult

Nếu bạn đang gọi startActivityForResult()từFragment , mã yêu cầu được thay đổi bởi Hoạt động sở hữu Đoạn.

Nếu bạn muốn nhận được mã kết quả chính xác trong hoạt động của mình, hãy thử điều này:

Thay đổi:

startActivityForResult(intent, 1); Đến:

getActivity().startActivityForResult(intent, 1);


10

Nếu bạn muốn cập nhật giao diện người dùng với kết quả hoạt động, bạn không thể sử dụng this.runOnUiThread(new Runnable() {} Làm điều này UI sẽ không làm mới với giá trị mới. Thay vào đó, bạn có thể làm điều này:

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

Điều này có vẻ ngớ ngẩn nhưng hoạt động khá tốt.


2

Trước tiên, bạn sử dụng startActivityForResult()với các thông số trong lần đầu tiên Activityvà nếu bạn muốn gửi dữ liệu từ thứ hai Activityđến đầu tiên Activitysau đó vượt qua giá trị sử dụng Intentvới setResult()phương pháp và nhận được rằng dữ liệu bên trong onActivityResult()phương pháp trong lần đầu tiên Activity.


1

Vấn đề rất phổ biến trong Android
Nó có thể được chia thành 3 Phần
1) bắt đầu Hoạt động B (Xảy ra trong Hoạt động A)
2) Đặt dữ liệu được yêu cầu (Xảy ra trong hoạt động B)
3) Nhận dữ liệu được yêu cầu (Xảy ra trong hoạt động A)

1) bắt đầu Hoạt động B

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

2) Đặt dữ liệu được yêu cầu

Trong phần này, bạn quyết định xem bạn có muốn gửi lại dữ liệu hay không khi một sự kiện cụ thể xảy ra.
Vd: Trong hoạt động B có một EditText và hai nút b1, b2.
Nhấp vào nút b1 sẽ gửi dữ liệu trở lại hoạt động A
Nhấp vào nút b2 không gửi bất kỳ dữ liệu nào.

Gửi dữ liệu

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

Không gửi dữ liệu

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

Người dùng nhấp vào nút quay lại
Theo mặc định, kết quả được đặt với mã phản hồi Activity.RESULT_CANCEL

3) Lấy kết quả

Cho rằng ghi đè lên phương thức 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à cách tiếp cận được đề xuất

ComponentActivityhiện cung cấp một ActivityResultRegistrycho phép bạn xử lý startActivityForResult()+ onActivityResult()cũng như requestPermissions()+onRequestPermissionsResult() chảy mà không trọng phương pháp trong bạn Activityhay Fragment, mang đến tăng độ an toàn loại qua ActivityResultContract, và cung cấp móc để thử nghiệm những dòng chảy.

Chúng tôi khuyên bạn nên sử dụng API kết quả hoạt động được giới thiệu trong AndroidX Activity 1.2.0-alpha02 và Fragment 1.3.0-alpha02.

Thêm cái này vào 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"

Làm thế nào để sử dụng hợp đồng xây dựng trước?

API mới này có các chức năng được xây dựng trước như sau

  1. Video
  2. PickContact
  3. Có được nội dung
  4. GetContents
  5. OpenDocument
  6. OpenDocument
  7. OpenDocumentTree
  8. TạoDocument
  9. Quay số
  10. Chụp ảnh
  11. Xin phep
  12. RequestPermissions

Một ví dụ sử dụng hợp đồng 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() }
       }

Vậy chuyện gì đang xảy ra ở đây? Hãy phá vỡ nó một chút. takePicturechỉ là một cuộc gọi lại trả về một Bitmap không thể thực hiện được - việc nó có rỗng hay không phụ thuộc vào việc onActivityResultquá trình có thành công hay không . prepareCallsau đó đăng ký cuộc gọi này vào một tính năng mới ComponentActivityđược gọi là ActivityResultRegistry- chúng tôi sẽ quay lại vấn đề này sau. ActivityResultContracts.TakePicture()là một trong những trợ giúp tích hợp mà Google đã tạo cho chúng tôi và cuối cùng gọi takePicturethực sự kích hoạt Ý định theo cách mà bạn đã làm trước đây Activity.startActivityForResult(intent, REQUEST_CODE).

Làm thế nào để viết một hợp đồng tùy chỉnh?

Hợp đồng đơn giản lấy Int làm Đầu vào và trả về Chuỗi yêu cầu Activity trả về kết quả Ý định.

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

Kiểm tra tài liệu chính thức này để biết thêm.


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{

}
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.