App crashes on screen rotation when trying to find menu item - java

I am using a collapsingToolbarLayout in my application and as long as the menu is not collapsed there is no problem when rotating the phone. But when the menu is collapsed and only the original toolbar is showing the app crashes. The thing is, when only the original toolbar is showing a clickable item appears and disappears when the collapsing toolbar is shown. When rotating the phone, the application does not find this item. How can I solve this?
The activity where the menu is.
private Menu menu;
protected void onCreate(Bundle savedInstanceState) {
...
AppBarLayout mAppBarLayout = findViewById(R.id.appBarLayout2);
mAppBarLayout.addOnOffsetChangedListener(new
AppBarLayout.OnOffsetChangedListener() {
int scrollRange = -1;
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int
verticalOffset) {
if (scrollRange == -1) {
scrollRange = appBarLayout.getTotalScrollRange();
}
if (scrollRange + verticalOffset == 0) {
isShow = true;
showOption();
} else if (isShow) {
isShow = false;
hideOption();
}
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
this.menu = menu;
getMenuInflater().inflate(R.menu.menu_scrolling, menu);
hideOption();
return true;
}
private void hideOption() {
MenuItem item = menu.findItem(R.id.action_info);
item.setVisible(false);
}
private void showOption() {
MenuItem item = menu.findItem(R.id.action_info);
item.setVisible(true);
}
The relevant code in xml-file:
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout2"
android:layout_width="match_parent"
android:layout_height="128dp"
android:theme="#style/AppTheme.Base"
app:layout_constraintTop_toTopOf="#+id/nestedScrollView">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsTool"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorSecondary"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleGravity="bottom|center"
app:expandedTitleMargin="16dp"
app:expandedTitleTextAppearance="#style/TextAppearance.AppCompat.Display2"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:title="#string/title_expenses">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:navigationIcon="#drawable/ic_action_exit"
app:title="#string/title_expenses"
app:titleTextColor="#android:color/background_light" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
The menu_Scrolling.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.journaldev.collapsingtoolbarlayout.ScrollingActivity">
<item
android:id="#+id/action_info"
android:icon="#drawable/ic_action_add"
android:orderInCategory="200"
android:title="Add"
app:showAsAction="ifRoom" />
</menu>
This is the error message:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.korneliapalm.android.samboappen/com.korneliapalm.android.samboappen.MoneyListActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'android.view.MenuItem android.view.Menu.findItem(int)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3114)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3257)
at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5039)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4948)
at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:69)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7050)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'android.view.MenuItem android.view.Menu.findItem(int)' on a null object reference
at com.korneliapalm.android.samboappen.MoneyListActivity.showOption(MoneyListActivity.java:163)
at com.korneliapalm.android.samboappen.MoneyListActivity.onCreate(MoneyListActivity.java:51)
at android.app.Activity.performCreate(Activity.java:7327)
at android.app.Activity.performCreate(Activity.java:7318)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3094)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3257) 
at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5039) 
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4948) 
at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:69) 
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:214) 
at android.app.ActivityThread.main(ActivityThread.java:7050) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965) 

The problem is that in onCreate you are calling the methods hideOption() and showOption().
However, oncreate is called before onCreateOptionsMenu which is where you are inflating the menu view. So calling menu.findItem(R.id.action_info); triggers a null pointer.
getMenuInflater().inflate(R.menu.menu_scrolling, menu);
You need to ensure that the menu view is inflated before you call these two methods in onCreate.
private void hideOption() {
if (menu == null) return;
MenuItem item = menu.findItem(R.id.action_info);
item.setVisible(false);
}
private void showOption() {
if (menu == null) return;
MenuItem item = menu.findItem(R.id.action_info);
item.setVisible(true);
}

Activity:
When orientation change occurs,android restarts the running Activity ( onDestroy() is called, followed by onCreate()). If you want to handle inside activity,you cant use: in manifest file for particular activity.
For API 12 and below:
android:configChanges="orientation"
if you are targeting API 13 or above
android:configChanges="orientation|screenSize"

