Android Development: Passing "menu" class to other activity - java

I have a menu.java and in this file I have lines of codes to allow the user to press the menu button and "MENU1" and "MENU2" will appear on their android phone. However, I have multiple java classes, and each java classes is its own activity. What would I need to do to have this menu class function in each activity without putting every line of code in the menu.java into each other .java
This is my Menu.java
public class Menu extends Activity {
public boolean onCreateOptionsMenu(android.view.Menu menu){
super.onCreateOptionsMenu(menu);
MenuInflater a = getMenuInflater();
a.inflate(R.menu.main_menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item){
switch (item.getItemId()){
case R.id.MENU1:
startActivity(new Intent("com.helloworld.test.MENU1"));
return true;
case R.id.MENU2:
startActivity(new Intent("com.helloworld.test.MENU2"));
return true;
}
return false;
}
}

You could create a base activity that all your other activities extend:
public class BaseActivity extends Activity {
public boolean onCreateOptionsMenu(android.view.Menu menu){
super.onCreateOptionsMenu(menu);
MenuInflater a = getMenuInflater();
a.inflate(R.menu.main_menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item){
switch (item.getItemId()){
case R.id.MENU1:
startActivity(new Intent("com.helloworld.test.MENU1"));
return true;
case R.id.MENU2:
startActivity(new Intent("com.helloworld.test.MENU2"));
return true;
}
return false;
}
}

Related

How to hide and show menu-items on action bar

I have a menu item system implemented into my action bar, I am trying to get a menu item to become invisible once clicked and then to become visible again after clicking a different menu item.
The reason for this is to prevent a menu item getting clicked more than once.
I have done the following attempt below however, I get a null pointer exception error. I believe I may need to implement some if statements here but I'm not sure how to go about it.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.tasklistmenu,menu);
return true;
}//OnCreateOptionsMenu
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.allTasks:
item.setVisible(false);
MenuItem notStartedStatus = findViewById(R.id.notStartedStatus);
notStartedStatus.setVisible(true);
MenuItem inProgressStatus = findViewById(R.id.inProgressStatus);
inProgressStatus.setVisible(true);
MenuItem completeStatus = findViewById(R.id.completeStatus);
completeStatus.setVisible(true);
Log error
Attempt to invoke interface method 'android.view.MenuItem
android.view.MenuItem.setVisible(boolean)' on a null object reference
NEW CODE
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem allTasks = menu.findItem(R.id.allTasks);
MenuItem notStartedStatus = menu.findItem(R.id.notStartedStatus);
MenuItem completeStatus = menu.findItem(R.id.completeStatus);
MenuItem inProgressStatus = menu.findItem(R.id.inProgressStatus);
if(tasksIsVisible) {
allTasks.setVisible(true);
} else {
allTasks.setVisible(false);
}
if(notStartedIsVisible) {
notStartedStatus.setVisible(true);
} else {
notStartedStatus.setVisible(false);
}
if(completeIsVisible) {
completeStatus.setVisible(true);
} else {
completeStatus.setVisible(false);
}
if(inProgressIsVisible) {
inProgressStatus.setVisible(true);
} else {
inProgressStatus.setVisible(false);
}
return true;
}//OnPrepareOptions
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.allTasks:
tasksIsVisible = false;
invalidateOptionsMenu();
Its not enough to change the isVisible variable. You have to call the setVisible() method every time you want to change the visibility. That method does more than just setting a boolean value, so just changing a boolean value will not do.
After changing the isVisible value to false, you need to call invalidateOptionsMenu() which will re-launch the menu by calling onPrepareOptionsMenu() again.
public boolean onPrepareOptionsMenu(Menu menu)
{
MenuItem notStartedStatus = menu.findItem(R.id.notStartedStatus);
if(isVisible)
{
notStartedStatus.setVisible(true);
}
else
{
notStartedStatus.setVisible(false);
}
return true;
}
Try this code for making the menu items unvisible:
...
isVisible = false;
invalidateOptionsMenu();
...

