Using a separate class for toolbar functions in Android Studio? - android

Lets say I have two different activities, both using the same toolbar, making use of the same layout and menu options. This part is no problem.
If I want a menu option to execute a specific function, I would naturally create a function, foo(), and call it when the menu option is selected. Because the onOptionsItemSelected(MenuItem item) method i handled individually in each acitivity, would it be a good practice to use a separate class with static "toolbar functions"? E.g. having a logout() function accessible from the dropdown menu in the toolbar from any activity.
It may seem obvious, however, I cannot find any "best practices" on the matter. So what are the best practice(s) for handling multiple activities calling the same "toolbar function"?
Example code: lets say MainActivity and SecondActivity both have the same toolbar. In both onCreate() methods:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Somewhere else in both of the acitivites:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.item_foo:
ToolbarFunctions.foo(); //Is this a good way to do it?
default:
break;
}
return super.onOptionsItemSelected(item);
}

Good practice it's using main parent activity class and extend all other activities. Here is some example of your parent Activity:
public abstract class MyParentActivity extends Activity {
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
return true;
}
// This is your abstract function for other activity!
public void foo();
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.item_foo:
foo(); //Is this a good way to do it? Yes, here it's okey!
default:
break;
}
return super.onOptionsItemSelected(item);
}
}
So you can define 10 your activity that extends from MyParentActivity as a code below. That is all:
public class MyOtherActivity extends MyParentActivity {
// Here your function will be called in every time
// when you click to Toolbar buttons!
//
// And you don't need write again about clicking menu!
#Ovveride
public void foo () {
//Any your behaviour
}
}

You can define a BaseActivity class and extend all other activities from the BaseActivity. You would include the common parts in the BaseActivity.

If your foo() function has only logic and no view logic, then is better to keep it in static class.It will be faster and unit testable. If it has view logic in it than go with BaseActivity example. If it has view and functional logic together may be is better to be static and also extend BaseActivity which must implement an interface with a method for your view updates.That interface you will pass to you static foo() method which will do the functional logic and will return with the interface to the activity called it, to let the activity update the view it self. Than you can still unit test your foo() method.
public interface FooInterface{
void onFooDone(Foo foo);
}
public static void foo(FooInterface fooInterface){
calculate...
if(fooInterface!=null)
fooInterface.onFooDone(fooObject);
}
Your activity must implement FooInterface
and call foo(this);

Related

OptionsMenu items common for multiple activites

The Android design guide says that Help should always be placed as the last item of the overflow menu (it should never appear in the ActionBar) and also, that is should be present in every activity, so that users don't have to look for it. Similar approach is also recommended for Settings.
However, I'm wondering what is the best way to make sure that all the activities in my app handle these items without lots of code repetition? Putting these common items manually into every XML menu file and then manually handling clicks on each of them in every activity class is just nonsense.
Since I am already extending all of my activities from a common base class (which provides some convenience methods), I came up with this approach: In the BaseActivity class, I define an empty initOptionsMenu() method which the subclasses may override (template method pattern style) by adding their specific items to the menu. This method is called at the start of onCreateOptionsMenu() and then the base class adds the common items (settings and help) at the end of the menu.
The onOptionsItemSelected() method follows the standard pattern - it switches on the item ID and in the default case, it passes the handing to the superclass. Again, the base class handles the setting and help cases.
public class BaseActivity extends Activity {
#Override
public boolean onCreateOptionsMenu(Menu menu) {
initOptionsMenu(menu);
menu.add(Menu.NONE, R.id.menu_settings, Menu.NONE, R.string.menu_help);
menu.add(Menu.NONE, R.id.menu_help, Menu.NONE, R.string.menu_help);
return true;
}
protected void initOptionsMenu(Menu menu) {}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_settings:
startActivity(new Intent(this, SettingsActivity.class));
return true;
case R.id.menu_help:
startActivity(new Intent(this, HelpActivity.class));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
Now, whenever I create a new activity, I extend the BaseActivity. If the derived activity provides some more items for the options menu, I do not override the standard onOptionsItemSelected(), but instead I override the custom initOptionsMenu() method and populate the menu there. In onOptionsItemSelected(), I need to handle only cases for the items specific for this activity, the common ones will be handled by the super call.
public class FooActivity extends BaseActivity {
#Override
protected void initOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.foo, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// cases for items in R.menu.foo
default:
return super.onOptionsItemSelected(item);
}
}
}
Is this pattern sensible? Can you come up with a better approach? Please share your thoughts.
I might not use initOptionsMenu method. I will just call super.onCreateOptionsMenu() after adding my menu from concrete implementation. My BaseActivity will add settings and help menu so
in BaseActivity:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(Menu.NONE, R.id.menu_settings, Menu.NONE, R.string.menu_help);
menu.add(Menu.NONE, R.id.menu_help, Menu.NONE, R.string.menu_help);
return true;
}
and in MainActivity extends BaseActivity:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(Menu.NONE, R.id.menu_create_dummy, Menu.NONE, R.string.menu_dummy);
menu.add(Menu.NONE, R.id.menu_delete_dummy, Menu.NONE, R.string.menu_dummy);
return super.onCreateOptionMenu(menu);
}

