Вопрос по service, rest, android – ResultReceiver не сохраняется до поворота экрана

5

Я реализую REST-клиент в Android. Я видел пример использованияService выполнить подключение к серверу иResultReceiver быть уведомленным о завершении операции. Я вызываю сервис из фрагмента и, если я пытаюсь повернуть экран во время работы сервиса, метод getActivity () вResultReceiver возвращает ноль, потому что, вероятно, этот фрагмент больше не находится в макете.

Метод обратного вызова во фрагменте:

@Override
public void onReceiveResult(int resultCode, Bundle resultData) {
    Response response = (Response) resultData
            .getSerializable(RestService.RESULT);
    if (resultCode == RestService.SUCCESS
            && response != null) {
        if (getActivity() != null) {
            recommendationResponse = response;
            getLoaderManager().restartLoader(0, new Bundle(),
                    Fragment.this);
        }

    }
}

getActivity() возвращает ноль Это нормально? Какой подход я могу использовать, чтобы разрешить уведомление даже при повороте экрана? Местная трансляция?

Ваш Ответ

5   ответов
1

что наткнулся на ту же проблему и решил ее, проверив NULL в методе onReceivedResult моего ResultReceiver. Размещенный здесь код работает с рабочим фрагментом (фрагмент без пользовательского интерфейса и setRetainInstance (true) в onCreate)

protected void onReceiveResult(int resultCode, Bundle resultData) {
            //Verify activity
            if(getActivity() != null){
                //Handle result
            }else{
                notificationPending = true;                 
            }
        }

Флаги NotificationPending помогают фрагменту удерживать ожидающее уведомление, если действие не было найдено (Действие недоступно во фрагменте Detach).

Когда фрагмент снова присоединяется к операции, я выполняю эту логику

public void onAttach(Activity activity){
    super.onAttach(activity);
        if(notificationPending){
            //Handle notification
            notificationPending = false;
        }
}

Надеюсь, поможет. Вы можете запросить дополнительную информацию, если хотите. ура

0

Я пытался сохранитьResultReceiver вonSaveInstanceState(), но это не работает, так как обновления, которые происходят во время полученияFragment уничтожается, теряется и ссылки на обратные вызовы тоже.

Объяснение и возможное решение можно найти здесь:https://stanmots.blogspot.com/2016/10/androids-bad-company-intentservice.html

Еще одна хорошая статья об этой проблеме: https://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html

Мое полное решение, как использоватьResultReceiver можно найти здесь: https://stackoverflow.com/a/54334864/6747171

1

BroadcastReceiver зарегистрирован с использованиемLocalBroadcastManager и это работает правильно. Это было не так просто. Существует ли лучшее решение?

12

Нет,

android:configChanges="orientation"

это не решение

Чтобы использовать ResultReceiver I:

save it on orientation changes:

@Override
public void onSaveInstanceState(Bundle outState) {
    outState.putParcelable(Consts.RECEIVER, mReceiver);
    super.onSaveInstanceState(outState);
}

reset the receiver:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {

    if (savedInstanceState != null) {
        mReceiver = savedInstanceState.getParcelable(Consts.RECEIVER);
    }
    else {
        mReceiver = new MyResultReceiver(new Handler());
    }
    mReceiver.setReceiver(this);
}

Вот мой класс ResultReceiver:

import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;

public class MyResultReceiver extends ResultReceiver {
    private Receiver mReceiver;

    public MyResultReceiver(Handler handler) {
        super(handler);
    }

    public void setReceiver(Receiver receiver) {
        mReceiver = receiver;
    }

    public interface Receiver {
        public void onReceiveResult(int command, Bundle resultData);
    }

    @Override
    protected void onReceiveResult(int command, Bundle resultData) {
        if (mReceiver != null) {
            mReceiver.onReceiveResult(command, resultData);
        }
    }
}
Brilliant! Я видел много других похожих вопросов (с большим количеством голосов), связанных сResultReceiverИ любой из них успешно решает такой частый сценарий, как активный отдых.
@ Алан Действительно! В этом есть смысл. Я тут вопрос открыл (stackoverflow.com/q/37439838/3075340) но возможно ли сделать так, чтобы пользовательский ResultReceiver реализовывал пакет или нет ..?
Как избежать исключения ClassCastException в onCreateView () при вызове getParcelable ()? Разве getParcelable () не возвращает экземпляр ResultReceiver (не экземпляр вашего подкласса), потому что ваш подкласс не реализует Parcelable.CREATOR?
@ Алан В моем тестировании, когда вы поворачиваете устройство, вышеописанный метод работает. Однако, если Android выключает приложение в фоновом режиме, и вы запускаете его снова, я получаю ClassCastException в onCreateView (). Я не уверен, почему, но это то, что я нашел из моих испытаний ...
@MicroR Я думаю, это потому, что при вращении Bundle не сериализуется в Parcel, он остается в памяти, и вы получаете исходный объект обратно. Если приложение закрывается (нехватка памяти), пакет, скорее всего, превращается в посылку, в которой вы сталкиваетесь с проблемами повторного извлечения объекта, потому что посылка будет возвращать только базовый ResultReceiver. Я до сих пор не нашел хорошего решения.
-1

Действия Android воссоздаются после поворота устройства.

После того, как действие воссоздано, оно не содержит старого контекста.getActivity() как ноль

What approach could I use to allow notification even on screen rotation? Local Broadcast?

Если вы не хотите, чтобы активность воссоздалась на экране поворота.

        <activity
            android:name=".MyActivity"
            android:configChanges="orientation"    <<<<<<<<<
            android:label="@string/app_name"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

И последнее Вам придется переопределить следующее в Деятельности.

@Override
    public void onConfigurationChanged(Configuration newConfig)
    {
        // TODO Auto-generated method stub
        super.onConfigurationChanged(newConfig);
    }
Спасибо за ответ. На самом деле я бы предпочел не устанавливать screenOrientation на манифест, потому что макет отличается в альбомном режиме, поэтому я не могу установить это. Matroska

Похожие вопросы