Override an Override? - java

I have an Activity in a Library that has a menu in it. The menu has all the standard attributes as well as the #Override on onCreateOptionsMenu and onOptionsItemSelected.
In my actual project which imports above library I have another activity that extends teh above activity. For this specific implementation of this program I want to have a different menu on this activity so inside this activities code base add add onCreateOptionsMenu and onOptionsItemSelected with the proper #Override, but i get the menu from the Library, not the override in the library.
What could I be doing wrong?
Base Class:
public class ListItems extends ListActivity {
public static final int LOGOUT = 0;
public static final int HISTORY = 1;
public static final int REFRESH = 2;
#Override
public boolean onCreateOptionsMenu(Menu menu){
menu.add(0, LOGOUT ,0,"Log Out");
menu.add(0,HISTORY,0,"Order History");
menu.add(0,REFRESH,0,"SMS");
return true;
}
#Override
public boolean onOptionsItemSelected (MenuItem item){
TextView textView = (TextView)findViewById(com.imobileminutes.library.R.id.text);
switch (item.getItemId()){
case LOGOUT:
Intent logOut = new Intent(ListItems.this,MainScreen.class);
startActivity(logOut);
finish();
return true;
case HISTORY:
Intent orderHistory = new Intent(this,OrderItems.class);
startActivity(orderHistory);
return true;
case REFRESH:
Intent orderHistory = new Intent(this,OrderItems.class);
startActivity(orderHistory);
return true;
}
return false;
}
}
Override Class
public class ListItems extends com.imobileminutes.library.ListItems {
static final int SMS = 2;
#Override
public boolean onCreateOptionsMenu(Menu menu){
Log.d("onCreateOptionsMenu", "My onCreateOptionsMenu ran");
Toast.makeText(getApplicationContext(), "HEllo Menu Created", Toast.LENGTH_LONG).show();
super.onCreateOptionsMenu(menu);
return true;
}
#Override
public boolean onOptionsItemSelected (MenuItem item){
Log.d("onCreateOptionsMenu", "My onOptionsItemSelected ran");
Toast.makeText(getApplicationContext(), "HElloonOptionsItemSelected", Toast.LENGTH_LONG).show();
super.onOptionsItemSelected(item);
return false;
}
}
CONCLUSION
It ended up being that my library was calling ListItems.this and CreateAccount.this which was referencing the activities in the library not in the extended classes.
I added an intent for every extended activity type and nwo call that, thus bringing up the extended activity rather than the base activity.
Thanks for the help guys.

Either you didn't copy and paste the code correctly, or part of the problem is in your base class, which provides the same definition for onCreateOptionsMenu as your derived class:
#Override
public boolean onCreateOptionsMenu(Menu menu){
menu.add(0, LOGOUT ,0,"Log Out");
menu.add(0,HISTORY,0,"Order History");
menu.add(0,REFRESH,0,"SMS");
return true;
}
That last line can't be right -- I'm pretty sure the last line of the base class implementation should be: menu.add(0,REFRESH,0,"REFRESH");.
But that last line of onCreateOptionsMenu also needs to be changed in the derived class:
#Override
public boolean onCreateOptionsMenu(Menu menu){
menu.add(0, LOGOUT ,0,"Log Out");
menu.add(0, HISTORY,0,"Order History");
menu.add(0, SMS,0,"SMS"); // Use the correct constant (SMS instead of REFRESH)
return true;
}
EDIT: Also, you can simplify the code a bit, by re-using the superclass implementation for those choices where you're currently just copying the superclass code (LOGOUT and HISTORY):
#Override
public boolean onOptionsItemSelected (MenuItem item){
TextView textView = (TextView)findViewById(com.imobileminutes.library.R.id.text);
// Left this as a 'switch'; you might want to use an 'if' instead.
switch (item.getItemId()){
case SMS:
AppClass.sendSMS("8135551212", "Hello Jason");
return true;
}
return super.onOptionsItemSelected(item);
}

Use the fully qualified name on the import my suspicion is you are referencing the wrong class.

Turns out it was the way I was calling the Activitys. I was calling the Activity directly in the Library rather than calling the overridden one. Since the overriden ones will be dynamic depending on the Apps naming, I ended up using Intents that will search for the callers packagename and append the specific intent onto it.
As soon as I set all that up, my SMS menu item showed.

Related

Android onBackPressed() is not being called?