Android WebView - Text Selection Listener in 2018

I will create an app that user will be enter the website url to my app. Then I am showing this page in my app using WebView.
As you know, when user clicks the any text in the context a little bit long, android cursor will appear then we can select text as many as we want.
After selection, we will see that "COPY, SHARE, SELECT ALL" etc..
My question is that when user selects text, I want to show them different options. Let's say "MyCOPY, SendTwitter, SendMessage".
How can i do that?
What I did so far?
I am just creating bar at the top of the app. But I don't want this.
Here is the code:
private WebView view;
private final String TAG = MainActivity.class.getSimpleName();
private ActionMode actionMode;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.view = findViewById(R.id.webView);
view.loadUrl("https://stackoverflow.com/questions/28385768/android-how-to-check-for-successful-load-of-url-when-using-webview-loadurl");
view.setWebViewClient(new MyWebViewClient());
Log.d(TAG, view.getUrl());
view.setOnLongClickListener((v) -> {
if (actionMode != null)
return false;
actionMode = startSupportActionMode(actionCallBack);
return true;
});
}
Where startSupportActionMode(actionCallBack) is
private ActionMode.Callback actionCallBack = new ActionMode.Callback() {
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
actionMode.getMenuInflater().inflate(R.menu.custommenu, menu);
actionMode.setTitle("Choose");
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
switch (menuItem.getItemId()){
case R.id.example_item_1:
Toast.makeText(MainActivity.this, "Option 1 selected", Toast.LENGTH_SHORT).show();
actionMode.finish();
return true;
case R.id.example_item_2 :
Toast.makeText(MainActivity.this, "Option 2 selected", Toast.LENGTH_SHORT).show();
actionMode.finish();
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode actionMode) {
actionMode = null;
}
};
You can implement the ActionMode.Callback interface to create your own menu upon selection.
An action mode's lifecycle is as follows:
onCreateActionMode(ActionMode, Menu) once on initial creation
onPrepareActionMode(ActionMode, Menu) after creation and any time the
ActionMode is invalidated
onActionItemClicked(ActionMode, MenuItem)
any time a contextual action button is clicked
onDestroyActionMode(ActionMode) when the action mode is closed
just make sure that your text views allow for text selection (android:textIsSelectable="true")
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
// Called when the action mode is created; startActionMode() was called
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Inflate a menu resource providing context menu items
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
return true;
}
// Called each time the action mode is shown. Always called after onCreateActionMode, but
// may be called multiple times if the mode is invalidated.
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false; // Return false if nothing is done
}
// Called when the user selects a contextual menu item
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_share:
shareCurrentItem();
mode.finish(); // Action picked, so close the CAB
return true;
default:
return false;
}
}
// Called when the user exits the action mode
#Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
}
};
then call startActionMode() to enable the contextual action mode when appropriate (source), such as inside a setOnLongClickListener

menu share across multiple activities [duplicate]

