Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ResultReceiver doesn't survire to screen rotation

I am implementing a REST client in Android. I have seen an example of using a Service to perform the connection to the server and the ResultReceiver to be notified of the operation completion. I am calling the service from a fragment and, if I try to rotate the screen while the service is running, the getActivity() method in ResultReceiver returns null because probably that fragment is not in layout anymore.

The callback method in the fragment:

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

    }
}

The getActivity() returns null. Is this normal? What approach could I use to allow notification even on screen rotation? Local Broadcast?

like image 302
Matroska Avatar asked Jun 07 '12 07:06

Matroska


3 Answers

No,

android:configChanges="orientation"

is not a solution.

To use 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);
    }
    

Here is my ResultReceiver class:

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);
        }
    }
}
like image 155
blyabtroi Avatar answered Nov 11 '22 21:11

blyabtroi


I am using a BroadcastReceiver registered using LocalBroadcastManager and it is working properly. It wasn't so simple. Does a better solution exist?

like image 43
Matroska Avatar answered Nov 11 '22 22:11

Matroska


I think I stumbled upon the same issue and resolved it by verifying for NULL in the onReceivedResult method of my ResultReceiver. The code posted here works on a worker fragment (fragment without UI and setRetainInstance(true) in onCreate)

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

The notificationPending flags helps the fragment hold the pending notification if the activity was not found (Activity is not available on fragment Detach).

When the fragment reattaches to the activity i perform this logic

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

Hope it helps. You can ask for further details if you like. Cheers

like image 42
Andres Avatar answered Nov 11 '22 22:11

Andres