I have been successfully using the option menu within my ListActivity. Until now. Apparently the menu button only causes the options menu to appear when there is data in the list. I tried loading the ListActivity without any data. This causes the menu button to fail. Even if I load data a little later on, the menu data still fails.
I have tried with both my HTC device and the emulator, just to make sure it was not a bug related to the hardware. Behavior is identical.
The onPrepareOptionsMenu method is never triggered (debugging using breakpoints and logging.)
Build target: Android 2.1update1
Thanks so much, as I am utterly stumped.
Here is the class code (is the menu xml relevant to post?):
package com.techmeridian.jobsite;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Typeface;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.style.StyleSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
/* *******************
* *******************
* *******************
* *******************
* *******************/
public class ApptList extends ListActivity {
private JobSiteDbAdapter mDbHelper;
private String curDate;
private String prevDate;
private String nextDate;
private boolean headerSet;
private View mDateHeader;
private Menu mMenu;
/* *******************
* *******************
* *******************
* *******************
* *******************/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.appt_list);
mDbHelper = new JobSiteDbAdapter(this);
mDbHelper.open();
setCurPrevNextDate();
fillData();
captureButtonClicks();
setPrevNextButtonState();
}
/* (non-Javadoc)
* @see android.app.ListActivity#onListItemClick(android.widget.ListView, android.view.View, int, long)
*/
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
Intent i = new Intent(this, ApptShow.class);
//Long id = (Long) getListAdapter().getItem(id);
i.putExtra("id", id);
// Create the view using FirstGroup's LocalActivityManager
View view = TabsFirstGroup.group.getLocalActivityManager()
.startActivity("show_appt", i
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))
.getDecorView();
// Again, replace the view
TabsFirstGroup.group.replaceView(view);
}
/* *******************
* *******************
* *******************
* *******************
* *******************/
private void setPrevNextButtonState() {
// disable prev menu item, if necessary
final ImageButton prevButton = (ImageButton) findViewById(R.id.button_prev_appt_list);
if(this.prevDate == null) {
prevButton.setEnabled(false);
} else {
prevButton.setEnabled(true);
}
// disable next menu item, if necessary
final ImageButton nextButton = (ImageButton) findViewById(R.id.button_next_appt_list);
if(this.nextDate == null) {
nextButton.setEnabled(false);
} else {
nextButton.setEnabled(true);
}
}
/* *******************
* *******************
* *******************
* *******************
* *******************/
private void captureButtonClicks() {
final ImageButton prevButton = (ImageButton) findViewById(R.id.button_prev_appt_list);
prevButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
setCurPrevNextDate("prevDate");
fillData();
setPrevNextButtonState();
}
});
final ImageButton nextButton = (ImageButton) findViewById(R.id.button_next_appt_list);
nextButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
setCurPrevNextDate("nextDate");
fillData();
setPrevNextButtonState();
}
});
}
/* *******************
* *******************
* *******************
* *******************
* *******************/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
this.mMenu = menu;
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_option_msg_appt, menu);
return true;
}
/* (non-Javadoc)
* @see android.app.Activity#onPrepareOptionsMenu(android.view.Menu)
* *******************
* *******************
* *******************/
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// TODO Auto-generated method stub
Boolean returnSuper = super.onPrepareOptionsMenu(menu);
// disable prev menu item, if necessary
MenuItem itemPrev = menu.findItem(R.id.menu_option_msg_appt_prev_item);
if(this.prevDate == null) {
itemPrev.setEnabled(false);
} else {
itemPrev.setEnabled(true);
}
// disable next menu item, if necessary
MenuItem itemNext = menu.findItem(R.id.menu_option_msg_appt_next_item);
if(this.nextDate == null) {
itemNext.setEnabled(false);
} else {
itemNext.setEnabled(true);
}
return returnSuper;
}
/* *******************
* *******************
* *******************
* *******************
* *******************/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.menu_option_msg_appt_prev_item:
setCurPrevNextDate(this.prevDate);
fillData();
return true;
case R.id.menu_option_msg_appt_next_item:
setCurPrevNextDate(this.nextDate);
fillData();
return true;
case R.id.menu_option_msg_appt_sort_item:
Log.v("sarah", "inside menu_option_msg_appt_sort_item");
return true;
case R.id.menu_option_msg_appt_refresh_item:
Log.v("sarah", "inside menu_option_msg_appt_refresh_item");
return true;
case R.id.menu_option_msg_appt_settings_item:
Log.v("sarah", "inside menu_option_msg_appt_settings_item");
Intent i = new Intent(this, NotifyingController.class);
startActivityForResult(i, 0);
return true;
}
return super.onOptionsItemSelected(item);
}
// brand new instance of this class.
// got here from onCreate()
// Either we are receiving the date via intent,
// or we will use today's date by default
private void setCurPrevNextDate() {
String mDate;
// were we passed a date?
Bundle extras = getIntent().getExtras();
mDate = extras != null ? extras.getString("curDate") : null;
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
// no date passed, use today's date
if(mDate == null) {
Date now = new Date();
try {
//Date convertedDate = df.parse(strDate);
mDate = df.format(now);
} catch(Exception e) {
Log.e("sarah",e.getMessage());
}
}
// now set the current date
try {
this.setCurPrevNextDate(mDate);
} catch(Exception e) {
Log.e("sarah",e.getMessage());
}
}
/* gotten to by hitting prev and next option menu buttons
* *******************
* *******************
* *******************
* *******************/
private void setCurPrevNextDate(String mDateNew) {
// can't always pass in "this.prevDate", so parse
if(mDateNew=="prevDate") {
mDateNew = this.prevDate;
} else if(mDateNew=="nextDate") {
mDateNew = this.nextDate;
}
// set this.curDate for reference
this.curDate = mDateNew;
DateFormat df = new SimpleDateFormat ("yyyy-MM-dd");
// now get yesterday and tomorrow
Cursor dateNext = mDbHelper.getNextApptDate(this.curDate);
startManagingCursor(dateNext);
String mDateNext = dateNext.getString(dateNext.getColumnIndexOrThrow("myDateNext"));
if(mDateNext != null) {
try {
// need to get stark date without time
// get Date from String, first
Date convertedNextDate = df.parse(mDateNext);
// now get String in stark format without time
this.nextDate = df.format(convertedNextDate);
} catch(Exception e) {
Log.e("sarah",e.getMessage());
}
} else {
this.nextDate = null;
}
Cursor datePrev = mDbHelper.getPrevApptDate(this.curDate);
startManagingCursor(datePrev);
// full date with time
String mDatePrev = datePrev.getString(datePrev.getColumnIndexOrThrow("myDatePrev"));
if(mDatePrev != null) {
try {
// need to get stark date without time
// get Date from String, first
Date convertedPrevDate = df.parse(mDatePrev);
// now get String in stark format without time
this.prevDate = df.format(convertedPrevDate);
} catch(Exception e) {
Log.e("sarah",e.getMessage());
}
} else {
this.prevDate = null;
}
}
/* *******************
* *******************
* *******************
* *******************
* *******************/
private void fillData() {
// get day, month, etc.
String strFriendlyDate = "";
try {
// get Date from String, first
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
Date convertedCurDate = df.parse(this.curDate);
// now get String in elongated format from Date
SimpleDateFormat friendlyDate = new SimpleDateFormat("EEEE MMMM dd, yyyy");
strFriendlyDate = friendlyDate.format(convertedCurDate);
} catch(Exception e) {
Log.e("sarah",e.getMessage());
}
// set appt list header with friendly date
TextView apptHeader = (TextView) this.findViewById(R.id.appt_list_header);
apptHeader.setText(strFriendlyDate);
// get all messages for date
Cursor c = mDbHelper.fetchAllApptsForDate(this.curDate);
startManagingCursor(c);
String[] from = new String[] { "customer_name", "mytime"};
int[] to = new int[] { R.id.appt_row_customer, R.id.appt_row_time };
// Now create an array adapter and set it to display using our row
SarahSimpleCursorAdapter appts =
new SarahSimpleCursorAdapter(this, R.layout.appt_row, c, from, to);
setListAdapter(appts);
}
/* *******************
* *******************
* *******************
* *******************
* *******************/
private class SarahSimpleCursorAdapter extends SimpleCursorAdapter {
private Context context;
private Cursor c;
public SarahSimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
this.c = c;
this.context = context;
}
/* (non-Javadoc)
* @see android.widget.CursorAdapter#getView(int, android.view.View, android.view.ViewGroup)
* *******************
* *******************
* ******************* *
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
//View v = super.getView(position, convertView, parent);
//customize the background look of each state of the row! yippee!
//v.setBackgroundResource(R.layout.appt_row_design);
View v = convertView;
int pos = position;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.appt_row, null);
}
//customize the background look of each state of the row! yippee!
// the white background that changes to orange when selected
c.moveToPosition(pos);
v.setBackgroundResource(R.layout.appt_row_design);
int subjectView = R.id.appt_row_customer;
//subject......................
//String strSubject = "deal with missing subject in terms of 'new' row design";
String strSubject = c.getString(c.getColumnIndex("customer_name"));
int length = 28;
if (strSubject != null && strSubject.length() > length)
strSubject = strSubject.substring(0, length) + "...";
TextView mySubject = (TextView) v.findViewById(subjectView);
// set the value of the xml element
//mySubject.setText(strSubject);
SpannableString content = new SpannableString(strSubject);
if(c.getInt(c.getColumnIndex("_id"))==1) {
content.setSpan(new StyleSpan(Typeface.BOLD), 0, content.length(), 0);
v.setBackgroundResource(R.layout.appt_row_new_design);
}
mySubject.setText(content);
//time......................
String strTime = c.getString(c.getColumnIndex("mytime"));
TextView myTime = (TextView) v.findViewById(R.id.appt_row_time);
myTime.setText(strTime);
return v;
}
}
}