Last Updated: August 01, 2022
·
10.43K
· philippeauriach

Starting an activity with result the clean way

[IMPORTANT NOTICE] THIS SOLUTION DOES NOT WORK. It was a good idea but in fact it wasn't : the base activity A keep a track of all handlers, so when you start an activity B, and because of memory pressure A is killed, then when B finishWithResult, A is recreated, so it does not have any handlers, and nothing will get called. Please do NOT use this solution.


I didn't like the way Android handles the startActivityForResult and the onActivityResult. It felt wrong to me, so I created a little base class allowing a cleaner way (to my point of view) of doing this.

In other words :

This sucks :

private void onButtonClicked(){
    Intent intent = new intent(this, Activity.class);
    startActivityForResult(intent, MY_REQUEST_CODE);    //we have to keep the request code, who cares ?
}
...
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch(requestCode){
        case MY_REQUEST_CODE: //when did we asked for this ?
            if(resultCode == Activity.RESULT_OK){
                // use data 
            }
    }
}

This is what we want :

private void onButtonClicked(){
    Intent intent = new intent(this, Activity.class);
    startActivityForResult(intent, Activity.RESULT_OK, new SuccessResultHandler() {
        @Override
        public void onResult(Intent data) {
            //here you have your results data. The resultCode has already been checked against Activity.RESULT_OK    
        }
    });
}

To have this feature, just create a base class for all your activities or fragment containing the following :

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by philippeauriach on 18/10/2016.
 */
public class BaseActivity extends AppCompatActivity {

    private Map<Integer, HandlerHolder> resultHandlers = new HashMap<>();
    private AtomicInteger counter = new AtomicInteger(Integer.MIN_VALUE);

    private int getNewRequestCode() {
        return new AtomicInteger().incrementAndGet();
    }

    protected void startActivityForResult(Intent intent, int successResultCode, SuccessResultHandler handler) {
        int requestCode = getNewRequestCode();
        resultHandlers.put(requestCode, new HandlerHolder(successResultCode, handler));
        startActivityForResult(intent, requestCode);
    }

    protected void startActivityForResult(Intent intent, ResultHandler handler) {
        int requestCode = getNewRequestCode();
        resultHandlers.put(requestCode, new HandlerHolder(handler));
        startActivityForResult(intent, requestCode);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        HandlerHolder handler = resultHandlers.get(requestCode);
        if (handler != null) {
            if (handler.successHandler != null) {
                if (resultCode == handler.successResultCode) {
                    handler.successHandler.onResult(data);
                }
                return;
            }
            if (handler.resultHandler != null) {
                handler.resultHandler.onResult(resultCode, data);
                return;
            }
        }
    }

    public interface SuccessResultHandler {
        void onResult(Intent data);
    }

    public interface ResultHandler {
        void onResult(int resultCode, Intent data);
    }

    protected class HandlerHolder {
        private Integer successResultCode;
        private SuccessResultHandler successHandler;
        private ResultHandler resultHandler;

        public HandlerHolder(Integer successResultCode, SuccessResultHandler successHandler) {
            this.successResultCode = successResultCode;
            this.successHandler = successHandler;
        }

        public HandlerHolder(ResultHandler resultHandler) {
            this.resultHandler = resultHandler;
        }
    }
}