Как дождаться завершения onActivityResult?

У меня есть фрагмент, который не следует открывать, если пользователь НЕ одобряет активацию Bluetooth, которая запрашивается с помощью этого фрагмента кода.

    Intent mIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
        mIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 240);
            startActivityForResult(mIntent, 1);
    //Here I want to exit the method in case result is denied
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.content,new ServerFragment()).addToBackStack(null).commit();

Я искал довольно много мест, и единственное, что я нашел, это использовать setResult из нового действия (в моем случае onActivityResult переопределяется в вызывающем действии, поскольку этот код находится внутри фрагмента)

Любые идеи?

Спасибо!

EDIT: вот трассировка стека

java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=131073, result=240, data=null} to activity {bt.bt/bt.bt.MainActivity}: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
                                                                               at android.app.ActivityThread.deliverResults(ActivityThread.java:3659)
                                                                               at android.app.ActivityThread.handleSendResult(ActivityThread.java:3702)
                                                                               at android.app.ActivityThread.access$1300(ActivityThread.java:155)
                                                                               at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1366)
                                                                               at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                               at android.os.Looper.loop(Looper.java:135)
                                                                               at android.app.ActivityThread.main(ActivityThread.java:5343)
                                                                               at java.lang.reflect.Method.invoke(Native Method)
                                                                               at java.lang.reflect.Method.invoke(Method.java:372)
                                                                               at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
                                                                               at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
                                                                            Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState



Ответы (3)


Я думаю, вы должны использовать BroadcastReceiver для регистрации события Bluetooth. В ваш Manifest.xml вам нужно добавить два оператора:

<uses-permission android:name="android.permission.BLUETOOTH" />
<receiver android:name=".BluetoothBroadcastReceiver"
              android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
 </intent-filter>
    </receiver>

Затем вам нужно реализовать метод onReceive():

public void onReceive(Context context, Intent intent) {

    String action = intent.getAction();
    Log.d("BroadcastActions", "Action "+action+"received");
    int state;
    BluetoothDevice bluetoothDevice;

    switch(action)
    {
        case BluetoothAdapter.ACTION_STATE_CHANGED:
            state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
            if (state == BluetoothAdapter.STATE_OFF)
            {
                Toast.makeText(context, "Bluetooth is off", Toast.LENGTH_SHORT).show();
                Log.d("BroadcastActions", "Bluetooth is off");
            }
            else if (state == BluetoothAdapter.STATE_TURNING_OFF)
            {
                Toast.makeText(context, "Bluetooth is turning off", Toast.LENGTH_SHORT).show();
                Log.d("BroadcastActions", "Bluetooth is turning off");
            }
            else if(state == BluetoothAdapter.STATE_ON)
            {
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.content,new ServerFragment()).addToBackStack(null).commit();
                Log.d("BroadcastActions", "Bluetooth is on");
            }
            break;

....
}

Вы можете увидеть больше по этой ссылке: Захват событий Bluetooth Broadcast Receiver Android

person NhatVM    schedule 04.03.2016

Вы должны просто вернуться в свою функцию после запуска намерения. Затем вы ждете обратного вызова в onActivityResult. В этом методе, если результат RESULT_OK, вы запустите свой фрагмент.

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == your_request_code_here) {
        if (resultCode != Activity.RESULT_CANCELED) {
            // start fragment
        }
    }
}

Полная активность:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent mIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
                mIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 240);
                startActivityForResult(mIntent, 1);
            }
        });
    }

    @Override
    public void onPause() {
        super.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == 1) {
            if (resultCode != Activity.RESULT_CANCELED) {

            }
        }
    }
}
person Francesc    schedule 04.03.2016
comment
Это не сработает, потому что onActivityResult является асинхронным, то есть вызывающий фрагмент не будет ждать результата, а продолжит выполнение. Если я попытаюсь добавить на экран новый фрагмент из onActivityResult, будет сгенерировано исключение IllegalStateException. - person Stefan; 04.03.2016
comment
Пожалуйста, опубликуйте свой код и трассировку стека. Это стандартный способ обработки таких запросов. - person Francesc; 04.03.2016
comment
Выложил, посмотри - person Stefan; 04.03.2016
comment
Попробуйте следующее: в onActivityResult установите логическое значение true (чтобы указать, что вы должны запустить фрагмент). Затем в onResume вы проверяете это логическое значение, если оно истинно, вы запускаете фрагмент и сбрасываете значение на false. - person Francesc; 04.03.2016
comment
Проблема в том, что я вызываю startActivityForResult из фрагмента, поэтому onSaveInstance или onResume не вызываются (поскольку просмотр не поставлен на паузу) - person Stefan; 04.03.2016
comment
Как можно не приостанавливать просмотр, если вы начинаете новую активность? Я не уверен, что следую. Не могли бы вы опубликовать больше своего кода, чтобы мы увидели поток? - person Francesc; 04.03.2016
comment
startActivityForResult использует встроенную функцию, она запускает диалог через Intent с запросом на обнаружение Bluetooth. Это АСИНХРОННО, поэтому ничего не приостанавливается. Это часть активности, в которой размещается фрагмент, вызывающий startActivityForResult. - person Stefan; 04.03.2016
comment
Я создал тестовое приложение (см. обновленный ответ выше). Когда я нажимаю кнопку, вызывается onPause (активность приостанавливается, пока отображается диалоговое окно). Когда я соглашаюсь включить BT, вызывается onActivityResult, а затем onResume, как и ожидалось. Если вы видите что-то другое, вам придется опубликовать свой код, чтобы мы могли вам помочь. - person Francesc; 04.03.2016
comment
Кажется, я этого не видел. Тем не менее, после попытки вызвать фрагмент замены в onResume возникает то же самое IllegalStateException - person Stefan; 04.03.2016
comment
Без всего кода я больше ничем помочь не могу, может быть, другие скинутся. - person Francesc; 04.03.2016

Как и в вставленном вами коде, вы создаете экземпляр фрагмента, как только вы вызываете startActivityForResult(), вам не нужно этого делать - это вызывает проблему. Вам просто нужно startActivityForResult(), а затем в своем методе onActivityResult() в своей деятельности вы можете создать экземпляр своего фрагмента, если resultCode равен RESULT_OK

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == your_request_code_here) {
        if (resultCode == Activity.RESULT_OK) {

getSupportFragmentManager().beginTransaction().replace(R.id.content,new ServerFragment()).addToBackStack(null).commit();
        }
    }
}
person Shadab Ansari    schedule 04.03.2016
comment
Посмотрите на трассировку стека - person Stefan; 04.03.2016