in my MainActivity, which extends from AppCompatActivity, I want to override the onBackPressed method like so:
#Override
public void onBackPressed() {
Log.d("MainActivity","onBackPressed");
Toast.makeText(getApplicationContext(),"onBackPressed",Toast.LENGTH_SHORT).show();
}
but onBackPressed does not get called. How ever if I do not override onBackPressed, the application closes, when I press the backbutton and if I do override it it doesn't.
The rest of my activity looks like this:
public class MainActivity extends AppCompatActivity {
private Toolbar toolbar;
private Drawer drawer;
private FloatingActionButton fab_test;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
fab_test = (FloatingActionButton) findViewById(R.id.fab_test);
fab_test.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(getApplicationContext(),"FAB Test pressed",Toast.LENGTH_SHORT).show();
}
});
buildDrawer();
getSupportFragmentManager().beginTransaction().add(R.id.fragmentContainer,page).commit();
}
#Override
public void onBackPressed() {
Log.d("MainActivity","onBackPressed");
Toast.makeText(getApplicationContext(),"onBackPressed",Toast.LENGTH_SHORT).show();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return true;
}
}
EDIT: I'm talking about the hardware-backbutton(not the actionbar one)
This question is already answered, but I feel to clear something here in this topic. Most comments and answeres point out to use super.onBackPressed() and that this is the cause of the not working method onBackPressed(). But that is not correct and important to let other beginners know. The method onBackPressed() does not need to use super.onBackPressed() . onBackPressed()also works if somebody, for example, comment super.onBackPressed() out.
As the questionier has written, he won´t use super.onBackPressed() because it will close the activity. So, the cause of this why it isn´t working, could be seperated into three possible causes:
The Log doesn´t work because of a wrong filter in the logcat console
The Toast dosn´t work because of the wrong passed context
The OS is implemented wrong by the supplier.
Usually, the toast works by passing the correct context. In the case of questioner, simply passing this .
#Override
public void onBackPressed() {
Log.d("MainActivity","onBackPressed");
Toast.makeText(this,"onBackPressed",Toast.LENGTH_SHORT).show();
}
For the Log, simply set the correct filter on logcat.
I don´t care if somebody give downvotes now, but it must be clear for other beginners, that super.onBackPressed() must not be used.
Anyway, the use of onKeyDown() also is a solution.
The onBackPressed() is a default action called from onKeyDown() in API < 5 and a default action called from onKeyUp() from API level 5 and up. If onKeyUp() does not call super.onKeyUp(), onBackPressed() will not be called.
Documentation onKeyDown()
Documentation onKeyUp().
#Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
/*
* without call to super onBackPress() will not be called when
* keyCode == KeyEvent.KEYCODE_BACK
*/
return super.onKeyUp(keyCode, event);
}
Also another reason that onBackPressed() may not be called is because you are using the soft back button on the actionbar, it that case the following is needed:
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
You are missing, super.onBackPressed();
#Override
public void onBackPressed() {
super.onBackPressed();
}
or you can use
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
//replaces the default 'Back' button action
if(keyCode==KeyEvent.KEYCODE_BACK) {
// something here
finish();
}
return true;
}
thanks
make sure you are not calling onkeydown in your super view as it handles the back button clicking first.
working fine onKeyDown function return type false;
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return false;
}
For whoever is wondering, as most functionality is deprected API 30>, the following will surely help you a lot.
public class MainActivity extends AppCompatActivity {
private OnBackPressedCallback onBackPressedCallback;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
onBackPressedCallback = new OnBackPressedCallback(true) {
#Override
public void handleOnBackPressed() {
// Your business logic to handle the back pressed event
Log.d(TAG, "onBackPressedCallback: handleOnBackPressed");
}
};
getOnBackPressedDispatcher().addCallback(this, onBackPressedCallback);
}
}
Just Remove super.onBackPressed() it will work

How to determine which child has called a parent’s method