You have not handled orientations in your code. You should try to handle them.
The reason for your crash is that when you rotate your screen following event happens:
Activity gets destroyed.
Activity gets re-created.
AppBarLayout's offset gets changed and the method onOffsetChanged is called.
if (scrollRange + verticalOffset == 0) { condition gets true and showOption(); method is called.
Because the Activity is being re-created, the menu item that is used in showOption(); method is null on the line MenuItem item = menu.findItem(R.id.action_info);
Because the item is null, the code item.setVisible(true); produces a runtime crash of Null Pointer Exception.
The proper way of handling orientations is to implement the following method in your Activity code:
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Checks the orientation of the screen
if (newConfig.orientation === Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show()
} else if (newConfig.orientation === Configuration.ORIENTATION_PORTRAIT) {
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show()
}
}
As a pre-cautionary measure, you can add null checks for avoiding the crashes temporarily like this:
private void hideOption() {
MenuItem item = menu.findItem(R.id.action_info);
if (item != null) {
item.setVisible(false);
} else {
Log.e("Your Class", "hideOption() was called, but menu item was null");
}
}
private void showOption() {
MenuItem item = menu.findItem(R.id.action_info);
if (item != null) {
item.setVisible(true);
} else {
Log.e("Your Class", "showOption() was called, but menu item was null");
}
}
I hope this helps.
Reference link:
https://developer.android.com/guide/topics/resources/runtime-changes

Related

getActionBar() is null outside the onCreate() method

Situation:
I am making a chat app with Skype like UI. The contacts recycler view is on the left side.
I have the custom ActionBar based theme.
I need to set the title in the ActionBar onClick.
So, basically, the onClick method is in the Adapter. OnClick of the contacts, the method is passed to the Activity with ActionBar and the name of the contact should come in the title.
The getActionBar() runs perfectly and the Title is set in onCreate method. But, app crashes when I do the same in method outside onCreate.
I referred links here and here but I couldn't solve my issue.
Please guide me regarding the same.
Example:
ChatActivity extends Activity {
//..onCreate here
if(getActionBar() != null) {
String title = " Chat: ";
if(userName != null) {
title = title + userName;
}
getActionBar().setTitle(title);
}
// onCreate finishes
// onContactChange
public void onContactChange(int position, ContactsVO addContact) {
userName = addContact.getName().toString();
String url = addContact.getDP();
if(getActionBar() != null) { //App crashes here
String title =" Chat: ";
if(userName != null)
title = title + userTo;
getActionBar().setTitle(title);
}
}
}
Async Task is called, webservice returns the data which is set in the Adapter.
Now,
in Adapter,
ChatActivity c1 = new ChatActivity();
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
ContactsVO contactsvo = data.get(position);
holder.tv.setText(contactsvo.getName());
String url = contactsvo.getDP();
Glide.with(getContext())
.load(url)
.crossFade()
.into(holder.img);
holder.row.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
c1.onContactChange(position,contactsvo); //method called here.
}
});
}
Stack Trace
E/ACRA: ACRA caught a NullPointerException exception for com.chat
Building report. 11-20 15:51:23.278 12797-12941/? E/ACRA: com.chat
fatal error : Attempt to invoke virtual method 'android.view.View
android.view.Window.getDecorView()' on a null object reference
java.lang.NullPointerException: Attempt to invoke virtual method
'android.view.View android.view.Window.getDecorView()' on a null
object reference
at android.app.Activity.initWindowDecorActionBar(Activity.java:2397)
at android.app.Activity.getActionBar(Activity.java:2339)
at com.chat.activities.ChatActivity.onContactChange(ChatActivity.java:276)
at com.chat.utilities.adapters.ChatCustomAdapter$1.onClick(ChatCustomAdapter.java:74)
at android.view.View.performClick(View.java:5678)
at android.view.View$PerformClick.run(View.java:22667)
at android.os.Handler.handleCallback(Handler.java:836)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6293)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1065)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:926)
Please guide me to solve the solution for the same.
My suggestion is to use setSupportActionBar() for whole activity.
Here in your layout.
<android.support.v7.widget.Toolbar
android:id="#+id/home_activity_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways" />
//OnCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_page);
toolbar = (Toolbar) findViewById(R.id.home_activity_toolbar);
configureHomeToolBar();
}
private void configureHomeToolBar() {
toolbar.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary));
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setIcon(R.drawable.my_logo);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
}
Then you will be able to use it by calling getSupportActionBar() anywhere in your activity such as:
getSupportActionBar().setDisplayUseLogoEnabled(false);
getSupportActionBar().setTitle(titlesArray[someIndex]);

