4

I am learning and loving Java and Android but have a long way to go. This is a best practice question, I think. In my Android Activity I have 6 classes. Several of them are calling methods that I have duplicated from another class. It seems redundant to duplicate the methods when I could just call them from another class. I also think it would be easier to maintain them all in one class. (Main activity, maybe?) My question is: What is the best practice for calling the same method from more than one class? For example, say my classes are:

Main Activity GameSelector Game1Home Game1

I have a few methods which are the same in every class. Lets call them getPrefs() and setPrefs(). I am not passing anything into them or out of them. Which class should they go in, and how do I call them from another class?

Edit - Thanks to some very helpful answers I have a fully functioning Configurations class and my other 6 classes look much cleaner! This will be very easy to maintain and I learn a few great pointers while making it. I'm posting my finished class here in case it may help anyone else. You can call the methods from your other classes like this:

Configurations.getPrefs(this);

and refer to static variables you've defined as global in your configurations file like this:

Configurations.buttonClicked.start();

Configurations.java:

public class Configurations extends Activity {
static MediaPlayer buttonClicked;
static MediaPlayer instructionsAudio;
static MediaPlayer messageAudio;
static MediaPlayer correctNum_sound;
static MediaPlayer incNuma_sound;
static MediaPlayer incNumb_sound;
static String storeChildsName;
static String storeRequestedRange;
static String storeVoiceChoice;
static Intent i;


public static void setupPrefs(final Activity a) {
    ImageButton settingsClicked = ((ImageButton) a.findViewById(R.id.prefButton));
    settingsClicked.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                ImageView settingsClicked = ((ImageView) a.findViewById(R.id.prefButton));
                    settingsClicked.setImageResource(R.drawable.settings_button_clicked);
                buttonClicked = MediaPlayer.create(a, R.raw.click);
                    buttonClicked.start();

                    Intent settingsActivity = new Intent(a.getBaseContext(),
                                    Preferences.class);
                    a.startActivity(settingsActivity);
            }
    });
}
public static void getPrefs(final Activity a) {
    // Get the xml/preferences.xml preferences
    SharedPreferences prefs = PreferenceManager
                    .getDefaultSharedPreferences(a.getBaseContext());
    storeChildsName = prefs.getString("editTextPref",
                    "Friend");
    storeRequestedRange = prefs.getString("listPref", "3");
    storeVoiceChoice = prefs.getString("voices", "1");
}

public static void setupMusicToggle(final Activity a) {
    i=new Intent(a, MyMusicService.class);
       final ToggleButton togglebutton =(ToggleButton)a.findViewById(R.id.music_toggle);
      togglebutton.setOnClickListener(new OnClickListener() {  
          public void onClick(View v) {   
              // Perform action on clicks    
              if (togglebutton.isChecked()) {   
                  Toast.makeText(a, "Music on.", Toast.LENGTH_SHORT).show();  
                  a.startService(i);  
              } else {   
                  a.stopService(i);
                  Toast.makeText(a, "Music off.", Toast.LENGTH_SHORT).show(); 
                      }    }}); 
}

public static void returnHome(View view, Activity a) {
    ImageView homeClicked = (ImageView) a.findViewById(R.id.home);
    homeClicked.setImageResource(R.drawable.homebuttonclicked);
    buttonClicked = MediaPlayer.create(a, R.raw.click);
    buttonClicked.start();
    Intent intent = new Intent(a, GameSelector.class);
    a.startActivity(intent);
}

public static void releaseMP(Activity a) {
    if (buttonClicked != null) {
        buttonClicked.stop();
        buttonClicked.release();}
        if (instructionsAudio != null) {
            instructionsAudio.stop();
            instructionsAudio.release();}
        if (messageAudio != null) {
            messageAudio.stop();
            messageAudio.release();
        }
        if (correctNum_sound != null){
            correctNum_sound.stop();
            correctNum_sound.release();
        }
        if (incNuma_sound != null) {
            incNumb_sound.stop();
            incNuma_sound.release();
        }
        if (incNumb_sound !=null) {
            incNumb_sound.stop();
            incNumb_sound.release();
        }
}

public static boolean isMyServiceRunning(Activity a) {
    ActivityManager manager = (ActivityManager) a.getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (MyMusicService.class.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}

}

Hope this helps someone as much as it's helped me!

PS - If you see any room for improvement in this code please share! I have a lot to learn =)

