Omar Abdelhafiz Omar Abdelhafiz - 1 month ago 13
Android Question

I want to remove the optionMenu when there are no items in ListView (emptyView is shown)?

I have an app that adds items to an sqlite database and returns a cursor, this cursor is then used with a custom CursorAdapter called StoreCursorAdapter to show the items in a ListView.

There is a (delete all) button as an optionsMenuItem.

I want to hide this optionsMenuItem when no items are avaliable in the ListView.

InventoryActivty

EditorActivity

Sorry for the links I am a new user so they don't allow me to embed images yet. :-(

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_inventory);

//Declare the views
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
ListView list = (ListView) findViewById(R.id.list);
emptyView = findViewById(R.id.empty_view);

//Set the screen to be shown when there are no list items
list.setEmptyView(emptyView);

//StoreCursorAdapter is a custom CursorAdapter
mAdapter = new StoreCursorAdapter(this, null);
list.setAdapter(mAdapter);
}

@Override
protected void onStart() {
super.onStart();
invalidateOptionsMenu();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu options from the res/menu/menu_inventory.xml file.
// This adds menu items to the app bar.
getMenuInflater().inflate(R.menu.menu_inventory, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// User clicked on a menu option in the app bar overflow menu
showDeleteConfirmationDialog();
return super.onOptionsItemSelected(item);
}


I tried

1 - emptyView.visibilty() == View.INVISBLE

2 - list.getAdapter == null

but they didn't work

What statement will do the job?!

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
if (//what statement) {
MenuItem menuItem = menu.findItem(R.id.action_delete_all);
menuItem.setVisible(false);
}
return true;
}


Note:

OnStart() gets called after I get back from the EditorActivity

Note:

In my app I can delete individual items from another activity so adding invalidateOptionsMenu(); in the onOptionsItemSelected won't do the job.

Answer

the correct condition to put inside onPrepareOptionsMenu is:

menuItem.setVisible(!mAdapter.isEmpty());

that is the same comparison the ListView uses manages the empty view (minus null check) (https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/widget/AdapterView.java#747)

but I believe there's another issue here, is that the data is changing after the activity started, during showDeleteConfirmationDialog(). That means you have to call invalidateOptionsMenu() the moment the data is changed. There're two ways of doing it. One more robust and the other is faster to code:

  1. faster to code (but not very good/clean):

add invalidateOptionsMenu() after the code that executes the DB operations.

  1. more robust/clean

you'll use start/stop callbacks to listen to changes in the data. Something like the following:

@Override protected void onStart(){
  super.onStart();
  invalidateOptionsMenu();
  mAdapter.registerDataSetObserver(dataObserver);
}

@Override protected void onStop(){
  mAdapter.unregisterDataSetObserver(dataObserver);
  super.onStop();
}

private final DataSetObserver dataObserver = new DataSetObserver(){
  @Override public void onChanged(){
    invalidateOptionsMenu();
  }
  @Override public void onInvalidated(){
    invalidateOptionsMenu();
  }
};

all code above was typed by heart, there're likely typos, but that's the idea and the typos you can fix later at your code.

Comments