当我关闭我的应用程序时,我收到以下错误:onPause:
Process: za.co.neilson.alarm, PID: 26280
java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = za.co.neilson.alarm.preferences.AlarmPreferenceListAdapter)
at android.os.Parcel.writeSerializable(Parcel.java:1316)
at android.os.Parcel.writeValue(Parcel.java:1264)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:618)
at android.os.Bundle.writeToParcel(Bundle.java:1692)
at android.os.Parcel.writeBundle(Parcel.java:636)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:2755)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3313)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5487)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.io.NotSerializableException: za.co.neilson.alarm.preferences.AlarmPreferencesActivity
at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1364)
at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1671)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1517)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1481)
at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:979)
at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:368)
at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1074)
at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1404)
at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1671)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1517)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1481)
at android.os.Parcel.writeSerializable(Parcel.java:1311)
at android.os.Parcel.writeValue(Parcel.java:1264)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:618)
at android.os.Bundle.writeToParcel(Bundle.java:1692)
at android.os.Parcel.writeBundle(Parcel.java:636)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:2755)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3313)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5487)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(Native Method)
我不明白的是,类AlarmPreferenceListAdapter是serliazable,这个错误仍然存在....
AlarmPreferencesActivity类(当onPause操作和错误发生时):
public class AlarmPreferencesActivity extends BaseActivity {
private Alarm alarm;
private MediaPlayer mediaPlayer;
private ListAdapter listAdapter;
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
setContentView(R.layout.alarm_preferences);
Bundle bundle = getIntent().getExtras();
if (bundle != null && bundle.containsKey("alarm")) {
setMathAlarm((Alarm) bundle.getSerializable("alarm"));
} else {
setMathAlarm(new Alarm());
}
if (bundle != null && bundle.containsKey("adapter")) {
setListAdapter((AlarmPreferenceListAdapter) bundle.getSerializable("adapter"));
} else {
setListAdapter(new AlarmPreferenceListAdapter(this, getMathAlarm()));
}
getListView().setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> l, View v, int position, long id) {
final AlarmPreferenceListAdapter alarmPreferenceListAdapter = (AlarmPreferenceListAdapter) getListAdapter();
final AlarmPreference alarmPreference = (AlarmPreference) alarmPreferenceListAdapter.getItem(position);
AlertDialog.Builder alert;
v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
switch (alarmPreference.getType()) {
case BOOLEAN:
CheckedTextView checkedTextView = (CheckedTextView) v;
boolean checked = !checkedTextView.isChecked();
((CheckedTextView) v).setChecked(checked);
switch (alarmPreference.getKey()) {
case ALARM_ACTIVE:
alarm.setAlarmActive(checked);
break;
case ALARM_VIBRATE:
alarm.setVibrate(checked);
if (checked) {
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
vibrator.vibrate(1000);
}
break;
}
alarmPreference.setValue(checked);
break;
case STRING:
alert = new AlertDialog.Builder(AlarmPreferencesActivity.this);
alert.setTitle(alarmPreference.getTitle());
// Set an EditText view to get user input
final EditText input = new EditText(AlarmPreferencesActivity.this);
input.setText(alarmPreference.getValue().toString());
alert.setView(input);
alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
alarmPreference.setValue(input.getText().toString());
if (alarmPreference.getKey() == Key.ALARM_NAME) {
alarm.setAlarmName(alarmPreference.getValue().toString());
}
alarmPreferenceListAdapter.setMathAlarm(getMathAlarm());
alarmPreferenceListAdapter.notifyDataSetChanged();
}
});
alert.show();
break;
case LIST:
alert = new AlertDialog.Builder(AlarmPreferencesActivity.this);
alert.setTitle(alarmPreference.getTitle());
CharSequence[] items = new CharSequence[alarmPreference.getOptions().length];
for (int i = 0; i < items.length; i++)
items[i] = alarmPreference.getOptions()[i];
alert.setItems(items, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (alarmPreference.getKey()) {
case ALARM_TONE:
// Setting deafault to silent unless clicking
alarm.setAlarmTonePath(alarmPreferenceListAdapter.getAlarmTonePaths()[0]);
alarm.setAlarmTonePath(alarmPreferenceListAdapter.getAlarmTonePaths()[which]);
if (alarm.getAlarmTonePath() != null) {
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
} else {
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.reset();
}
try {
// mediaPlayer.setVolume(1.0f, 1.0f);
mediaPlayer.setVolume(0.2f, 0.2f);
mediaPlayer.setDataSource(AlarmPreferencesActivity.this, Uri.parse(alarm.getAlarmTonePath()));
mediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
mediaPlayer.setLooping(false);
mediaPlayer.prepare();
mediaPlayer.start();
// Force the mediaPlayer to stop after 3
// seconds...
if (alarmToneTimer != null)
alarmToneTimer.cancel();
alarmToneTimer = new CountDownTimer(3000, 3000) {
@Override
public void onTick(long millisUntilFinished) {
}
@Override
public void onFinish() {
try {
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
} catch (Exception e) {
}
}
};
alarmToneTimer.start();
} catch (Exception e) {
try {
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
} catch (Exception e2) {
}
}
}
break;
default:
break;
}
alarmPreferenceListAdapter.setMathAlarm(getMathAlarm());
alarmPreferenceListAdapter.notifyDataSetChanged();
}
});
alert.show();
break;
case MULTIPLE_LIST:
alert = new AlertDialog.Builder(AlarmPreferencesActivity.this);
alert.setTitle(alarmPreference.getTitle());
CharSequence[] multiListItems = new CharSequence[alarmPreference.getOptions().length];
for (int i = 0; i < multiListItems.length; i++)
multiListItems[i] = alarmPreference.getOptions()[i];
// Handling when it's NULL, ie. No days selected...
boolean[] checkedItems = new boolean[multiListItems.length];
for (Alarm.Day chosenDay : getMathAlarm().getChosenDays()) {
checkedItems[chosenDay.ordinal()] = true;
}
alert.setMultiChoiceItems(multiListItems, checkedItems, new OnMultiChoiceClickListener() {
@Override
public void onClick(final DialogInterface dialog, int which, boolean isChecked) {
Alarm.Day thisDay = Alarm.Day.values()[which];
if (isChecked) {
alarm.addChosenDay(thisDay);
} else {
// Remove and allow checking no days
alarm.removeChosenDay(thisDay);
}
}
});
alert.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
alarmPreferenceListAdapter.setMathAlarm(getMathAlarm());
alarmPreferenceListAdapter.notifyDataSetChanged();
}
});
alert.show();
break;
case TIME:
TimePickerDialog timePickerDialog = new TimePickerDialog(AlarmPreferencesActivity.this, new OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker timePicker, int hours, int minutes) {
Calendar newAlarmTime = Calendar.getInstance();
newAlarmTime.set(Calendar.HOUR_OF_DAY, hours);
newAlarmTime.set(Calendar.MINUTE, minutes);
newAlarmTime.set(Calendar.SECOND, 0);
alarm.setAlarmTime(newAlarmTime);
alarmPreferenceListAdapter.setMathAlarm(getMathAlarm());
alarmPreferenceListAdapter.notifyDataSetChanged();
}
}, alarm.getAlarmTime().get(Calendar.HOUR_OF_DAY), alarm.getAlarmTime().get(Calendar.MINUTE), true);
timePickerDialog.setTitle(alarmPreference.getTitle());
timePickerDialog.show();
break;
/* Notes: 6/23/2015:
- Need to add a date selection (after the time selection)
- Need to change the repeat from list to checkbox
- If select repeat yes, opens the usual dialog to select the days
and adds an extra row with the days that the event is repeating
- If un-selecting the repeat, will clear those days previously selected (basically just automate un-checking that days list)
*/
case DATE:
DatePickerDialog datePickerDialog = new DatePickerDialog(AlarmPreferencesActivity.this, new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
Calendar newAlarmDate = Calendar.getInstance();
newAlarmDate.set(Calendar.YEAR, year);
newAlarmDate.set(Calendar.MONTH, monthOfYear);
newAlarmDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
// Prevent setting to a previous date:
if (newAlarmDate.before(Calendar.getInstance())) {
// Then set to current date:
newAlarmDate = Calendar.getInstance();
Toast.makeText(getApplicationContext(), "Cannot Set Event in Past", Toast.LENGTH_LONG).show();
}
alarm.setAlarmDate(newAlarmDate);
alarmPreferenceListAdapter.setMathAlarm(getMathAlarm());
alarmPreferenceListAdapter.notifyDataSetChanged();
}
}, alarm.getAlarmDate().get(Calendar.YEAR), alarm.getAlarmDate().get(Calendar.MONTH), alarm.getAlarmDate().get(Calendar.DAY_OF_MONTH));
datePickerDialog.setTitle(alarmPreference.getTitle());
datePickerDialog.show();
break;
default:
break;
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
boolean result = super.onCreateOptionsMenu(menu);
menu.findItem(R.id.menu_item_new).setVisible(false);
return result;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_save:
// Input Sanitation:
Calendar setTimeValues = Calendar.getInstance();
setTimeValues.set(Calendar.HOUR, alarm.getAlarmTime().get(Calendar.HOUR));
setTimeValues.set(Calendar.MINUTE, alarm.getAlarmTime().get(Calendar.MINUTE));
// If repeating alarm, setting before the present time, should increment to the next day it will be active
if (alarm.getChosenDays().length != 0 && alarm.getAlarmDate().before(Calendar.getInstance())
&& setTimeValues.before(Calendar.getInstance())) {
Toast.makeText(getApplicationContext(), "Repeat: time is before present - set alarm to next active day", Toast.LENGTH_LONG).show();
alarm.getAlarmDate().add(Calendar.DAY_OF_MONTH, 1);
// Trouble is, if today ie, Sunday, is one of the days chosen for repeating...it gets caught up
// Then iterate to the next day the alarm should be activated
while (!Arrays.asList(alarm.getChosenDays()).contains(Alarm.Day.values()[alarm.getAlarmDate().get(Calendar.DAY_OF_WEEK) - 1])) {
alarm.getAlarmDate().add(Calendar.DAY_OF_MONTH, 1);
}
}
if (alarm.getChosenDays().length != 0 && alarm.getAlarmDate().before(Calendar.getInstance())
&& setTimeValues.equals(Calendar.getInstance())) {
Toast.makeText(getApplicationContext(), "Repeat: time is before present - set alarm to next active day", Toast.LENGTH_LONG).show();
alarm.getAlarmDate().add(Calendar.DAY_OF_MONTH, 1);
// Trouble is, if today ie, Sunday, is one of the days chosen for repeating...it gets caught up
// Then iterate to the next day the alarm should be activated
while (!Arrays.asList(alarm.getChosenDays()).contains(Alarm.Day.values()[alarm.getAlarmDate().get(Calendar.DAY_OF_WEEK) - 1])) {
alarm.getAlarmDate().add(Calendar.DAY_OF_MONTH, 1);
}
}
if (alarm.getChosenDays().length != 0) {
while (!Arrays.asList(alarm.getChosenDays()).contains(Alarm.Day.values()[alarm.getAlarmDate().get(Calendar.DAY_OF_WEEK) - 1])) {
alarm.getAlarmDate().add(Calendar.DAY_OF_MONTH, 1);
}
}
// If individual alarm and setting time before presentm should not allow saving at all
if (alarm.getChosenDays().length == 0 && alarm.getAlarmDate().before(Calendar.getInstance())
&& setTimeValues.equals(Calendar.getInstance())
||
alarm.getChosenDays().length == 0 && alarm.getAlarmDate().before(Calendar.getInstance())
&& setTimeValues.before(Calendar.getInstance())) {
Toast.makeText(getApplicationContext(), "Cannot set event in past", Toast.LENGTH_LONG).show();
} else {
// Everthing else is allowed
Database.init(getApplicationContext());
if (getMathAlarm().getId() < 1) {
Database.create(getMathAlarm());
} else {
Database.update(getMathAlarm());
}
callMathAlarmScheduleService();
Toast.makeText(AlarmPreferencesActivity.this, getMathAlarm().getTimeUntilNextAlarmMessage(), Toast.LENGTH_LONG).show();
finish();
}
break;
case R.id.menu_item_delete:
AlertDialog.Builder dialog = new AlertDialog.Builder(AlarmPreferencesActivity.this);
dialog.setTitle("Delete");
dialog.setMessage("Delete this alarm?");
dialog.setPositiveButton("Ok", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Database.init(getApplicationContext());
if (getMathAlarm().getId() < 1) {
// Alarm not saved
} else {
Database.deleteEntry(alarm);
callMathAlarmScheduleService();
}
finish();
}
});
dialog.setNegativeButton("Cancel", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
dialog.show();
break;
}
return super.onOptionsItemSelected(item);
}
private CountDownTimer alarmToneTimer;
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putSerializable("alarm", getMathAlarm());
outState.putSerializable("adapter", (AlarmPreferenceListAdapter) getListAdapter());
}
;
@Override
protected void onPause() {
super.onPause();
if(mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.release();
}
}
@Override
protected void onResume() {
super.onResume();
}
public Alarm getMathAlarm() {
return alarm;
}
public void setMathAlarm(Alarm alarm) {
this.alarm = alarm;
}
public ListAdapter getListAdapter() {
return listAdapter;
}
public void setListAdapter(ListAdapter listAdapter) {
this.listAdapter = listAdapter;
getListView().setAdapter(listAdapter);
}
public ListView getListView() {
if (listView == null)
listView = (ListView) findViewById(android.R.id.list);
return listView;
}
public void setListView(ListView listView) {
this.listView = listView;
}
@Override
public void onClick(View v) {
}
}