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.
Related
I'm working on an Android TV app that plays a video and I'm using PlaybackSupportFragment to implement the on-screen controls.
I am, however, not able to fully hide the secondary actions (thumbs up, thumbs down, repeat, ...). Actually I was able to hide the buttons, however the "three dots" button still stays there. And I have not figured out how to hide this "three dots" button.
I tried not to add any secondary actions buttons. But no luck. There are no secondary buttons but the "three-dots" button is still there.
public class MySupportFragment extends PlaybackSupportFragment {
MyPlaybackControlGlue myGlue = new MyPlaybackControlGlue(context);
...
myGlue.setHost(new PlaybackSupportFragmentGlueHost(this));
...
}
public class MyPlaybackControlGlue extends PlaybackControlGlue{
...
#Override
protected void onCreateSecondaryActions(ArrayObjectAdapter adapter) {
//Do not add any secondary actions to the adapter
}
#Override
protected void onCreatePrimaryActions(SparseArrayObjectAdapter adapter) {
//No need to add any other actions here. The Play/Pause action is enough.
}
}
I think I figured it out.
Do not add any secondary actions in the "onCreateSecondaryActions" method.
But also call following method so that the "three dots" button is not shown.
getControlsRowPresenter().setSecondaryActionsHidden(false)
For example like so
#Override
protected void onCreateControlsRowAndPresenter() {
super.onCreateControlsRowAndPresenter();
getControlsRowPresenter().setSecondaryActionsHidden(false);
}
The code that have you posted in the question worked for me, however I am extending VideoPlayerGlue
public class CustomPlaybackControlGlue extends VideoPlayerGlue {
public CustomPlaybackControlGlue(Context context, LeanbackPlayerAdapter playerAdapter, OnActionClickedListener actionListener) {
super(context, playerAdapter, actionListener);
}
#Override
protected void onCreatePrimaryActions(ArrayObjectAdapter adapter) {
//Do not add any secondary actions to the adapter
}
#Override
protected void onCreateSecondaryActions(ArrayObjectAdapter adapter) {
//No need to add any other actions here. The Play/Pause action is enough.
}
}
I have that AlertDialog that is showing twice, and I have no clue why! The problem doesn't apply only for AlertDialogs; However, it applies for "Activities" as well.
Note that i'm facing the problem with Android 4.0.3.However, When I run the application on Android 2.3.6, everything works normally.
In order to solve my problem with Activities, I have set in the manifest file :
android:launchMode="singleInstance" and it worked.
However, this cannot be done for AlertDialogs as they do not have any references in the manifest file to set it to singleInstance or something like that.
Some people told me to put a BreakPoint in order to check my code after show(). But I do not know how to put a BreakPoint and how to check.
EDIT:
I am using HoloEverywhere and SherlockActionBar. I do not know how much effect they do have.
#Override
public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
switch(item.getItemId())
{
case R.id.action_one:
alertDialog();
break;
case R.id.action_two:
Intent i = new Intent(this,Info.class);
startActivity(i);
overridePendingTransition(0, 0);
break;
}
return super.onOptionsItemSelected(item);
}
private void alertDialog(){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("My title");
AlertDialog alert= builder.create();
alert.show();
}
in case R.id.action_two it's working fine after setting the launchMode="singleInstance" in the manifest file. However, in case R.id.action_one which launches the AlertDialog it's still opening twice.
#Override
public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) {
// TODO Auto-generated method stub
com.actionbarsherlock.view.MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.action_options, menu);
return super.onCreateOptionsMenu(menu);
}
Change this line:
return super.onCreateOptionsMenu(menu);
to:
return true;
When you call super.onCreateOptionsMenu, it attaches additional onMenuItemClickListener listeners to each item in the menu, so that would cause 2 clicks to be recorded.
(PS: I actually figured this out and was going to post it, but had to take a call. No joke)
Here's a very simplified version of my Activity:
public class Search extends Activity {
//I need to access this.
public SearchResultsAdapter objAdapter;
public boolean onOptionsItemSelected(MenuItem itmMenuitem) {
if (itmMenuitem.getItemId() == R.id.group) {
final CharSequence[] items = {"Red", "Green", "Blue"};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(itmMenuitem.getTitle());
builder.setSingleChoiceItems(lstChoices),
0, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
//I need to access it from here.
}
});
AlertDialog alert = builder.create();
alert.show();
return true;
}
}
}
When the menu button is pressed, my applications pops up an AlertDialog. When creating the AlertDialog and in-line onClickListener is attached to the each of the items in the dialog. I need to access the objAdapater variable that is defined in my Search activity. I don't have access to the search instance within my onClickListener so I can't access it. I have a little bit of a soup in my code with the passing of the Activity instance everywhere. Maybe I'm doing something wrong.
How would I get access to the Activity (Search instance) from within my onClickListener so I can access it's methods and variables.
Thank you.
Using Search.this.objAdapter to access objAdapter from the listener should work.
Search.this refers to the current instance of Search and allow you to access its fields and methods.
Make your activity implement OnClickListener:
public class Search extends Activity implements DialogInterface.OnClickListener { ...
Add the onclick method to your activity:
public void onClick(DialogInterface dialog, int item) {
//I need to access it from here.
}
Then pass your activity as the listener:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(itmMenuitem.getTitle());
builder.setSingleChoiceItems(lstChoices),0, this);
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
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.