Android load multiple menu layout files possible?

I want to have a superclass activity that defines what basic menu items each activity should have in addition to their own.
Here is my code so far:
public abstract class SuperActivity extends FragmentActivity {
protected List<TextView> textView = new ArrayList<TextView>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getContentResource());
setTextViews(textView);
}
protected abstract void setTextViews(List<TextView> textViews);
protected abstract int getContentResource();
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.menuitemsforallsubclasses, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.basicmenuitem1:
allSubclassActivitiesCanDoThis()
return true;
case R.id.basicmenuitem2:
allSubclassActivitiesCanDoThis2()
return true;
}
}
}
In the subclasses I would then just add something to onCreateOptionsMenu (an additional layout file) and onOptionsItemSelected, is that correct? Just want to make sure I am not on the wrong track here. Would it even be possible to load multiple layout file in the same activity?
FYI: In case you are wondering why I have a TextView array in the activity: In addition to this I want to have all TextViews of each subclass activity in an ArrayList, so that I can add listeners to all of them automatically so I know when something has changed in the activity or to do some other neat stuff.
Is what I am doing possible? Is it possible to load multiple menu layout files?

What's the best way to implement a Application wide Options menu on Android?

I'm an Android newbie, and working on an app which needs an Options menu. I have currently implemented the options menu by setting it as the primary activity and Extending it in the main activity.
But since I work in a team, this method doesn't work always with us since we need to extend another activity which is essential.
My Question
How do I implement this Options Menu across the application without Extending the activity in my Main activity?
My Current Setup
I have a MainActivity (This starts first) - MainActivity extends MenuClass
I have the OptionsMenu Class, MenuClass (I want this to be Application wide) - MenuClass extends Activity
I have three other Classes, that extends Activity itself! And these three activities are triggered from the MainActivity and when done, returns to the MainActivity.
If you don't want to, or can't create a base Activity which every other activity then extends - why don't you have a utilities class which has a public static void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {...} function and a public static boolean onOptionsItemSelected(MenuItem item) {...}?
public class Utils {
public static void onCreateOptionsMenu(Menu menu, MenuInflater inflater ){
//... create default options here
}
public static boolean onOptionsItemSelected(MenuItem item) {
//... see if you want to handle the selected option here, return true if handled
}
}
then from you Activity you can do this:
public class YourActivity extends Activity {
// ...
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater ){
Utils.onOptionsItemSelected(menu, inflater);
//... add other options here
}
public boolean onOptionsItemSelected(MenuItem item) {
boolean handled = Utils.onOptionsItemSelected(item);
if (!handled) {
switch(item.getItemId()) {
case R.id.menu_sign_out:
//... deal with option
break;
//.. deal with other options
}
}
return handled;
}
You may want to change the exact implementation of this depending on how you build it in to your app - ie you may not want the utils methods to be static as you may require some state to be maintained in there, but this should work.

Re-using Options menu code