I am using the same tabBar across multiple Activities. And since there are extensive logic involved for onOptionsItemSelected, I want to write the relevant methods once and then reuse them. Hence I am deciding to created a super class called CustomActionBarActivity and then have the children activities extend it. One particular problem I need help with is how can I tell which child has caused the onOptionsItemSelected to be called? To elucidate, I will present the general code and then a failed attempt at a solution.
Here is the general code
public class CustomActionBarActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.tab_dog:
startActivity(new Intent(this, DogActivity.class));
return true;
case R.id.tab_cat:
startActivity(new Intent(this, CatActivity.class));
return true;
case R.id.tab_mouse:
startActivity(new Intent(this, MouseActivity.class));
return true;
case R.id.tab_goose:
startActivity(new Intent(this, GooseActivity.class));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
Failed attempt
If I try, for instance,
case R.id.tab_dog:
if(!(this instanceof DogActivity))
startActivity(new Intent(this, DogActivity.class));
then I get a compile error such that CustomActionBarActivity is not compatible with DogActivity. Thanks for any help you can provide.
Instead of having your parent class inspect the children using reflection (which is pretty fragile since it doesn't scale with the number of children subclasses you create), maybe you could take advantage of dynamic dispatch instead.
For example, maybe you could declare an abstract method in your parent activity like:
protected abstract void onTabItemSelected(MenuItem item);
Then your children activities can override this method depending on the desired behavior. For example, DogActivity might implement it like this:
protected boolean onTabItemSelected(MenuItem item) {
if (item.getItemId() != R.id.dog_tab) {
startActivity(new Intent(this, DogActivity.class));
return true;
}
return false;
}
The onOptionsItemSelected method would then be implemented like this:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (onTabItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
Let me know if I misunderstood the question. Either way, you might be able to modify this approach to suit your use case.

Android SDK - Eclipse - how to use some piece of code in more than one class

I'm new in Java (Eclipse), and I want to know if there is any way to create a file with some piece of code and just call it in the class.
Because I have a lot of different classes for different results but there is some code that don't change from one to another (the menu for example) and I want to make this more practical when I have to adapt that code, without change class by class.
Is there any way to do this ?
I accomplish this in my projects with classes I call Helper classes. I got the idea from the GoogleIO app source code. They have a class called the ActivityHelper. It does exactly what your are talking about, puts code that is used over and over in one place. Here is my MenuHelper class as an example. My menu is the same for a lot of my Activities so it made sense to do it this way...
public class MenuHelper {
public static void build(Menu menu) {
menu.add(Menu.NONE, Key.Activity.LOGOUT, 0, R.string.label_logout)
.setIcon(android.R.drawable.ic_menu_close_clear_cancel);
menu.add(Menu.NONE, Key.Activity.FEEDBACK, 0,
com.bytebenderapps.dbitly.R.string.label_feedback).setIcon(
android.R.drawable.ic_menu_send);
}
public static boolean onMenuItemSelected(int featureId, MenuItem item,
Context context) {
switch (item.getItemId()) {
case Key.Activity.LOGOUT:
removeCredentials(context);
startLoginActiviy(context);
break;
case Key.Activity.FEEDBACK:
startFeedbackActivity(context);
break;
}
return true;
}
private static void startLoginActiviy(Context context) {
Intent intent = new Intent(context, LoginActivity.class);
context.startActivity(intent);
}
private static void removeCredentials(Context context) {
Editor editor = PreferenceManager.getDefaultSharedPreferences(context)
.edit();
editor.clear();
editor.commit();
}
public static void toggleLogoff(Menu menu, boolean userLoggedIn) {
MenuItem item = menu.findItem(Key.Activity.LOGOUT);
item.setEnabled(userLoggedIn);
}
private static void startFeedbackActivity(Context context) {
context.startActivity(new Intent(context, FeedbackActivity.class));
}
}
And then the implementation in one of my activities
public class MyActivity {
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuHelper.build(menu);
return true;
}
#Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
super.onMenuItemSelected(featureId, item);
return MenuHelper.onMenuItemSelected(featureId, item, this);
}
}
It will help us solve your doubts if you post some piece of code or give us a better clue what you want to achieve and what is your current approach.
General answer would be that you can and should separate your code in different classes, but from case to case there are different approaches to apply
anyhow this post/thread can be useful to you.

Using Interface to implement code on all activities

I am trying to implement some code on every activity and don't want to copy and page the code into each activity.
Originally I just had a parent activity with the code then extended all of the others but I couldn't do this on ListActivities or ExpandableListActivities.
I think this will be done by using an interface class then having each activity implement this. However when I try to do this Eclipse gives me an error and says to remove the method body.
Here is what I have so far
import android.content.Intent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;
public interface MenuOptions {
/**
* Method called when the hardware menu button is called. Uses optionmenu.xml for layout
*/
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.optionmenu, menu);
return true;
}
/**
* Event listener for the options menu. If home is pressed user is sent to home screen. If settings is pressed user is sent to setting screen
* User is passed as an extra
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent nextIntent = null;
switch (item.getItemId()) {
case R.id.home:
Toast.makeText(this, "You pressed the icon!", Toast.LENGTH_LONG).show();
nextIntent = new Intent(this, Home.class);
break;
case R.id.settings:
Toast.makeText(this, "You pressed the text!", Toast.LENGTH_LONG).show();
nextIntent = new Intent(this, Settings.class);
break;
}
nextIntent.putExtra("user", user);
startActivity(nextIntent);
return true;
}
}
Interface classes in Java should only contain method signatures and no implementation. Therefore you have to create a base class:
public class MenuOptions extends Activity {
/**
* Method called when the hardware menu button is called. Uses optionmenu.xml for layout
*/
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.optionmenu, menu);
return true;
}
/**
* Event listener for the options menu. If home is pressed user is sent to home screen. If settings is pressed user is sent to setting screen
* User is passed as an extra
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent nextIntent = null;
switch (item.getItemId()) {
case R.id.home:
Toast.makeText(this, "You pressed the icon!", Toast.LENGTH_LONG).show();
nextIntent = new Intent(this, Home.class);
break;
case R.id.settings:
Toast.makeText(this, "You pressed the text!", Toast.LENGTH_LONG).show();
nextIntent = new Intent(this, Settings.class);
break;
}
nextIntent.putExtra("user", user);
startActivity(nextIntent);
return true;
}
}
And your activity:
public class YourActivity extends MenuOptions {
/*...*/
}
Interfaces are not allowed to have method bodies. This is because it describes the interface of an object, not the method itself.
The problem with the same menu options shared by all activities is a common one. The easiest way of handling this is to define 2 or 3 superclasses (for ListActivities and MapActivities).
As far as I know an interface only describes what methods must be supported by a class implementing the interface.
This is the difference between implementing an interface and extending a class.
- so you can't write an interface thats used by all your classes, only define a set of methods which must be defined by any class implementing that interface
I would say your best bet is to create a new class which can be used by all your activities to do the same job. Then you'll need an instance of that class which is created and initialised by each activity onCreate (or somewhere else)
Alternately you may find you can make your new class static so you don't need to create an instance, just call a static method at the right times
One other way of doing it is to create a subclass of Activity which includes the standard behaviour and create all your activities as a subclass of this. Where you have ListActivities (for instance) you'll have to do some recoding, making them subclassed activities containing lists

