3

I divide responsibilites of MainActivity and try keep it clean and readable by extending BaseActivities such as MainActivity extends AdBaseActivity extends LocationBaseActivity extends FullScreenActivity extends Activity.

Each activity only takes care of what they are named to do while keeping MainActivity to set layouts and views and run main object for the task such as GameSurfaceView or main class it supposed to run. Is this bad programming practice regarding to coupling and cohesion, hard to test or from any other design principle aspect?

Is using a class, for example LocationController with all life cycle methods required and instantiated or used with dependency injection, better over extending BaseActivities?

I wonder how to maintain Manager classes with callbacks needed by Activity when a permission is needed and DialogFragment or any other view should be infilated for example, or result from another Activity is returned? These manager classes can be members of other classes and having deeper references to Activity may cause memory leaks and it could be hard to detect if this situation can only occur when a manager class is on a particular state that prevents Activity reference not be released.

Thracian
  • 43,021
  • 16
  • 133
  • 222

3 Answers3

1

TLDR;

Yes and no!

Inheritance and all OOP principles are very effective for readability and code management, but since your are developing a mobile application, too many classes may reduce memory and performance.


I understand what you are trying to do and why. I had the same issue a while back when programming a fairly big Android app.

As it was basically a single Activity app with 4 Fragments I ended up having too much code in my MainActivity, even by delegating some code to my Fragments.

I then changed my MainActivity and made it own the following Manager classes through composition:

  • LocationManager
  • ApiVendorManager
  • UIManager
  • BackgroundJobManager
  • AppFunctionalityManager
  • StageTransitionManager
  • ...

each containing 800+ lines of code and life-cycle callbacks (onCreate(), onPause(), ...).

After that, my MainActivity was so clean and well-organized that I was proud of myself, but I noticed a drastic performance drain.

I then stumbled upon this documentation page that says:

However, abstractions come at a significant cost: generally they require a fair amount more code that needs to be executed, requiring more time and more RAM for that code to be mapped into memory.

What I did at the end was finding some balance between abstraction and performance by maintaining only 4 Managers.

I would say: keep abstracting until you notice performance issues. That's the moment you should consider limiting inheritance and composition and perhaps even re-merge some previously extended classes.

The same principle applies to extending your Activity classes.

payloc91
  • 3,724
  • 1
  • 17
  • 45
  • Honestly, i prefer composition over inheritance creating manager classes for location, sensor, bluetooth etc. but this managers having references to Activity and these manager classes becoming some part of other class making deeper references, isn't this bad? Also, you need to declare callbacks for these classes that should be implemented by the Activity which turns results my activity with too many callbacks. Role of Activity class is both for views and methods like onPermissionResult() methods makes it hard to maintain it for me. – Thracian Oct 19 '17 at 14:56
  • That's exactly what I did. I had an interface `BaseManager` declare all my methods (`nextStage()`, ...) and life-cycle callbacks (`onCreate()`, ...). I made sure that my `MainActivity` was calling all `Managers` sub-methods. E.g: `onResume()` **must** call `onResume()` method in all `managers`. `Managers` had then a reference to the `Activity`. What you did, by splitting responsibilities across classes, by composition or inheritance, is **very good practice**. The problem I warned you about is that in the mobile world you may face hardware limitations. If that was your concern. @FatihOzcan – payloc91 Oct 19 '17 at 15:09
  • My actual fear is not be able to maintain them when project gets bigger having deeper references to this manager and these managers having other objects may result keeping references to Activity/context or other class that may cause memory leaks. Performance is more visible and can be solved but there could be states of object that may cause memory leaks. Also i want these classes to be re-usuable. – Thracian Oct 19 '17 at 15:14
  • As I said, just do not use too many composite classes. Each `Manager` should follow the `Activity` guidelines for freeing resources: either in the `onResume()` or `onDelete()` method. Do not be afraid of storing a reference to your `Activity`. A good no-leak example is the famous `MapView` inside a `Fragment`. It does not cause any memory leak. Just make sure that the owner's life-cycle methods call the sub-class respective method as well. If you are concerned with memory leaks, you may check out Java's `WeakReference`. – payloc91 Oct 19 '17 at 15:40
1

It depends on targeted project. If you wanna get benefit of re-usability. Then it is not a good practice because it won't be easy to split dependencies. but if you are not planning to re-use code again and you stuff is relatively small .. then It might not be that bad and sometimes it's the only way to manage logic in inheritance style.

But there is another way ... compositions!

see : Difference between Inheritance and Composition

Composition is has-a relationship while inheritance is is-a. Actually composition is the exit door when inheritance is heavy to go on.

Using dependency injector like Dagger to apply composition would give a good quality code in terms of readability, reusability, and Extensibility.

Maher Abuthraa
  • 17,493
  • 11
  • 81
  • 103
  • I prefer composition over inheritance, that's actually why i ask about but Activity class assumes both view and controller roles makes it hard for me to grasp the right model. Why isn't inheritance for Activity is not good for resubility, you can always remove and add indepented activites focused on task they need to do. In the example i wrote you can change the order of extension, remove or add any BaseActivities such as SensorBaseActivity or BluetoothBaseActivity without too much effort. – Thracian Oct 19 '17 at 15:01
  • Consider you have a big layer as super class i.e. BT. And you need to set base class to it. You cannot do that easily with inheritance. One more thing, Inheritance leads to unfold all methods from all super class but composition will group these methods under it type. So it's easy to recognize and safe from being overrided. Last thing relates to testing and customization . you can swap modules easily with composition. With mocks, or customized modules . That'd be impossible with inheritance. That doesn't mean inheritance is evil ☺. Just don't load too much variant codes there. – Maher Abuthraa Oct 19 '17 at 15:41
0

Coupling is a fundamental key on OOP and there's no such thing as "doing it wrong by coupling". You want to encapsulate as much as possible and everytime you feel like you are writing the same code for a second time use coupling instead.

Also refer to this question for some more clarification on a subject close to yours: Is there such thing as too many classes?

Asger
  • 83
  • 1
  • 11
  • I know coupling and cohesion is part of software developing process but i'm hoping to keep it on minimum for re-usability and maintainability. My question is not about having too many classes, i actually very much favor too many classes to separate responsbilities and avoid creating god object responsible from everything. It's good to abide GRASP and SOLID principles however Activites with all callbacks, especially onResultActivity() and onPermissionResult() methods and view infilation makes your classes to be abstracted totally. I want to know what kind of structure and balance should be. – Thracian Oct 19 '17 at 15:31