如何在Android上管理startActivityForResult?

时间:2012-05-02 03:03:01

标签: android android-intent android-activity startactivityforresult

在我的活动中,我通过startActivityForResult从主要活动中调用了第二个活动。在我的第二个活动中,有一些方法可以完成此活动(可能没有结果),但是,只有其中一个返回结果。

例如,从主要活动我称之为第二个。在这项活动中,我正在检查手机的某些功能,例如是否有相机。如果没有,那么我将关闭此活动。此外,在准备MediaRecorderMediaPlayer期间,如果出现问题,我将关闭此活动。

如果其设备有摄像头并完全录制,则在用户点击完成按钮后录制视频后,我会将结果(录制视频的地址)发送回主要活动。

如何检查主要活动的结果?

13 个答案:

答案 0 :(得分:2272)

FirstActivity使用SecondActivity方法<{1}}致电startActivityForResult()

例如:

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

SecondActivity中设置要返回FirstActivity的数据。如果您不想返回,请不要设置任何。

例如:如果要发回数据,请在SecondActivity中:

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

如果您不想返回数据:

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

现在,在FirstActivity课程中,请为onActivityResult()方法编写以下代码。

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    if (requestCode == 1) {
        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 :(得分:46)

  

如何检查主要活动的结果?

您需要覆盖Activity.onActivityResult(),然后检查其参数:

  • requestCode标识哪个应用返回了这些结果。这是由您在致电startActivityForResult()
  • 时定义的
  • resultCode会通知您此应用是否成功,失败或其他不同
  • data保存此应用返回的所有信息。这可能是null

答案 2 :(得分:40)

补充@ Nishant的答案,返回活动结果的最佳方法是:

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

我遇到了

的问题
new Intent();

然后我发现正确的方法是使用

getIntent();

获取当前意图

答案 3 :(得分:35)

示例

要在上下文中查看整个过程,这是一个补充答案。有关详细说明,请参阅my fuller answer

enter image description here

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

答案 4 :(得分:11)

对于那些遇到wrong requestCode in onActivityResult

问题的人

如果您从startActivityForResult()呼叫Fragment,则拥有该片段的活动会更改requestCode。

如果您想在活动中获得正确的resultCode,请尝试以下方法:

变化:

startActivityForResult(intent, 1);致:

getActivity().startActivityForResult(intent, 1);

答案 5 :(得分:10)

如果要使用活动结果更新用户界面,则无法使用this.runOnUiThread(new Runnable() {} 这样,UI就不会刷新新值。相反,你可以这样做:

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

这看似愚蠢但效果很好。

答案 6 :(得分:7)

建议使用ActivityResultRegistry

ComponentActivity现在提供了一个ActivityResultRegistry,可让您处理startActivityForResult() + onActivityResult()以及requestPermissions() + onRequestPermissionsResult()流而无需重写方法在您的ActivityFragment中,通过ActivityResultContract增强了类型安全性,并提供了用于测试这些流的钩子。

强烈建议使用AndroidX Activity 1.2.0-alpha02和Fragment 1.3.0-alpha02中引入的Activity Result API。

将此添加到您的build.gradle

def activity_version = "1.2.0-beta01"

// Java language implementation
implementation "androidx.activity:activity:$activity_version"
// Kotlin
implementation "androidx.activity:activity-ktx:$activity_version"

如何使用预建合同?

此新API具有以下预先构建的功能

  1. TakeVideo
  2. PickContact
  3. GetContent
  4. GetContents
  5. OpenDocument
  6. OpenDocuments
  7. OpenDocumentTree
  8. CreateDocument
  9. 拨号
  10. TakePicture
  11. RequestPermission
  12. RequestPermissions

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

那么这是怎么回事?让我们稍微细分一下。 takePicture只是一个回调,它返回可为空的位图-是否为空取决于onActivityResult处理是否成功。 prepareCall,然后将此调用注册到ComponentActivity上名为ActivityResultRegistry的新功能中-我们稍后再讲。 ActivityResultContracts.TakePicture()是Google为我们创建的内置帮助程序之一,最终调用takePicture实际上会像以前使用Activity.startActivityForResult(intent, REQUEST_CODE)一样触发Intent。

如何编写自定义合同?

以Int作为输入并返回请求活动的String的简单协定将在结果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)
        }
    }
}

查看this官方文档以了解更多信息。

答案 7 :(得分:5)

startActivityForResult:已在 Android X 中弃用

对于方式,我们有registerForActivityResult

在 Java 中:

 // You need to create a launcher variable inside onAttach or onCreate or global, i.e, before the activity is displayed
 ActivityResultLauncher<Intent> launchSomeActivity = registerForActivityResult(
     new ActivityResultContracts.StartActivityForResult(),
     new ActivityResultCallback<ActivityResult>() {
              @Override
              public void onActivityResult(ActivityResult result) {
                   if (result.getResultCode() == Activity.RESULT_OK) {
                         Intent data = result.getData();
                         // your operation....
                    }
               }
      });

      public void openYourActivity() {
            Intent intent = new Intent(this, SomeActivity.class);
            launchSomeActivity.launch(intent);
      }

在 Kotlin 中:

var resultLauncher = registerForActivityResult(StartActivityForResult()) { result ->
    if (result.resultCode == Activity.RESULT_OK) {
        val data: Intent? = result.data
        // your operation...
    }
}

fun openYourActivity() {
    val intent = Intent(this, SomeActivity::class.java)
    resultLauncher.launch(intent)
}

优势:

  1. 新方法是降低我们在从片段或另一个活动中调用活动时所面临的复杂性
  2. 轻松请求任何许可并获得回电