This question already has answers here:
Android: Best way to share code between activities? [closed]
(2 answers)
Closed 4 years ago.
I have multiple activities sharing the same options menu so in my every activity, I am doing
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.settings:
Intent opensettings = new Intent(this, SettingsActivity.class);
startActivity(opensettings);
return true;
case R.id.help:
...others
default:
return super.onOptionsItemSelected(item);
}
}
Is there a way to share the above code amongst different activities?
I have tried adding a class
class MenuHelper{
Context ctx;
public MenuHelper(Context context){
ctx=context
}
public boolean openMenuItems(Menu item){
switch(item.getItemId()) //here .getItemId() doesnt work{
case R.id.settings: //R.id.settings not found
}
}
}
But am stuck in my helper class. How do I proceed so that in my different activities I only have to
MenuHelper menuitems = new MenuHelper(this);
menuitems.openMenuItems(menu)
You can have a BaseActivity where you can put the common implementation across your activities and then have other activities extend the BaseActivity
public class BaseActivity extends AppCompatActivity {
// Any other common methods
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.settings:
Intent opensettings = new Intent(this, SettingsActivity.class);
startActivity(opensettings);
return true;
case R.id.help:
...others
default:
return super.onOptionsItemSelected(item);
}
}
}
You can now create your activities extending BaseActivity:
public class MainActivity extends BaseActivity {
}
Why not just create a super class for your common Activities? If you create a super class, like so:
public class MySharedMenuActivity extends Activity {
#Override
public boolean onOptionsItemSelected(MenuItem item) { ... }
}
Then, if you extend that class for the activities you want, you will be able to access the shared menu.
Inheritance
As the other responses suggest, you could use inheritance to provide this sort of functionality. That does break the "favor composition over inheritance rule", but may be the practical solution for simple applications.
Composition
I think you are on the right path with creating a "menu helper" of sorts. I'd prefer a name such as OptionsMenuHandler and would probably write it like this:
public class OptionsMenuHandler {
private final Activity activity;
public OptionsMenuHandler(Activity activity) {
this.activity = activity;
}
public boolean onCreateOptionsMenu(Menu menu) {
// do menu inflation here.
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.settings:
Intent openSettings = new Intent(activity, SettingsActivity.class);
activity.startActivity(openSettings);
return true;
case R.id.help:
// others
default:
return false;
}
}
public boolean onPrepareOptionsMenu(Menu menu) {
// do menu preparation here.
}
}
and use it like this:
public class TestActivity extends AppCompatActivity {
private final OptionsMenuHandler optionsMenuHandler = new OptionsMenuHandler(this);
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return optionsMenuHandler.onCreateOptionsMenu(menu) ||
super.onCreateOptionsMenu(menu);
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
return optionsMenuHandler.onPrepareOptionsMenu(menu) ||
super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return optionsMenuHandler.onOptionsItemSelected(item) ||
super.onOptionsItemSelected(item);
}
}
This does require extra boiler plate in each Activity. It also creates abstraction. The abstraction is justified because it keeps the code DRY. I also like the fact that business logic isn't tucked away and invisible inside a parent class somewhere... the composition makes the location of the business logic a lot more obvious.
Base Activity that Supports Composition
Another option would be to support composition in a base Activity as follows...
Create a well defined abstraction:
public interface OptionsMenuHandler {
boolean onCreateOptionsMenu(Menu menu);
boolean onOptionsItemSelected(MenuItem item);
boolean onPrepareOptionsMenu(Menu menu);
}
Create an implementation for the abstraction:
public class DefaultOptionsMenuHandler implements OptionsMenuHandler {
private final Activity activity;
public DefaultOptionsMenuHandler(Activity activity) {
this.activity = activity;
}
public boolean onCreateOptionsMenu(Menu menu) {
// do menu inflation here.
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.settings:
Intent openSettings = new Intent(activity, SettingsActivity.class);
activity.startActivity(openSettings);
return true;
case R.id.help:
// others
default:
return false;
}
}
public boolean onPrepareOptionsMenu(Menu menu) {
// do menu preparation here.
}
}
Support composition in the base class (ie base class has a setter):
public class BaseActivity extends AppCompatActivity {
#Nullable
private OptionsMenuHandler optionsMenuHandler;
protected void setOptionsMenuHandler(OptionsMenuHandler optionsMenuHandler) {
this.optionsMenuHandler = optionsMenuHandler;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return optionsMenuHandler != null
? optionsMenuHandler.onCreateOptionsMenu(menu)
: super.onCreateOptionsMenu(menu);
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
return optionsMenuHandler != null
? optionsMenuHandler.onPrepareOptionsMenu(menu)
: super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return optionsMenuHandler != null
? optionsMenuHandler.onOptionsItemSelected(item)
: super.onOptionsItemSelected(item);
}
}
Set the implementation in the Activity that needs the functionality.
public class TestActivity extends BaseActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setOptionsMenuHandler(new DefaultOptionsMenuHandler(this));
}
}
The net benefit here is that you write the main boilerplate once and support it through all of your activities. You can also continue to keep your business logic defined in the top level activity - where it goes with the other various logic for that particular activity.
Most non-trivial apps would benefit from something along these lines. I typically do something even more robust that supports zero or more OptionsMenuHandlers being set in any given activity where each handler supports a specific type of functionality. The code for this is fairly long and many considerations are needed, so I won't produce it here.