1
  • It seems your Configurations class does not use any static member from the Activity class. If this is the case, you do not need to extend Activity, unless you are extending your other activity classes as extends Configurations. Commented Aug 13, 2013 at 6:18

4 Answers 4

7

There are several ways to share code - you can do it by

  1. Defining a "helper" class, and adding your static methods to it,
  2. Defining a base class (often an abstract base class) and adding your methods to it,
  3. Defining a non-static class, and embedding an instance of that class in each of the classes that need to share the code; classes could also share a reference to a common instance.

It is hard to say which approach is more appropriate, but from the method names it appears that you are planning to get and set preferences. In situations like that, the #1 or #3 with a shared instance are often the most appropriate.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, das. Going to edit my question as the code I want to enter is too large for a comment.
@CaseyMurray You need to change setupPrefs to take the Activity object in which the method has been before, call setupPrefs(this), and use the activity object inside setupPrefs to call instance methods, i.e. instead of, say, findViewById(R.id.prefButton); you would write activity.findViewById(R.id.prefButton);, and so on.
Very easy to understand that explanation, thank you! I am plugging away at changing it to be all static and refer to the activity object.
is it necessary to include import com.example.zengame1.Configurations; in every class I need to use this file? Or is there something else I should be doing to ensure that the global variables as defined in the Configurations file are properly passed into the class I am calling them from?
@CaseyMurray Java has no global variables, so I am not sure I understand. Importing is always optional: all it does is letting you skip com.example.zengame1. in front of Configurations. If common member variables are inherited from a base class, then you should import Configurations and inherit it in each class where it is needed.
1

It depends on what each method does. By the name, getPrefs() looks like setting preferences of some sort. In that case, what I personally do, is create a class Configuration and make a singleton instance that all classes share.

Android is slightly different from the usual Java.
In 'usual' Java, you instantiate the objects, have a reference to them and then you call methods on them.
In Android, most of your methods are defined in Activity, Fragment, DialogFragment , etc. and you are not in control of instantiating them. The methods defined whitin those can only be called within themselves unless declared static.

So, go over your design, see what the methods do and check if you can make a different class out of them :)
Hope it helps.

3 Comments

The difference is no that big and once you need to define your own methods you should probably start to write 'usual' Java classes. People always tend to put way too much stuff into their Activites / Fragments / ... Single responsibility per class should still apply here
@zapl Exactly. Separation of concerns. that is. OP asked how she could call methods from other classes .. so I just added that :-)
Thanks for a great answer. The singleton mention sent me somewhere to read more about what that is and it's been helpful!
1

It all depends upon the sole purpose of the classes and methods you define.

If there are too many methods you need to use in many of your activities, then one option wil be;

  1. Define a separate helper class and implement those methods there. Include them in all your required classes.
  2. Inheritance or interface would be a second option.

Comments

1

What I do is to create an abstract Activity class that extends the Android API's Activity class (or the support library's FragmentActivity class):

public abstract class Activity extends android.app.Activity { //or extends FragmentActivity
//put your common stuff here
}

Similar recommendations would ask you to name this class BaseActivity, but I like the name Activity better because it's in sync with the Android system.

All my activities would be extended from this abstract class:

//GameActivity.java
public class GameActivity extends Activity {
}

//OptionsActivity.java
public class OptionsActivity extends Activity {
}

I also keep this abstract Activity class (and some other goodies) in a library project so that I have a single base for all my common stuff and all my other projects would simply include this as a library (Project Properties > Android > Libraries > Add). But of course, your development needs may differ from this model.

Extra tips for your Java development:

  • Always start with the strictest access modifier (private), changing to more leniant ones as you need more access (default > protected > public).
  • If a method does not use anything non-static, be sure to make it a static method. This way you don't have to instantiate an object just to call the method inside its class.
  • Use getters and setters for member fields unless you are sure direct access is desired and will not introduce chances of errors.
  • Use wrapper classes like java.lang.Integer when you need to show 'not known' or 'invalid' status of a primitive type (int).

2 Comments

Very helpful extra tips! Thank you! I don't know if I am comfortable enough with my knowledge to override the Activity class like that yet but it seems like a very organized way to do things and I hope to try it in the future.
@CaseyMurray Don't worry about it. You are not overriding, but merely extending it. It will still be the same to Android, just that now you can add common stuff inside. Overriding would be where the original functionality is lost. That doesn't happen in extension unless you deliberately override a method or something.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.