How do I use a ViewPager with the AHBottomNavigation bar?

I want to use the ViewPager with the BottomNavigation bar from Aurel Hubert https://github.com/aurelhubert/ahbottomnavigation
I have following code:
My activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.aaron.waller.mrpolitik.MainActivity"
android:id="#+id/content_id">
<com.aurelhubert.ahbottomnavigation.AHBottomNavigation
android:id="#+id/myBottomNavigation_ID"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
and my MainActivity.java:
public class MainActivity extends AppCompatActivity implements AHBottomNavigation.OnTabSelectedListener {
AHBottomNavigation bottomNavigation;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportActionBar().hide();
bottomNavigation = (AHBottomNavigation) findViewById(R.id.myBottomNavigation_ID);
bottomNavigation.setOnTabSelectedListener(this);
bottomNavigation.setDefaultBackgroundColor(Color.BLUE);
this.createNavItems();
}
//Create items, add them to bar, set propertied and set current item
private void createNavItems() {
//CREATE ITEMS
AHBottomNavigationItem ohnemundItem = new AHBottomNavigationItem("Parteien", R.drawable.parteienicon);
AHBottomNavigationItem grinseItem = new AHBottomNavigationItem("Statistiken", R.drawable.statsicon);
AHBottomNavigationItem lachItem = new AHBottomNavigationItem("Fragen", R.drawable.fragenicon);
//ADD THEM to bar
bottomNavigation.addItem(ohnemundItem);
bottomNavigation.addItem(grinseItem);
bottomNavigation.addItem(lachItem);
//set properties
bottomNavigation.setDefaultBackgroundColor(Color.parseColor("#FEFEFE"));
//set current item
bottomNavigation.setCurrentItem(0);
}
#Override
public void onTabSelected(int position, boolean wasSelected) {
if (position == 0) {
ParteienFragment parteienFragment = new ParteienFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.content_id, parteienFragment).commit();
} else if (position == 1) {
StatistikenFragment statistikenFragment = new StatistikenFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.content_id, statistikenFragment).commit();
} else if (position == 2) {
FragenFragment fragenFragment = new FragenFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.content_id, fragenFragment).commit();
}
}
}
I have no clue how to implement a ViewPager in this case.
I have already googled but have found nothing specific to this NavigationBar.
Is it possible at all to add a swipe effect with this navigation bar?
All I want is that I can wipe left and right between my Fragments.
I know it is a bit late but here goes a way of achieving what you pretend. If you want a swipe behaviour you should make a touch event in your activity to detect a swipe. After you detect a swipe it should be simple, just get the current item, and depending on the swipe set the position on the bottom navigation.
Example:
if(isSwipeRight && bottomNavigation.getCurrentItem() > 0)
bottomNavigation.setCurrentItem(bottomNavigation.getCurrentItem()-1);
else if(isSwipeLeft && bottomNavigation.getCurrentItem() < numTabs-1)
bottomNavigation.setCurrentItem(bottomNavigation.getCurrentItem()+1);

Android app crashing on method call from menu item

