1

For example, assume my app has 3 steps with 3 pages:

Step 1 : MainActivity: choose color

enter image description here


Step 2 : EditTextActivity: input text

enter image description here


Step 3 : GreenActivity: display color and input text

enter image description here


In EditTextActivity, which activity to go after Next pressed depends on previous MainActivity, so I write a switch case to do that:

MainActivity:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.setTitle("Step 1");
    }

    public void redTheme(View view){
        Intent i=new Intent(this,EditTextActivity.class);
        i.putExtra("callbackId",0);
        this.startActivity(i);
    }

    public void greenTheme(View view){
        Intent i=new Intent(this,EditTextActivity.class);
        i.putExtra("callbackId",1);
        this.startActivity(i);
    }

    //similar for BlueActivity
    .
    .
    .
}

EditTextActivity:

public class EditTextActivity extends AppCompatActivity {
    public int callbackId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_edit_text);
        this.setTitle("Step 2");
        this.callbackId=this.getIntent().getIntExtra("callbackId",0);
    }

    public void next(View view){
        switch (this.callbackId){
            case 0: {
                Intent i2 = new Intent(this, RedActivity.class);
                EditText editText = (EditText) this.findViewById(R.id.editText);
                i2.putExtra("text", editText.getText().toString());
                this.startActivity(i2);
                break;
            }
            case 1: {
                Intent i2 = new Intent(this, GreenActivity.class);
                EditText editText = (EditText) this.findViewById(R.id.editText);
                i2.putExtra("text", editText.getText().toString());
                this.startActivity(i2);
                break;
            }
            //similar for BlueActivity
            .
            .
            .
        }
    }
}

But I think it is an maintain nightmare: when I add a new color Activity, eg: YellowActivity, I need to edit both the MainActivity and EditTextActivity and then add a new switch option. I would like the logic of Next button placed in MainActivity and so I use my own callback mechanism:

MainActivity:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.setTitle("Step 1");
    }

    public void redTheme(View view){
        Intent i=new Intent(this,EditTextActivity.class);
        final EditTextActivity.Callback callback= new EditTextActivity.Callback() {
            @Override
            public void run(EditTextActivity editTextActivity) {
                Intent i2=new Intent(editTextActivity,RedActivity.class);
                EditText editText=(EditText)editTextActivity.findViewById(R.id.editText);
                i2.putExtra("text",editText.getText().toString());
                editTextActivity.startActivity(i2);
                EditTextActivity.callbackMap.remove(editTextActivity.callbackId);
            }
        };
        int hashCode=callback.hashCode();
        EditTextActivity.callbackMap.put(hashCode,callback);
        i.putExtra("callbackId",hashCode);
        this.startActivity(i);
    }

    public void greenTheme(View view){
        Intent i=new Intent(this,EditTextActivity.class);
        final EditTextActivity.Callback callback= new EditTextActivity.Callback() {
            @Override
            public void run(EditTextActivity editTextActivity) {
                Intent i2=new Intent(editTextActivity,GreenActivity.class);
                EditText editText=(EditText)editTextActivity.findViewById(R.id.editText);
                i2.putExtra("text",editText.getText().toString());
                editTextActivity.startActivity(i2);
                EditTextActivity.callbackMap.remove(editTextActivity.callbackId);
            }
        };
        int hashCode=callback.hashCode();
        EditTextActivity.callbackMap.put(hashCode,callback);
        i.putExtra("callbackId",hashCode);
        this.startActivity(i);
    }

    //similar for BlueActivity
    .
    .
    .
}

EditTextActivity:

public class EditTextActivity extends AppCompatActivity {
    public interface Callback{
        public void run(EditTextActivity editTextActivity);
    }
    public static Map<Integer,Callback> callbackMap=new HashMap<>();

    public int callbackId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_edit_text);
        this.setTitle("Step 2");
        this.callbackId=this.getIntent().getIntExtra("callbackId",0);
    }

    public void buttonPressed(View view){
        callbackMap.get(this.callbackId).run(this);
    }
}

Which I use a static map to hold callbacks instead of embedded in switch case, and now I can add a new operation of Next button without modifying EditTextActivity.

However, I found this mechanism is far more complicated than the original one:

  1. It contains more codes
  2. The new approach is less straight forward than the original one, which I afraid my teammates would fail to understand what I'm trying to do.
  3. The standard way in many docs seems just use switch case

So my question is: should I eliminate switch case at this case?

Note : I'm asking about the general approach of passing functions or callbacks to subsequent activity, not specific for this case. So don't make suggestions like "passing color string to EditTextActivity".

ggrr
  • 5,725
  • 11
  • 35
  • 37
  • Possible duplicate of [Refactoring Switch Statements and is there any real use for Switch Statements at all?](https://softwareengineering.stackexchange.com/questions/147214/refactoring-switch-statements-and-is-there-any-real-use-for-switch-statements-at) – gnat Aug 17 '17 at 07:05
  • What I find worse than using a `switch` here is that you have a lot of unnecessary duplication in your code. Please get rid of it at least for the sake of a simplistic example. – larsbe Aug 17 '17 at 07:46

1 Answers1

2

By factoring out the duplicated code first, you can come to a completely different solution.

If I take the first version (with switch) and refactor the duplicated code, you end up with something like

public class EditTextActivity extends AppCompatActivity {
    public int callbackId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_edit_text);
        this.setTitle("Step 2");
        this.callbackId=this.getIntent().getIntExtra("callbackId",0);
    }

    public void next(View view){
        Intent i2;
        switch (this.callbackId){
            case 0: {
                i2 = new Intent(this, RedActivity.class);
                break;
            }
            case 1: {
                i2 = new Intent(this, GreenActivity.class);
                break;
            }
            //similar for BlueActivity
            .
            .
            .
        }
        EditText editText = (EditText) this.findViewById(R.id.editText);
        i2.putExtra("text", editText.getText().toString());
        this.startActivity(i2);
    }
}

Now you can see that the only real variation is which Intent to create for the follow-on activity.
A logical change now is to not pass in an int, but rather the Intent to activate next, or the Activity class that should be used to create the Intent.
As passing objects that way doesn't really seem feasible in Android, the next best thing is similar to the static map you used:

MainActivity:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.setTitle("Step 1");
    }

    public void redTheme(View view){
        Intent i=new Intent(this,EditTextActivity.class);
        int hashCode=callback.hashCode();
        EditTextActivity.callbackMap.put(hashCode,RedActivity.class);
        i.putExtra("callbackId",hashCode);
        this.startActivity(i);
    }

    public void greenTheme(View view){
        Intent i=new Intent(this,EditTextActivity.class);
        int hashCode=callback.hashCode();
        EditTextActivity.callbackMap.put(hashCode,GreenActivity.class);
        i.putExtra("callbackId",hashCode);
        this.startActivity(i);
    }

    //similar for BlueActivity
    .
    .
    .
}

EditTextActivity:

public class EditTextActivity extends AppCompatActivity {
    public static Map<Integer,Class<? extends Activity>> callbackMap=new HashMap<>();

    public int callbackId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_edit_text);
        this.setTitle("Step 2");
        this.callbackId=this.getIntent().getIntExtra("callbackId",0);
    }

    public void next(View view){
        Intent i2 = new Intent(this, callbackMap.get(this.callbackId));
        EditText editText = (EditText) this.findViewById(R.id.editText);
        i2.putExtra("text", editText.getText().toString());
        this.startActivity(i2);
    }
}
Bart van Ingen Schenau
  • 71,712
  • 20
  • 110
  • 179