Set search widget back button functionality

I have implemented the Android search widget in my navigation drawer based app. I have set it to open the keyboard and focus the editText when clicking on the search icon. I want to set the back button (up button) to hide the keyboard. I have searched the web for the R.id of the up button, and found this android.R.id.home. So I have set it to be:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
...
case android.R.id.home:
hideKeyboard();
break;
...
}
I debugged the code and noticed that clicking on the navigation bar icon fires up the android.R.id.home, but hitting the up button of the search widget doesn't even enter the onOptionsItemSelected(MenuItem item) function.
I have also tried this:
searchView.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
hideKeyboard();
}
}
});
But didn't work.
How can I hide the keyboard when pressing the back (up) button?
Setting the search view:
private void setSearchView(Menu menu) {
// Get the SearchView and set the searchable configuration
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
searchView = (SearchView) menu.findItem(R.id.search).getActionView();
// Assumes current activity is the searchable activity
searchView.setSearchableInfo(searchManager
.getSearchableInfo(getComponentName()));
searchView.setIconifiedByDefault(false);
SearchView.OnQueryTextListener queryTextListener = new SearchView.OnQueryTextListener() {
public boolean onQueryTextChange(String newText) {
Home.getFilter().filter(newText);
return true;
}
public boolean onQueryTextSubmit(String query) {
return true;
}
};
searchView.setOnQueryTextListener(queryTextListener);
}
The following code should work:
searchView = (SearchView) menu.findItem(R.id.search).getActionView();
searchView.setOnCloseListener(new OnCloseListener() {
#Override
public bool OnClose() {
searchView.clearFocus();
return true;
});
However this didn't work for me for some reason. :-/
I found the workaround below here:
searchView = (SearchView) menu.findItem(R.id.search).getActionView();
searchView.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
#Override
public void onViewDetachedFromWindow(View v) {
searchView.clearFocus();
}
#Override
public void onViewAttachedToWindow(View v) {
}
});
I don't think that using android.R.id.home will work since I think that onOptionsItemSelected(android.R.id.home) will only be called once the SearchView has been closed.

ActionBarSherlock with multiple MenuItems?