I have a function called createGrid that crates a grid of buttons in a Gridlayout (code below), sets their listener and adds a custom layout called no_padding_button to each one.
after creating the grid, depending on what button(s) the user has clicked on I have another function called saveDesign that iterates through the gridlayout and returns the number of clicked buttons depending on their tag. I call saveDesign from a menu Item.
The problem is that as soon as I called the saveDesign method, the app crashes.
The grid works fine, you click buttons, they change color and their tag changes but some reason trying to read through the gridlayout crashes the app.
can you guys help me understand what the error in my code is?
Thanks
//method to create a new grid, the number of rows and columns come from the dialogue inside the activity and then passed to this function
void createGrid(final Context context, GridLayout gridLayout) {
gridLayout.setColumnCount(totalColumns); //set the number of rows of the gridlayout
gridLayout.setRowCount(totalRows); //set the number of columns of the grid layout
//add the buttons and implement their listeners
for (int i = 0; i < totalRows; i++) {
for (int j = 0; j < totalColumns; j++) {
Button button = new Button(context);
//no padding
button.setBackground(context.getResources().getDrawable(R.drawable.no_padding_button));
//set the name of the button according to its position
button.setText(Integer.toString(i) + "," + Integer.toString(j)+",");
//hide the name, the user does not need to see this information at this moment
button.setTextColor(View.INVISIBLE);
//setting up the layout parameters for each button
GridLayout.LayoutParams param = new GridLayout.LayoutParams();
param.setMargins(0, 0, 0, 0);
button.setLayoutParams(param);
//button listener
button.setOnClickListener(new View.OnClickListener() {
boolean already_clicked = false;
#Override
public void onClick(View v) {
//on click, hide the button
Button button = (Button) v;
if(!already_clicked){
//change the color of the selected buttons as an indication
button.setBackgroundColor(context.getResources().getColor(R.color.selected_button));
button.setTag(1);
already_clicked =true;
}
else{
button.setBackgroundColor(context.getResources().getColor(R.color.unselected_button));
button.setTag(0);
already_clicked =false;
}
}
});
gridLayout.addView(button);
}
}
Toast.makeText(context, "Grid Created", Toast.LENGTH_SHORT).show();
}
saveDesing method:
public void saveDesign(){
int temp=0;
for (int i=0;i<gridLayout.getChildCount(); i++){
Button childButton = (Button)gridLayout.getChildAt(i);
if(childButton.getTag().toString() == "1"){
temp++;
}
}
Toast.makeText(this, Integer.toString(temp), Toast.LENGTH_SHORT).show();
}
the xml code of the activity holding the gridlayout:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<HorizontalScrollView android:id="#+id/HorizontalScrollView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gridLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
</GridLayout>
</HorizontalScrollView>
</ScrollView>
UPDATE 1 the error log , i also tried string.equals("1") but i got the same error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.test.gridtest, PID: 3247
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Object.equals(java.lang.Object)' on a null object reference
at com.example.abtin.gridtest.MainActivity.saveDesign(MainActivity.java:85)
at com.example.abtin.gridtest.MainActivity.onOptionsItemSelected(MainActivity.java:109)
at android.app.Activity.onMenuItemSelected(Activity.java:3204)
at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:406)
at android.support.v7.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:195)
at android.support.v7.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:103)
at android.support.v7.app.AppCompatDelegateImplV9.onMenuItemSelected(AppCompatDelegateImplV9.java:667)
at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:810)
at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:152)
at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:957)
at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:947)
at android.support.v7.widget.ActionMenuView.invokeItem(ActionMenuView.java:616)
at android.support.v7.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:153)
at android.view.View.performClick(View.java:5610)
at android.view.View$PerformClick.run(View.java:22260)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
If you don't click on button, it haven't tag. Therefore childButton.getTag() return null and toString crash your app.
So check in saveDesign()
if(childButton.getTag() != null) {
if(childButton.getTag().toString() == "1"){
temp++;
}
}
or set button tag when create button.

Hide Android-PullToRefresh along with Action Bar

I have three tabs and hiding the Action Bar on the middle tab. The third tab had pull to refresh. Android does a great job of animating the sliding in and out of the Action Bar but when I pull to refresh on the third tab and switch to the middle tab (where the Action Bar is hidden) I see the following:
The action bar is hidden from the PageAdapter and hidden as follows:
#Override
public void onPageSelected(int position) {
if (position == 1) {
mActionBar.hide();
} else {
mActionBar.show();
}
}
Pull to Refresh is implemented in a fragment (third tab) with the layout as:
<?xml version="1.0" encoding="utf-8"?>
<uk.co.senab.actionbarpulltorefresh.extras.actionbarsherlock.PullToRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ptr_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/grey_canvas_bg"
android:orientation="vertical"
>
<se.emilsjolander.stickylistheaders.StickyListHeadersListView
android:id="#+id/list_feed"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</uk.co.senab.actionbarpulltorefresh.extras.actionbarsherlock.PullToRefreshLayout>
and initialised in the OnCreateView as follows:
mPullToRefreshLayout = (PullToRefreshLayout) view.findViewById(R.id.ptr_layout);
ActionBarPullToRefresh.from(getActivity())
.allChildrenArePullable()
.useViewDelegate(StickyListHeadersListView.class, new ViewDelegate() {
#Override
public boolean isReadyForPull(View view, float v, float v2) {
View childView = updatesListView.getChildAt(0);
int top = (childView == null) ? 0 : childView.getTop();
return top >= 0;
}
})
.listener(this)
.setup(mPullToRefreshLayout);
Thanks for any help!

