Como gerenciar o startActivityForResult no Android?

969

Na minha atividade, estou chamando uma segunda atividade da atividade principal por startActivityForResult. Na minha segunda atividade, existem alguns métodos que finalizam essa atividade (talvez sem resultado), no entanto, apenas um deles retorna um resultado.

Por exemplo, da atividade principal, chamo de segunda. Nesta atividade, estou verificando alguns recursos do aparelho, como se ele tivesse uma câmera. Se não tiver, fecharei esta atividade. Além disso, durante a preparação MediaRecorderou MediaPlayerse ocorrer um problema, fecharei esta atividade.

Se o dispositivo tiver uma câmera e a gravação for concluída completamente, depois de gravar um vídeo, se um usuário clicar no botão Concluído, enviarei o resultado (endereço do vídeo gravado) de volta à atividade principal.

Como verifico o resultado da atividade principal?

Hesam
fonte

Respostas:

2447

Na sua FirstActivitychamada, o SecondActivityuso startActivityForResult() método

Por exemplo:

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

No seu SecondActivityconjunto, os dados aos quais você deseja retornarFirstActivity . Se você não quiser voltar, não defina nenhum.

Por exemplo: In, SecondActivityse você deseja enviar dados de volta:

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

Se você não deseja retornar dados:

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

Agora em sua FirstActivityclasse, escreva o código a seguir para o onActivityResult()método

@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

Para implementar a transmissão de dados entre duas atividades de uma maneira muito melhor no Kotlin, acesse este link ' Uma maneira melhor de transmitir dados entre as atividades '

Nishant
fonte
1
Qual é o objetivo de colocar uma intenção quando RESUT_CANCELLED em setResult (RESULT_CANCELED, returnIntent);
Ismail Sahin
4
@ismail Suponha que, em SecondActivityalguma exceção ocorrida, nesse caso também seja necessário retornar o resultado para FirstActivity, para que você possa defini-lo como "RESULT_CANCELLED"no bloco catch e retornar para FirstActivtye para FirstActivity's' 'onActivityResult()verificar se obteve o resultado do êxito ou falha.
Nishant
10
Portanto, depende de você, se você não precisar saber o motivo do cancelamento, poderá usar apenas setResult (RESULT_CANCELED); sem intenção
Ismail Sahin 31/10
2
@Lei Leyba Nenhum finish () não é chamado após chamar startActivityForResult () .O First Actvity passará para o estado de pausa.
Nishant
6
Para mim ele não está funcionando -.- é isso que eu odeio soooo muito sobre Android - este sistema é tão pouco confiável: - /
Martin Pfeffer
50

Como verificar o resultado da atividade principal?

Você precisa substituir Activity.onActivityResult()e verificar seus parâmetros:

  • requestCodeidentifica qual aplicativo retornou esses resultados. Isso é definido por você quando você liga startActivityForResult().
  • resultCode informa se este aplicativo foi bem-sucedido, falhou ou algo diferente
  • datamantém todas as informações retornadas por este aplicativo. Isso pode ser null.
Sam
fonte
Isso significa que o requestCode é usado apenas na primeira atividade e nunca é usado para a segunda atividade? Se a 2ª atividade tiver abordagens diferentes, ela mudará, mas com base nos extras de intenção e não no requestCode, certo? Edit: Sim, stackoverflow.com/questions/5104269/…
JCarlosR
44

Complementando a resposta de @ Nishant, a melhor maneira de retornar o resultado da atividade é:

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

Eu estava tendo problemas com

new Intent();

Então eu descobri que a maneira correta está usando

getIntent();

para obter a intenção atual

Julian Alberto
fonte
Parece um pouco estranho criar um novo Intentque exista apenas para conter um Bundlee não tenha os valores normais, como uma ação ou componente. Mas também parece um pouco estranho (e potencialmente perigoso?) Modificar o Intentque foi usado para iniciar a atividade atual. Então, procurei na fonte o próprio Android e descobri que eles sempre criam um novo Intentpara usar como resultado. Por exemplo, github.com/aosp-mirror/platform_frameworks_base/blob/…
spaaarky21
Olá spaaarky21, obrigado pelo seu comentário. Sinto muito por não ter sido tão claro ao explicar exatamente como acabei com essa solução. Isso foi há três anos e eu só me lembro que meu aplicativo estava travando por causa de "nova Intenção", foi isso que eu quis dizer quando disse "Eu estava tendo problemas". Na verdade, eu apenas tentei com "getIntent", porque fazia sentido na época e funcionou! Por isso, decidi compartilhar minha solução. Talvez não seja a melhor escolha de palavras para dizer "melhor caminho" ou "caminho correto", mas eu mantenho a minha solução. Foi o que resolveu meu problema e, aparentemente, outras pessoas também. Obrigado
Julian Alberto
1
Uau! funciona bem. getIntent()parece ser uma maneira perfeita de retornar dados para atividades desconhecidas, de onde a atividade foi chamada. Obrigado!
sam
43

