0

I was recently reading about design patterns and especially about low coupling and delegation.

I was wondering, whether there should be any logic on the Activity class or if it only serves the view.

E.g. I have an activity called BattleActivity and that is supposed to work as some kind of session between two players. A lot of Push Notifications happen there, also the class works as an Observer, so there is a lot of comminication going on there.

Right now I am trying to figure out what logic could I move to a separated object(and whether I should) and then just work with the activity.

Example of one of my methods on the activity:

private void postCastedSpell(final int spellId) {
        Call call = StaticGlobalContainer.api.postSpellToBattle(Integer.parseInt(battleId), Integer.parseInt(MainActivity.CURRENT_USER_ID), spellId, 100);
        call.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Response<User> response, Retrofit retrofit) {
                User user = response.body();
                if (response.code() == 202) {
                    // 200
                    Log.i("Posting spell to battle", "Success");
                    Boolean affectedUserIsOpponent = isUserOpponent(user);
                    if (affectedUserIsOpponent && user.currentHp<1){
                        StaticGlobalContainer.battleOnResult(Constants.WON, getApplicationContext());
                    }else {
                        updateBattleLog(affectedUserIsOpponent, user, spellId);
                    }
                    // TODO: do something here
                } else {
                    // 404 or the response cannot be converted to User.
                    Log.e("Posting spell to battle", "Error:" + response.errorBody());
                }
            }

            @Override
            public void onFailure(Throwable t) {
                Log.i("HttpRequest-Post spell", "Failure");
            }
        });
    }
Ondrej Tokar
  • 4,898
  • 8
  • 53
  • 103
  • 1
    You're treading into the area of high opinion about app architecture, and there are a lot of ways to do what you're asking, none of them necessarily more ore less correct than another. – Doug Stevenson Feb 25 '16 at 20:37
  • 1
    It's certainly not a bad thing to have logic in your Activity. An Activity simply serves to run that part of the app, which includes instantiating views, manipulating them, handling user input, etc. As a developer, it is your job to decide how much logic is TOO much logic in one class. And that basically depends on your own personal preference. If you feel like some tasks could be broken off into separate classes, go for it. Otherwise, do what you need to in the Activity itself. – NoChinDeluxe Feb 25 '16 at 20:38
  • I was hoping for having one or two correct ways... Anyway thank you for slight clarification of my problem :) – Ondrej Tokar Feb 25 '16 at 20:39
  • I agree with Doug, this is a very opinionated question. In reality, you probably will find that yes, you will do logic in your Activity, regardless of what POSA pattern you implement. There needs to be some logic associated to the activity, how much? well thats up to your implementation – kandroidj Feb 25 '16 at 20:39
  • Thank you all for your kind replies, it makes sense. – Ondrej Tokar Feb 25 '16 at 20:40
  • Answer to another question that might help you: http://stackoverflow.com/a/4329537/1168342 – Fuhrmanator Feb 26 '16 at 14:18

1 Answers1

2

It's not specifically bad to put a lot of logic in Activities, but you're right to try to keep it only view related things. If the app is relatively small, it might not be worth moving the logic out. Also, there is some overhead to using abstractions.

if your abstractions aren't supplying a significant benefit, you should avoid them

I try to keep any big data objects in a manager class, so given your example, it might worthwhile to create a Battle manager class to hold all the logic involved in it, like this postCastedSpell function. This way all the Battle information is self contained, and also can be used elsewhere in other activities.

Just keep in mind if you're use data manager classes and you want them to prompt some sort of interation with the UI, you'll have to use Callbacks or the Bus pattern since the Battle manager won't have access to your UI. For example, to call the postCastedSpell the call would look like: BattleActivity:

BattleManager bm = BattleManager.getInstance(user1, user2);

onSpellClicked() {
   bm.castSpell(spellId, user1, callback)
}

BasicCallback callback = new BasicCallback() {
    @Override
    onComplete() {
        if (MyInfoFragment.this.isVisible()) {
            [Update UI]
        }
    }
};

NOTE: When using callbacks like my example, when it finally gets called the activity may have already gone out of view and have been already garbage collected. So in the callback function you need to first make sure it is still visible before trying to modify the UI that possibly no longer exists.

Community
  • 1
  • 1
ScottyC
  • 1,467
  • 1
  • 15
  • 22
  • Thank you for your answer. Just for clarification, if I make an object, let's say the Manager is it the right way to use the Callback to work with the UI? What if I pass a context object? Or the activity object and then I call a method that is in that activity to update the UI? Your answer to these questions would help me a lot. – Ondrej Tokar Feb 25 '16 at 21:36
  • 2
    Though you could technically do this, you want to try to avoid references to your activity between other persistent classes. This is because you want your activity to get garbage collected at some point after it goes out of view. If your BattleManager always exists and holds a reference to your activity, the activity will never get garbage collected. Regarding this garbage collection, I also added an edit on how to handle this if it DOES get collected before your callback comes back. – ScottyC Feb 25 '16 at 21:52
  • Thank you for all your answers. You have helped a lot! – Ondrej Tokar Feb 25 '16 at 22:06