I've been using ABS 4.0 with two MenuItems in one of my apps, but have discovered a little error: When pressing the second MenuItem, it does exactly the same as the first one...
I've tried just about everything I can think of, but it isn't working. I've altered onOptionItemSelected, as I thought that was the method I need to edit.
EDIT:
I've been looking at #Ollie's suggestions, but neither LogCat nor Debug is showing weird things. Maybe it's in some other part of the code, or a declaration for ABS? Here's the entire code, if you could look through it, that would be great!
The code for the whole Activity, as it's maybe in some other place?
package bas.sie.Antonius;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
public class TeacherInfo extends SherlockActivity {
String URLhome;
String Info;
String TeacherAb;
TextView mTxtvInfo;
Button mBtnTeacherStSchedule;
Button mBtnTeacherDaySchedule;
private static String mainUrl = "http://www.carmelcollegegouda.nl/site_ant/";
private static String endUrl = ".htm";
private static String[] myUrls = { "roosters/dagroosters/Doc_V1_",
"roosters/standaardroosters/Doc1_" };
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.contactinfo);
setTitle("Over deze leraar");
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
mTxtvInfo = (TextView) findViewById(R.id.TxtvTeacher);
Intent startingIntent = getIntent();
Info = startingIntent.getStringExtra("contact");
mTxtvInfo.setText(Info);
Intent startingIntent1 = getIntent();
TeacherAb = startingIntent1.getStringExtra("abbrev");
mBtnTeacherDaySchedule = (Button) findViewById(R.id.btnTeacherDaySchedule);
mBtnTeacherStSchedule = (Button) findViewById(R.id.btnTeacherStSchedule);
mBtnTeacherDaySchedule.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
URLhome = makeUrl(0);
Intent i = new Intent(TeacherInfo.this, MyWebView.class);
i.putExtra("home", URLhome);
startActivityForResult(i, 0);
}
});
mBtnTeacherStSchedule.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
URLhome = makeUrl(1);
Intent i = new Intent(TeacherInfo.this, MyWebView.class);
i.putExtra("home", URLhome);
startActivityForResult(i, 0);
}
});
}
private String makeUrl(int index) {
String s = mainUrl + myUrls[index] + TeacherAb + endUrl;
return s;
}// makeurl
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add("Instellingen")
.setIcon(R.drawable.ic_settings)
.setShowAsAction(
MenuItem.SHOW_AS_ACTION_IF_ROOM
| MenuItem.SHOW_AS_ACTION_WITH_TEXT);
menu.add("Over de app")
.setIcon(R.drawable.ic_about)
.setShowAsAction(
MenuItem.SHOW_AS_ACTION_IF_ROOM
| MenuItem.SHOW_AS_ACTION_WITH_TEXT);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Intent intent = new Intent(this, AntoniusActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
return true;
case R.id.settings:
Intent i = new Intent(this, About.class);
startActivity(i);
return true;
case R.id.about:
Intent about = new Intent(this, About.class);
startActivity(about);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
I'm thinking that the problem is in the declaration of the menu items, but I don't see any problem there...
Could you take a look at my menu.xml? Posted here:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="#+id/settings"
android:icon="#drawable/ic_settings"
android:title="Instellingen"></item>
<item android:id="#+id/about"
android:icon="#drawable/ic_about"
android:title="Over de app"></item>
</menu>
Create the menu like this:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return super.onCreateOptionsMenu(menu);
}
Then use a switch statement to handle selections:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// Do stuff
return true;
case R.id.menu_item_2:
// Do stuff
return true;
default:
return super.onOptionsItemSelected(item);
}
}
EDIT: Finally, you should do different things for each item, if you change the Intent target Activity to another, it'll do what you expect:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// ... Stuff ...
case R.id.settings: // Settings item
Intent i = new Intent(this, About.class); // Start About.java Activity, but item says "settings"
// TODO: Change About to Settings?
i = new Intent(this, Settings.class);
startActivity(i);
return true;
case R.id.about: // About item
Intent about = new Intent(this, About.class); // Start About.java Activty
startActivity(about);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
What I find odd is the way you create your menu.
You have defined menu layout it in a menu.xml, yet you do not reference this layout in a onCreateOptionMenu() method.
It should be something like this:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getSupportMenuInflater().inflate(R.menu.menu, menu);
return super.onCreateOptionsMenu(menu);
}
Pay attention to the getSupportMenuInflater() method which is used instead of getMenuInflater(). Why this must be so is somewhere in docemntation about android support library which in term is used by ActionBarSherlock library.
What you do is create menu in code programmatically by using a method menu.add() with a signature add(CharSequence). Nowhere it is in there that you give ItemId. I guess (and this is only a guess) android in that case assigns the same id to all items, something like zero or some other arbitrary number. You should use a method with a signature add(int, int, int,CharSequence) or add(int, int, int, int) as only those allow you to specify ItemId. So, both of your menu items have the same id. And this is (I guess again) the cause that they behave the same.
One more thing. Be careful that you use the correct substitute classes and methods from support library and ActionBarSherlock library.
Please let us know if this solved the problem as I am only running this in my head.

Categories