I've written a ListActivity for Android 2.1 which is used to display a list of event categories. As the user selects a category, the program calls a web service to retrieve a list of sub-events. For example, a top level event might be "soccer" and when the user selects this the web service would return various soccer associations (e.g. "english", "french", "german", etc.) and display them in a new list.
The following code seems to work occasionally, however sometimes the call to the service (in EventsListTask) fails because the serviceBinder is null. How/Why does this happen?
public class EventListsActivity extends ListActivity {
private static final String EVENT_ID = "EventId";
private List<ListItem> eventList;
private ArrayAdapter<ListItem> listItemArrayAdapter;
private static final int LOADING_DIALOG = 1;
private EventsListTask eventsListTask = null;
private BFService serviceBinder;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.i("EventListsActivity", "service connected");
serviceBinder = ((BFService.BFBinder)iBinder).getService();
}
public void onServiceDisconnected(ComponentName componentName) {
Log.i("EventListsActivity", "service disconnected");
serviceBinder = null;
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i("EventListsActivity", "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.list);
eventList = new ArrayList<ListItem>();
listItemArrayAdapter = new ArrayAdapter<ListItem>(this, R.layout.row, eventList);
setListAdapter(listItemArrayAdapter);
Intent bindIntent = new Intent(this, BFService.class);
bindService(bindIntent, mConnection, Context.BIND_AUTO_CREATE);
int eventId = getIntent().getIntExtra(EVENT_ID, -1);
if (eventsListTask == null || eventsListTask.getStatus() == AsyncTask.Status.FINISHED) {
eventsListTask = new EventsListTask();
eventsListTask.execute(eventId);
}
}
@Override
protected void onDestroy() {
Log.i("EventListsActivity", "destroyed");
super.onDestroy();
unbindService(mConnection);
}
@Override
protected void onListItemClick(ListView listView, View view, int position, long id) {
super.onListItemClick(listView, view, position, id);
ListItem selectedItem = (ListItem) listView.getAdapter().getItem(position);
Intent intent;
if (selectedItem.getMarketType() != null) {
intent = new Intent(this, MarketActivity.class);
intent.putExtra(EVENT_ID, selectedItem.getId());
startActivityIfNeeded(intent, -1);
} else if (selectedItem.getId() != -1) {
intent = new Intent(this, EventListsActivity.class);
intent.putExtra(EVENT_ID, selectedItem.getId());
startActivityIfNeeded(intent, -1);
} else {
Log.e("EventListsActivity", "unexpected item selected!");
}
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case (LOADING_DIALOG) :
AlertDialog.Builder loadingDialog = new AlertDialog.Builder(this);
loadingDialog.setTitle("Please Wait...");
loadingDialog.setMessage("Communicating with remote service.");
return loadingDialog.create();
}
return null;
}
private class EventsListTask extends AsyncTask<Integer, Void, LoginStatusEnum> {
@Override
protected void onPreExecute() {
showDialog(LOADING_DIALOG);
}
@Override
protected void onPostExecute(LoginStatusEnum loginStatusEnum) {
dismissDialog(LOADING_DIALOG);
if (loginStatusEnum != null) {
switch (loginStatusEnum) {
case OK:
for (ListItem item : eventList) {
listItemArrayAdapter.add(item);
}
listItemArrayAdapter.notifyDataSetChanged();
break;
}
}
}
@Override
protected LoginStatusEnum doInBackground(Integer... params) {
LoginStatusEnum result = LoginStatusEnum.OK;
Integer eventId = params[0];
if (serviceBinder != null) {
try {
if (eventId == null || eventId == -1) {
eventList = serviceBinder.getActiveEventTypes();
} else {
eventList = serviceBinder.getEvents(eventId);
}
} catch (WebServiceException wse) {
result = LoginStatusEnum.valueOf(wse.getMessage());
}
} else {
Log.e("EventListsActivity", "serviceBinder is null!");
}
return result;
}
}
}
EDIT: The serviceBinder appears to be set to null when I reach the bottom of a list, when I change the target intent to go to a different activity:
intent = new Intent(this, MarketActivity.class);
intent.putExtra(EVENT_ID, selectedItem.getId());
startActivity(intent);
This new activity also uses the same background service (binds in the same way, etc.). Is there anything I need to watch out for when doing this? Am I calling the target intent incorrectly?
EDIT2: Here's the output from LogCat when I start the activity which calls the service (this time the service failed straight away!):
04-02 07:02:49.147: INFO/ActivityManager(61): Starting activity: Intent { cmp=net.foobar.activity/.EventListsActivity }
04-02 07:02:49.257: INFO/EventListsActivity(353): onCreate
04-02 07:02:49.426: INFO/EventListsActivity(353): service connected
04-02 07:02:49.437: ERROR/EventListsActivity(353): serviceBinder is null!