Is there a convenient way of showing the same Options menu options in multiple Activities?
Example: In my app, I display a TV Guide in one of three ways.
Seven day guide (TabActivity with 7 tabs)
All channels 'Now showing' (ListActivity)
All shows today by start time (Activity - could be changed easily to ListActivity)
For the Options menu in the TabActivity, the code is quite simple...
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
menu.clear();
inflater.inflate(R.menu.gv_options_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.view:
...
...
}
}
...but at the moment it seems I need to copy/paste it to the other two Activities which I don't like doing. If I change the Options menu code for one I'll need to do it for the other two also.
The only alternative I can think of is I have a 'helper' class (POJO) to which I could add a method and pass the context into to allow use of the getMenuInflator() method and another method I could pass the result of item.getItemId() into to process with the switch-case.
What is the normal way of having multiple Activities with the same Options menu?
Create a simple separate class with these two methods:
public class MyMenuHandler {
private Activity mActivity;
public MyMenuHandler(Activity activity) {
mActivity = activity;
}
public boolean onPrepareOptionsMenu(Menu menu) {
MenuInflater inflater = mActivity.getMenuInflater();
menu.clear();
inflater.inflate(R.menu.gv_options_menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.view:
...
}
}
}
In your activities override those callback methods and redirect the call to an instance of your MyMenuHandler class:
public class MyActivity1 extends TabActivity {
private MyMenuHandler mMenuHandler;
#Override
public void onCreate(Bundle savedInstanceState) {
...
mMenuHandler = new MyMenuHandler(this);
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// you may also add here some items which are specific
// for one activity, not for the others
...
return mMenuHandler.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// handle selection of your specific items here,
// if none of them has been selected call mMenuHandler method
...
return mMenuHandler.onOptionsItemSelected(item);
}
}
This will let you hold in one place the code which respond to selection of your basic menu items, so there will be no need to worry about copy-pasting it to all activities which are to have the same menu.
One approach is to use inheritance with your Activities. Create a base Activity that implements the options menu methods and then each child Activity will gain that functionality. This is the recommended approach on the Android developer site:
Tip: If your application contains multiple activities and some of them provide the same Options Menu, consider creating an activity that implements nothing except the onCreateOptionsMenu() and onOptionsItemSelected() methods. Then extend this class for each activity that should share the same Options Menu. This way, you have to manage only one set of code for handling menu actions and each descendant class inherits the menu behaviors.
Unfortunately this won't work for you as you are not inheriting from Activity itself but differing subclasses of it, but that is the 'normal' way to do it.
You can encapsulate your action menu in a fragment. In this way you only need to add the fragment in the onCreate menu of your activity.
You need to call setHasOptionsMenu once the fragment is created.
To add the add fragment use a tag instead of a layout id.

Same option menu in all Activities in Android

I have 10-15 activities in my project. I want to have the option menu mostly in all Activities. Then is their any way we can do it at one place and it appears in all activities.
Also, I will like to hide the option menu in some. So, is it possible or I have to write option menu code in all activities.
Regards
Sunil
Create a Class (say BaseActivity) that extends Activity, and override onCreateOptionsMenu and onOptionsItemSelected functions.
public class BaseActivity extends Activity {
// Activity code here
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.options_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.item:
// do what you want here
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
Now, in the other 15-16 activities, instead of extending an Activity, you should extend BaseActivity.
public class FooActivity extends BaseActivity {
// Activity code here
}
This way, all your activities derive the options menu. For activities where you want the options menu disabled, you can override it again in that particular activity.
public class BarActivity extends BaseActivity {
// Activity code here
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Do Nothing
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Do Nothing
}
}
Hopefully, it doesn't give you problems in the manifest file.
The solution to this problem is in your new activity add this menu method.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_home_page, menu);
menu.removeItem(R.id.logout);
return true;
}
In each activity this method will automatically appear.
If it doesn't then add it with the inflate call. It requires two parameters, an xml resource(the same one that you used in your original activity), and the menu object that is pass into the onCreateOptionsMenu method.
menu.removeItem will remove the menu item of whatever resource id you pass to it.
I hope this helps those who are facing this problem.
Thank you, and happy to share this post.
It is not enough to just extend the BaseActivity, you must also call super.onCreateOptionsMenu(menu) and super.onOptionsItemSelected(item) like this in your other activities:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
//getMenuInflater().inflate(R.menu.menu_second, menu); <- remove this
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}

Categories

Resources