答案 8 :(得分:2)

首先,您将startActivityForResult()与参数放在第一个Activity中,如果您想将数据从第二个Activity发送到第一个Activity,则使用Intent传递值使用setResult()方法,并在onActivityResult()中的Activity方法中获取该数据。

答案 9 :(得分:2)

我会在简短回答中用androidx发布新的“方法”(因为在某些情况下,您不需要自定义注册表或合同)。如果您需要更多信息,请参见:https://developer.android.com/training/basics/intents/result

重要:实际上存在一个与androidx向后兼容的bug,因此您必须在gradle文件中添加fragment_version否则,您将收到一个异常“新结果API错误:只能将低16位用于requestCode”。

dependencies {

    def activity_version = "1.2.0-beta01"
    // Java language implementation
    implementation "androidx.activity:activity:$activity_version"
    // Kotlin
    implementation "androidx.activity:activity-ktx:$activity_version"

    def fragment_version = "1.3.0-beta02"
    // Java language implementation
    implementation "androidx.fragment:fragment:$fragment_version"
    // Kotlin
    implementation "androidx.fragment:fragment-ktx:$fragment_version"
    // Testing Fragments in Isolation
    debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
}

现在,您只需要添加活动的此成员变量。这使用了预定义的注册表和通用合同。

public class MyActivity extends AppCompatActivity{

   ...

    /**
     * Activity callback API.
     */
    // https://developer.android.com/training/basics/intents/result
    private ActivityResultLauncher<Intent> mStartForResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),

            new ActivityResultCallback<ActivityResult>() {

                @Override
                public void onActivityResult(ActivityResult result) {
                    switch (result.getResultCode()) {
                        case Activity.RESULT_OK:
                            Intent intent = result.getData();
                            // Handle the Intent
                            Toast.makeText(MyActivity.this, "Activity returned ok", Toast.LENGTH_SHORT).show();
                            break;
                        case Activity.RESULT_CANCELED:
                            Toast.makeText(MyActivity.this, "Activity canceled", Toast.LENGTH_SHORT).show();
                            break;
                    }
                }
            });

在使用新API之前:

btn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MyActivity .this, EditActivity.class);
                startActivityForResult(intent, Constants.INTENT_EDIT_REQUEST_CODE);
            }
        });

您可能会注意到,请求代码现在由google框架生成(并保留)。 您的代码成为。

 btn.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(MyActivity .this, EditActivity.class);
                    mStartForResult.launch(intent);
                }
            });

希望我的回答对某些人有帮助!

答案 10 :(得分:1)

android中非常常见的问题 可分为3件
1)开始活动B(在活动A中发生)
2)设置请求的数据(在活动B中发生)
3)接收请求的数据(在活动A中发生)

  

1)startActivity B

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

2)设置请求的数据

在此部分中,您决定是否要在特定事件发生时发回数据 例如:在活动B中有一个EditText和两个按钮b1,b2 单击按钮b1将数据发送回活动A
单击按钮b2不会发送任何数据。

发送数据

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

不发送数据

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

用户点击后退按钮
默认情况下,结果使用Activity.RESULT_CANCEL响应代码

设置
  

3)检索结果

对于覆盖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 
}
}

答案 11 :(得分: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{

}
}

答案 12 :(得分:0)

在您的主要活动中

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    findViewById(R.id.takeCam).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent=new Intent(getApplicationContext(),TakePhotoActivity.class);
            intent.putExtra("Mode","Take");
            startActivity(intent);
        }
    });
    findViewById(R.id.selectGal).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent=new Intent(getApplicationContext(),TakePhotoActivity.class);
            intent.putExtra("Mode","Gallery");
            startActivity(intent);
        }
    });
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

}

要显示的第二个活动

private static final int CAMERA_REQUEST = 1888;
private ImageView imageView;
private static final int MY_CAMERA_PERMISSION_CODE = 100;
private static final int PICK_PHOTO_FOR_AVATAR = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_take_photo);

    imageView=findViewById(R.id.imageView);

    if(getIntent().getStringExtra("Mode").equals("Gallery"))
    {
        pickImage();
    }
    else {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.CAMERA}, MY_CAMERA_PERMISSION_CODE);
            } else {
                Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                startActivityForResult(cameraIntent, CAMERA_REQUEST);
            }
        }
    }
}
public void pickImage() {
    Intent intent = new Intent(Intent.ACTION_PICK);
    intent.setType("image/*");
    startActivityForResult(intent, PICK_PHOTO_FOR_AVATAR);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
{
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == MY_CAMERA_PERMISSION_CODE)
    {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
        {
            Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(cameraIntent, CAMERA_REQUEST);
        }
        else
        {
            Toast.makeText(this, "Camera Permission Denied..", Toast.LENGTH_LONG).show();
        }
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == CAMERA_REQUEST && resultCode == Activity.RESULT_OK) {
        Bitmap photo = (Bitmap) data.getExtras().get("data");
        imageView.setImageBitmap(photo);
    }
        if (requestCode == PICK_PHOTO_FOR_AVATAR && resultCode == Activity.RESULT_OK) {
            if (data == null) {
                Log.d("ABC","No Such Image Selected");
                return;
            }
            try {
                Uri selectedData=data.getData();
                Log.d("ABC","Image Pick-Up");
                imageView.setImageURI(selectedData);
                InputStream inputStream = getApplicationContext().getContentResolver().openInputStream(selectedData);
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                Bitmap bmp=MediaStore.Images.Media.getBitmap(getContentResolver(),selectedData);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch(IOException e){

            }
    }
}