Exemplo

Para ver todo o processo em contexto, aqui está uma resposta suplementar. Veja minha resposta completa para mais explicações.

insira a descrição da imagem aqui

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
fonte
Isso pode ser feito por dois aplicativos diferentes A e app b? stackoverflow.com/questions/52975645/…
Jerry Abraham
12

Para aqueles que têm problemas com requestCode incorreto onActivityResult

Se você está chamando startActivityForResult()de seu Fragment, o requestCode é alterado pela atividade que possui o fragmento.

Se você deseja obter o resultado correto na sua atividade, tente o seguinte:

Mudança:

startActivityForResult(intent, 1); Para:

getActivity().startActivityForResult(intent, 1);

Tomasz Mularczyk
fonte
10

Se você deseja atualizar a interface do usuário com o resultado da atividade, não é possível usar this.runOnUiThread(new Runnable() {} Fazendo isso, a interface do usuário não será atualizada com novo valor. Em vez disso, você pode fazer isso:

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

Isso parece bobagem, mas funciona muito bem.

DaviF
fonte
2

Primeiro você usa os startActivityForResult()parâmetros primeiro Activitye, se deseja enviar dados do segundo Activityao primeiro Activity, passe o valor usando Intentwith setResult()method e obtenha esses dados dentro do onActivityResult()método primeiro Activity.

Dharmendra Pratap
fonte
1

Problema muito comum no android
Ele pode ser dividido em 3 partes
1) iniciar a atividade B (acontece na atividade A)
2) definir dados solicitados (acontece na atividade B)
3) receber dados solicitados (acontece na atividade A)

1) startActivity B

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

2) Defina os dados solicitados

Nesta parte, você decide se deseja enviar dados de volta ou não quando ocorrer um evento específico.
Ex .: Na atividade B há um EditText e dois botões b1, b2.
Clicar no botão b1 envia os dados de volta à atividade A
Clicar no botão b2 não envia nenhum dado.

Enviando dados

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

Não está enviando dados

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

usuário clica no botão Voltar
Por padrão, o resultado é definido com o código de resposta Activity.RESULT_CANCEL

3) Recuperar resultado

Para essa substituição do método 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
fonte
1

O ActivityResultRegistry é a abordagem recomendada

ComponentActivityagora oferece uma ActivityResultRegistryque lhe permite lidar com o startActivityForResult()+ onActivityResult(), bem como requestPermissions()+ onRequestPermissionsResult()flui sem substituir métodos em sua Activityou Fragment, traz maior segurança Tipo de viaActivityResultContract , e fornece ganchos para testar esses fluxos.

É altamente recomendável usar as APIs de resultado da atividade introduzidas na atividade AndroidX 1.2.0-alpha02 e no fragmento 1.3.0-alpha02.

Adicione isto ao seu 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"

Como usar o contrato pré-construído?

Essa nova API possui as seguintes funcionalidades pré-criadas

  1. TakeVideo
  2. PickContact
  3. Obter conteudo
  4. GetContents
  5. OpenDocument
  6. OpenDocuments
  7. OpenDocumentTree
  8. CreateDocument
  9. Discar
  10. Tire uma foto
  11. RequestPermission
  12. RequestPermissions

Um exemplo que usa o contrato 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() }
       }

Então, o que está acontecendo aqui? Vamos dividir um pouco. takePictureé apenas um retorno de chamada que retorna um bitmap anulável - se é nulo ou não, depende se o onActivityResultprocesso foi ou não bem-sucedido. prepareCalldepois registra essa chamada em um novo recurso ComponentActivitychamado ActivityResultRegistry- voltaremos a isso mais tarde. ActivityResultContracts.TakePicture()é um dos ajudantes internos que o Google criou para nós e, finalmente, a chamada takePicturerealmente aciona a intenção da mesma maneira que você faria anteriormente Activity.startActivityForResult(intent, REQUEST_CODE).

Como escrever um contrato personalizado?

Contrato simples que pega um Int como uma Entrada e retorna uma String que solicitou a Atividade retorna no resultado 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)
        }
    }
}

Verifique esta documentação oficial para mais informações.

Darish
fonte
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
fonte