Methods available across an app?

I'm 100% sure this is going to be one of those newbie questions, but here it goes...
Is there a way I can write a method in one activity and be able to access it from the others?
Example:
I have six activites in my app, each with it's own menu.xml because the options available for each need to be different, and I have these menus & menuitems set up as shown:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.calculator_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
//Handle item selection
switch (item.getItemId()) {
case R.id.menuItem_calculator_Help:
helpDialogGo();
return true;
case R.id.menuItem_calculator_Settings:
//settingsActivityGo();
return true;
case R.id.menuItem_calculator_Share:
shareGo();
return true;
case android.R.id.home:
// app icon in Action Bar clicked; go home
Intent uptohome = new Intent(this, Main.class);
uptohome.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(uptohome);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
The an example of one of these methods is:
private void helpDialogGo() {
Toast.makeText(this, "help", Toast.LENGTH_LONG).show();
AlertDialog.Builder alt_bld = new AlertDialog.Builder(this);
alt_bld.setMessage("Sorry, no help has been written since this application is still in development. This is a prerelease version.")
.setCancelable(false)
.setPositiveButton("Cool", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Action for 'Yes' Button
dialog.cancel();
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Action for 'NO' Button
dialog.cancel();
}
});
AlertDialog alert = alt_bld.create();
// Title for AlertDialog
alert.setTitle("Pixel Help");
// Icon for AlertDialog
alert.setIcon(R.drawable.question);
alert.show();
}
So is there a way to have this custom method shared among all the activities and run it when the button is pressed in each of them, as to avoid having large amounts of code replicated across my app?
And if so, are there any potholes that I may hit? (Some of the menu items are going to bring up dialogs, others will take the user to a new activity)
Do you have similar menuitems in every activity? i.e. same number of items but different behaviour? If yes...
How about creating a BaseActivity which overrides onCreateOptionsMenu and onOptionsItemSelected() methods.. (As you have given in the above example). All your activities should inherit from this BaseActivity and then override the menu handling methods. eg. helpDialogGo() will go to the new class.
so the BaseActivity will have onCreateOptionsMenu and onOptionsItemSelected() methods. Plus all the menuItem actions (i.e. helpDialogGo() etc) as empty methods. The inherited classes will overide menuItem Actions.
If the menuitems are not similar in each activity, you are better off creating menu for each activity.
EDIT:
Not sure what you expect more. I thought I made it clear. Let me try again.
Class BaseActivity extends Activity.
BaseActivity extends Activity {
// Copy your onCreateOptionsMenu() and onOptionsItemSelected() methods here
protected void helpDialogGo() { }
// ... other methods
}
Class MyActivity1 extends BaseActivity.
MyActivity1 extends BaseActivity {
// Copy your helpDialogGo() code in full here and then make
// any specific changes to menu behaviour based on activity.
}
Class MyActivity2 extends BaseActivity
MyActivity2 extends BaseActivity {
// Copy your helpDialogGo() code in full here and then make
// any specific changes to menu behaviour based on activity.
}
One way, of course, is to created some custom classes that encapsulate your desired functionality - and use those within your activities. It's a better abstraction than placing the implementation directly in the Activity(s) itself (all things being equal, and based on what you described so far).
Any time you find yourself duplicating an implmentation that's a flag reminding you this is a good place to roll that code into its own class - usually.

Categories

Resources