How to change menu item text dynamically in Android

I'm trying to change the title of a menu item from outside of the onOptionsItemSelected(MenuItem item) method.
I already do the following;
public boolean onOptionsItemSelected(MenuItem item) {
try {
switch(item.getItemId()) {
case R.id.bedSwitch:
if(item.getTitle().equals("Set to 'In bed'")) {
item.setTitle("Set to 'Out of bed'");
inBed = false;
} else {
item.setTitle("Set to 'In bed'");
inBed = true;
}
break;
}
} catch(Exception e) {
Log.i("Sleep Recorder", e.toString());
}
return true;
}
however I'd like to be able to modify the title of a particular menu item outside of this method.
I would suggest keeping a reference within the activity to the Menu object you receive in onCreateOptionsMenu and then using that to retrieve the MenuItem that requires the change as and when you need it. For example, you could do something along the lines of the following:
public class YourActivity extends Activity {
private Menu menu;
private String inBedMenuTitle = "Set to 'In bed'";
private String outOfBedMenuTitle = "Set to 'Out of bed'";
private boolean inBed = false;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
// Create your menu...
this.menu = menu;
return true;
}
private void updateMenuTitles() {
MenuItem bedMenuItem = menu.findItem(R.id.bedSwitch);
if (inBed) {
bedMenuItem.setTitle(outOfBedMenuTitle);
} else {
bedMenuItem.setTitle(inBedMenuTitle);
}
}
}
Alternatively, you can override onPrepareOptionsMenu to update the menu items each time the menu is displayed.
As JxDarkAngel suggested, calling this from anywhere in your Activity,
invalidateOptionsMenu();
and then overriding:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem item = menu.findItem(R.id.bedSwitch);
if (item.getTitle().equals("Set to 'In bed'")) {
item.setTitle("Set to 'Out of bed'");
inBed = false;
} else {
item.setTitle("Set to 'In bed'");
inBed = true;
}
return super.onPrepareOptionsMenu(menu);
}
is a much better choice. I used the answer from https://stackoverflow.com/a/17496503/568197
you can do this create a global "Menu" object then assign it in onCreateOptionMenu
public class ExampleActivity extends AppCompatActivity
Menu menu;
then assign here
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
this.menu = menu;
return true;
}
Then later use assigned Menu object to get required items
menu.findItem(R.id.bedSwitch).setTitle("Your Text");
Create a setOptionsTitle() method and set a field in your class. Such as:
String bedStatus = "Set to 'Out of Bed'";
...
public void setOptionsTitle(String status)
{
bedStatus = status;
}
Now when the menu gets populated, change the title to whatever your status is:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(bedStatus);
// Return true so that the menu gets displayed.
return true;
}
You better use the override onPrepareOptionsMenu
menu.Clear ();
if (TabActual == TabSelec.Anuncio)
{
menu.Add(10, 11, 0, "Crear anuncio");
menu.Add(10, 12, 1, "Modificar anuncio");
menu.Add(10, 13, 2, "Eliminar anuncio");
menu.Add(10, 14, 3, "Actualizar");
}
if (TabActual == TabSelec.Fotos)
{
menu.Add(20, 21, 0, "Subir foto");
menu.Add(20, 22, 1, "Actualizar");
}
if (TabActual == TabSelec.Comentarios)
{
menu.Add(30, 31, 0, "Actualizar");
}
Here an example
I use this code to costum my bottom navigation item
BottomNavigationView navigation = this.findViewById(R.id.my_bottom_navigation);
Menu menu = navigation.getMenu();
menu.findItem(R.id.nav_wall_see).setTitle("Hello");
Declare your menu field.
private Menu menu;
Following is onCreateOptionsMenu() method
public boolean onCreateOptionsMenu(Menu menu) {
this.menu = menu;
try {
getMenuInflater().inflate(R.menu.menu_main,menu);
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "onCreateOptionsMenu: error: "+e.getMessage());
}
return super.onCreateOptionsMenu(menu);
}
Following will be your name setter activity. Either through a button click or through conditional code
public void setMenuName(){
menu.findItem(R.id.menuItemId).setTitle(/*Set your desired menu title here*/);
}
This worked for me.
You can do it like this, and no need to dedicate variable:
Toolbar toolbar = findViewById(R.id.toolbar);
Menu menu = toolbar.getMenu();
MenuItem menuItem = menu.findItem(R.id.some_action);
menuItem.setTitle("New title");
Or a little simplified:
MenuItem menuItem = ((Toolbar)findViewById(R.id.toolbar)).getMenu().findItem(R.id.some_action);
menuItem.setTitle("New title");
It works only - after the menu created.
You can Change Menu Item text using below Code: -
fun showPopup(v: View) {
popup = PopupMenu(context, v)
val inflater = popup?.menuInflater
popup?.setOnMenuItemClickListener(this)
inflater?.inflate(R.menu.menu_main, popup?.menu)
val menu: Menu = popup!!.menu
val item = menu.findItem(R.id.name)
if (item.title.equals("Name")) {
item.title = "Safal Bhatia"
}
}
It seems to me that you want to change the contents of menu inside a local method, and this method is called at any time, whenever an event is occurred, or in the activity UI thread.
Why don't you take the instance of Menu in the global variable in onPrepareOptionsMenu when this is overridden and use in this method of yours. Be sure that this method is called whenever an event is occurred (like button click), or in the activity UI thread, handler or async-task post-execute.
You should know in advance the index of this menu item you want to change. After clearing the menu, you need to inflate the menu XML and update your item's name or icon.
For people that need the title set statically.
This can be done in the AndroidManifest.xml
<activity
android:name=".ActivityName"
android:label="Title Text" >
</activity>
I needed to change the menu icon for the fragment. I altered Charles’s answer to this question a bit for the fragment:
private Menu top_menu;
//...
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setHasOptionsMenu(true);
//...
rootview = inflater.inflate(R.layout.first_content,null);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_menu, menu);
this.top_menu = menu;
}
// my procedure
private void updateIconMenu() {
if(top_menu!= null) {
MenuItem nav_undo = top_menu.findItem(R.id.action_undo);
nav_undo.setIcon( R.drawable.back);
}
}
I hit this problem too. In my case I wanted to set the string to
reflect additional information using getString.
As stated above you need to find the correct menuItem in the menu and set it in the onPrepareOptionsMenu method. The solutions above didn't handle the case where the item was in a sub menu and for this you need to search the submenu for the item. I wrote a little Kotlin recursive function to allow me to this for multiple items. Code below...
override fun onPrepareOptionsMenu(menu: Menu) {
...
menu.menuSetText(R.id.add_new_card,
getString(R.string.add_card, currentDeck.deckName))
...
}
private fun Menu.getMenuItem(idx: Int, itemId: Int): MenuItem? {
Log.d(TAG, "getMenuItem: $idx of ${this.size()}")
if (idx >= size()) return null
val item = getItem(idx)
if (item.hasSubMenu()) {
val mi = item.subMenu.getMenuItem(0, itemId)
// mi non-null means we found item.
if (mi != null)
return mi
}
if (item != null && item.itemId == itemId)
return item
return getMenuItem(idx + 1, itemId)
}
fun Menu.menuSetText(itemId: Int, title: String) {
val menuItem = getMenuItem(0, itemId)
if (menuItem != null)
menuItem.title = title
else
Log.e(TAG,
"menuSetText to \"$title\": Failed to find ${
"itemId:0x%08x".format(itemId)}"
)
}

Categories

Resources