setResult não funciona quando o botão VOLTAR é pressionado

111

Estou tentando definirResult depois que o botão VOLTAR foi pressionado. Eu chamo onDestroy

Intent data = new Intent();
setResult(RESULT_OK, data) 

Mas quando se trata de

onActivityResult(int requestCode, int resultCode, Intent data) 

o resultCode é 0 (RESULT_CANCELED) e os dados são 'nulos'.

Então, como posso passar o resultado da atividade encerrada pelo botão VOLTAR?

alex2k8
fonte

Respostas:

159

Você precisa substituir o onBackPressed()método e definir o resultado antes da chamada para a superclasse, ou seja,

@Override
public void onBackPressed() {
    Bundle bundle = new Bundle();
    bundle.putString(FIELD_A, mA.getText().toString());
    
    Intent mIntent = new Intent();
    mIntent.putExtras(bundle);
    setResult(RESULT_OK, mIntent);
    super.onBackPressed();
}
n224576
fonte
23
Observe que, se você usar essa abordagem, a invocação super.onBackPressed () deve acontecer após a chamada para setResult () conforme mostrado acima ou você terá o problema original novamente!
jengelsma
1
Essa é a melhor resposta aqui. Se substituirmos onPause () ou onDestroy (), onBackPressed () será chamado primeiro e definirá o resultado como 0. Esteja ciente disso!
Marek
ou você pode definir o resultado padrão em onCreate. Qualquer lugar antes de terminar () está bom.
Helin Wang
5
Implementei uma abordagem semelhante, mas ainda não funciona. Para a instância, tenho o código de solicitação e a intenção funcionando, mas o resultCode é sempre 0.
Neon Warge
68

Activityo resultado deve ser definido antes de finish() ser chamado. Clicar em VOLTAR realmente liga finish()em seu activity, então você pode usar o seguinte snippet:

@Override
public void finish() {
    Intent data = new Intent();
    setResult(RESULT_OK, data); 

    super.finish();
}

Se você ligar NavUtils.navigateUpFromSameTask();no onOptionsItemSelected(), finish()é chamado, mas você vai ter o errado result code. Então, você tem que chamar finish()não navigateUpFromSameTaskno onOptionsItemSelected(). requestCode errado em onActivityResult

JBM
fonte
Isso funciona no caso de OPs, mas não em geral, certo? Existem mais métodos além de finish () que induzem o fim do ciclo de vida do aplicativo (via onPause () e onDestroy ())? Veja também meu comentário na outra resposta.
pjv
E mesmo se não houvesse, você não saberia quando seria introduzido em uma atualização de API. Não tão facilmente como faria quando o comportamento de onPause () ou onDestroy () fosse alterado. Esses são os métodos que você deve substituir.
pjv
6
@pjv - Não entendi, o que finishtem a ver com onPausee onDestroy? Aqueles totalmente não estão relacionados, exceto que finishinicia o processo de rescisão que onPausee onDestroyfazem parte.
JBM
20

Se você quiser definir um costume RESULT_CODEno onBackPressedevento, então você precisa primeiro conjunto a resulte depois chamar o super.onBackPressed()e você receberá o mesmo RESULT_CODEna de atividade chamador onActivityResultmétodo

    @Override
    public void onBackPressed()
    {
         setResult(SOME_INTEGER);
         super.onBackPressed();
    }
Khurram Shehzad
fonte
10

Refatorei meu código. Inicialmente, preparei alguns dados e configurei como activity resultem onDestroy(isso não funcionou). Agora eu defino os activitydados cada vez que os dados a serem retornados são atualizados e não há nada em onDestroy.

alex2k8
fonte
Isso não funciona para mim, pois meus dados são atualizados em "onPause"
Bostone
Se sua atividade for recriada após a ligação setResult(), seus dados serão perdidos.
Jarett Millard de
3

Você deve substituir onOptionsItemSelected assim:

@Override
public boolean onOptionsItemSelected(final MenuItem item) {
    switch (item.getItemId()) {
    case android.R.id.home:
        final Intent mIntent = new Intent();
        mIntent.putExtra("param", "value");
        setResult(RESULT_OK, mIntent);
        finish();
        return true;
    default:
        return super.onOptionsItemSelected(item);
    }
}
mdolanci
fonte
2

Consulte o documento onActivityResult (int, int, Intent)

A solução é verificar o resultCode para o valor Activity.RESULT_CENCELED . Se sim, isso significa que BACK foi pressionado ou a atividade travou. Espero que funcione para vocês, funcione para mim :).

Ankur
fonte
Esta é a solução exata .. Você tem que Código de Resultado .. Ninguém pode definir o resultado além de você no código. Portanto, se o resultado não for OK, significa que ele pressiona de volta ou travou.
John
0

onDestroyestá muito atrasado na cadeia - em vez disso, substitua onPausee isFinishing()verifique se sua atividade está no final de seu ciclo de vida.

Roman Nurik
fonte
1
Não, também é tarde demais.
alex2k8
Na verdade, eu chamo isso de bug: code.google.com/p/android/issues/detail?id=1671 . Em aplicativos complexos, acho que devido a isso, há apenas alguns comportamentos que você não pode programar.
pjv
Também é muito contra-intuitivo. Tanto que continuo cometendo o mesmo erro, já faz 2 anos.
pjv
Na verdade - isso é ainda pior. E existe no JB enquanto estou codificando. Se eu chamar setResult de onPause, ele será executado, mas nether resultCode nem data será definido quando onActivityReturn for executado. Por quê?
Bostone
E é por isso que: "As implementações deste método (onPause) devem ser muito rápidas porque a próxima atividade não será retomada até que este método retorne" goo.gl/8S2Y
Bostone
0

Tente substituir onBackPressed (do Android nível 5 para cima) ou substituir onKeyDown () e capturar KeyEvent.BUTTON_BACK (consulte os resultados de atividades do Android ). Isso funciona para mim.

MrJre
fonte
0

Não confie em nenhuma lógica executada em onPause de uma atividade quando retornar à inicial. De acordo com a documentação:

As implementações deste método (onPause) devem ser muito rápidas porque a próxima atividade não será retomada até que este método retorne

Consulte http://goo.gl/8S2Y para obter detalhes.

A maneira mais segura é definir o resultado após a conclusão de cada operação de alteração de resultado (como você mencionou em sua resposta)

Bostone
fonte
0

Eu colo a resposta pode ser útil para outras pessoas: quando um conjunto launcheMode com android: launchMode = "singleTask" eu também não consigo obter o resultado, o documento diz:

     /* <p>Note that this method should only be used with Intent protocols
 * that are defined to return a result.  In other protocols (such as
 * {@link Intent#ACTION_MAIN} or {@link Intent#ACTION_VIEW}), you may
 * not get the result when you expect.  For example, if the activity you
 * are launching uses the singleTask launch mode, it will not run in your
 * task and thus you will immediately receive a cancel result.
 */

e:

     /* <p>As a special case, if you call startActivityForResult() with a requestCode 
 * >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your
 * activity, then your window will not be displayed until a result is 
 * returned back from the started activity.  This is to avoid visible 
 * flickering when redirecting to another activity. 
 */
banxi1988
fonte