3

I am developing Android app and my MainActivity is becoming God Object.
By the way native Activity class implementation is some sort of God Object already.
The problem is that my activity class is growing and growing.
Let me explain class responsibilites, for those who are not familiar with android.
Activity is like a screen with it's UI, lifecycle, functionality to communicate with OS.
Drawer is part of UI that brings to the activity side menu for navigation in the app. What is the problem.

public abstract class MainActivity extends SingleFragmentToolBarActivity<T> implements Drawer.OnDrawerItemClickListener {
    private static final int PROFILE_HEADER_IDENTIFIER = 200;
    private float mDisplayDpWidth;
    private float mDisplayDpHeight;
    private Drawer.Result mNavigationDrawer;
    private AccountHeader.Result mAccountHeader;
    private double mDrawerWidthFactor = 0.9;
    private double mDrawerHeaderHeightFactor = 0.3;
    private IProfile<ProfileDrawerItem> mGuestProfile;
    private IProfile<ProfileDrawerItem> mLoggedInProfile;
    private boolean userIsLogged = false;
    public Drawer.Result getNavigationDrawer() {
        return this.mNavigationDrawer;
    }
    private AccountHeader.Result geAccountHeader() {
        return this.mAccountHeader;
    }
    private static final int PROFILE_SETTING = 1;
    private final AccountHeader.OnAccountHeaderSelectionViewClickListener mHeaderSelectionViewClickListener = new AccountHeader.OnAccountHeaderSelectionViewClickListener(.....);
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setUpNavigationDrawer(savedInstanceState);
    }

    private void setUpNavigationDrawer(Bundle savedInstanceState) {
        DrawerImageLoader.init(new DrawerImageLoader.IDrawerImageLoader() {
            @Override
            public void set(ImageView imageView, Uri uri, Drawable placeholder) {
                Picasso.with(imageView.getContext()).load(uri).placeholder(placeholder).into(imageView);
            }

            @Override
            public void cancel(ImageView imageView) {
                Picasso.with(imageView.getContext()).cancelRequest(imageView);
            }

            @Override
            public Drawable placeholder(Context ctx) {
                return null;
            }
        });
        getDisplayMetrics();
        mGuestProfile = buildGuestProfile();
        mAccountHeader = buildNavigationHeader(savedInstanceState);
        mNavigationDrawer = buildDrawer(savedInstanceState);
    }
    protected Drawer.Result buildDrawer(Bundle savedInstanceState) {
     Drawer drawer =  new Drawer(this)
            .withActivity(this);
    ........
    }
    protected List<IProfile> getProfileItemList() {
    ......        
    }
    protected AccountHeader.Result buildNavigationHeader(Bundle savedInstanceState) {
    ......
    }
    private ProfileDrawerItem buildGuestProfile() {
        .......
    }
    private ProfileDrawerItem buildLoggedInProfile(UserBean userBean) {
        .......
    }
    private void getDisplayMetrics() {
       .....
    }
    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int i, long l, IDrawerItem iDrawerItem) {
     ......
    }

    protected Drawer addItemsIntoDrawer(Drawer buildDrawer) {
        ......
    }
    public void setDrawerWidthFactor(double factor) {
      ......
    }
    public void setDrawerHeaderHeightFactor(double factor) {
      ......
    }

This is only declaration of some methods and class members.
This code above is ONLY for setting navigation drawer in my MainActivity, there will be quite more code in the future here for communicating with services and so on, if to left this as it is, soon I will get class with millions line of code, tons of class members and ton of methods.

Ho to solve this problem, what pattern can be acceptable in this way.
Setting drawer requires reference to the Activity.
I have some ideas how to solve this problem.
Use strategy pattern create interface with all these methods responsible for setting navigation drawer, but how can I pass reference to the activity into the interface implementation in this case I have to create not interface but abstract class and pass reference to the Activity into it's constructor.
This will work, but I still think that it is not perfect, clean solution.

Please suggest what can I do to stop class growing.

EDIT

There is only small responsibility of my activity, there will be more important responsibilities in the future, so I have to get rid of writing a lot initialization code. I haven't post body of methods (300 lines of code). I have found one possible way here is to create some abstract class with basic methods and than create implementation and just use it in my activity when I need this.And in this case it will be possible to change it in runtime (before view has been inflated).

  • 17
    Not everything need be a pattern. Simple composition should suffice. – Telastyn Jun 1 '15 at 11:35
  • I understand, but just have a look on this horrible code, there is only small responsibility of my activity, there will be more important responsibilities in the future, so I have to get rid of writing a lot initialization code. I haven't post body of methods (300 lines of code). I have found one possible way here is to create some abstract class with basic methods and than create implementation and just it in my activity when I need this. – CROSP Jun 1 '15 at 11:40
  • possible duplicate of What are the practical ways to implement the SRP? – gnat Jun 1 '15 at 11:45
  • 1
    Other questions that might have useful information (not duplicates): Architectural problem for Activity communication in an Android app - How large is ok for a Class? – user22815 Jun 1 '15 at 12:13
  • 2
    @CROSP: the upvotes are probably trying to tell you you should not focus so much on "patterns" here. Refactoring to smaller classes does not need the application of a standard design pattern from the GOF book. Better get a copy of Bob Martin's "Clean Code" book, or a copy of Martin Fowler's "Refactoring" book, they contain lots of suggestions how to create smaller classes without using patterns. – Doc Brown Jun 1 '15 at 14:50
2

You could create list of classes responsible for each operation, where and when it makes sense for example,

public abstract class MainActivity extends SingleFragmentToolBarActivity<T> implements Drawer.OnDrawerItemClickListener {
    ....

    private void setUpNavigationDrawer(Bundle savedInstanceState) {
        NavigationDrawer drawer = new NavigationDrawer(this,savedInstanceState);  
        drawer.setup();
    }
}

Here you could move logic for each operation (in this example it's NavigationDrawer) to own class where it takes care of the operation.

1

I would first break it down into a number of classes with their own SINGLE responsibilities.

You would need to apply GRASP principals here first. GRASP

Secondly, I would look into strategy design pattern. Strategy Design Pattern

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.