作为The Big Nerd Ranch的Android指南示例犯罪意图的一部分, 我正在更新一个按钮,其中输入了日期/时间 日期/ TimePicker。 Button和Date / TimePicker位于不同的位置 片段。我正在使用Intent在它们之间传输数据。它 在Pre-Lollipop设备上工作正常,但似乎没有更新按钮 Android 5.0或Lollipop设备上的文字。我错过了什么?
可以在Github看到完整的代码。
CrimeFragment.java
package com.sudhirkhanger.android.criminalintent;
import java.util.Date;
import java.util.UUID;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
public class CrimeFragment extends Fragment {
private Crime mCrime;
private EditText mTitleField;
private Button mDateButton;
private Button mTimeButton;
private CheckBox mSolvedCheckBox;
private static final String TAG = "CriminalFragment";
public static final String EXTRA_CRIME_ID = "com.sudhirkhanger.android.criminalintent.crime_id";
private static final String DIALOG_DATE = "date";
private static final String DIALOG_TIME = "time";
private static final int REQUEST_DATE = 0;
private static final int REQUEST_TIME = 1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UUID crimeId = (UUID) getArguments().getSerializable(EXTRA_CRIME_ID);
mCrime = CrimeLab.get(getActivity()).getCrime(crimeId);
}
private void updateDateAndTime() {
Date d = mCrime.getDate();
CharSequence c = DateFormat.format("EEEE, MMM dd, yyyy", d);
CharSequence t = DateFormat.format("h:mm a", d);
mDateButton.setText(c);
mTimeButton.setText(t);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_crime, parent, false);
mTitleField = (EditText) v.findViewById(R.id.crime_title);
mTitleField.setText(mCrime.getTitle());
mTitleField.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence c, int start, int before,
int count) {
mCrime.setTitle(c.toString());
}
public void beforeTextChanged(CharSequence c, int start, int count,
int after) {
// This space intentionally left blank
}
public void afterTextChanged(Editable c) {
// This one too
}
});
mDateButton = (Button) v.findViewById(R.id.crime_date);
mDateButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
FragmentManager fm = getActivity().getSupportFragmentManager();
DatePickerFragment dialog = DatePickerFragment
.newInstance(mCrime.getDate());
dialog.setTargetFragment(CrimeFragment.this, REQUEST_DATE);
dialog.show(fm, DIALOG_DATE);
}
});
mTimeButton = (Button) v.findViewById(R.id.crime_time);
mTimeButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
FragmentManager fm = getActivity().getSupportFragmentManager();
TimePickerFragment dialog = TimePickerFragment
.newInstance(mCrime.getDate());
dialog.setTargetFragment(CrimeFragment.this, REQUEST_TIME);
dialog.show(fm, DIALOG_TIME);
}
});
updateDateAndTime();
mSolvedCheckBox = (CheckBox) v.findViewById(R.id.crime_solved);
mSolvedCheckBox.setChecked(mCrime.isSolved());
mSolvedCheckBox
.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// Set the crime's solved property
mCrime.setSolved(isChecked);
}
});
return v;
}
public static CrimeFragment newInstance(UUID crimeId) {
Bundle args = new Bundle();
args.putSerializable(EXTRA_CRIME_ID, crimeId);
CrimeFragment fragment = new CrimeFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK)
return;
if (requestCode == REQUEST_DATE) {
Date date = (Date) data
.getSerializableExtra(DatePickerFragment.EXTRA_DATE);
mCrime.setDate(date);
updateDateAndTime();
} else if (requestCode == REQUEST_TIME) {
Date date = (Date) data
.getSerializableExtra(TimePickerFragment.EXTRA_TIME);
mCrime.setDate(date);
updateDateAndTime();
}
}
}
DatePickerFragment.java
package com.sudhirkhanger.android.criminalintent;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.View;
import android.widget.DatePicker;
import android.widget.DatePicker.OnDateChangedListener;
public class DatePickerFragment extends DialogFragment {
public static final String EXTRA_DATE = "com.sudhirkhanger.android.criminalintent.date";
private Date mDate;
public static DatePickerFragment newInstance(Date date) {
Bundle args = new Bundle();
args.putSerializable(EXTRA_DATE, date);
DatePickerFragment fragment = new DatePickerFragment();
fragment.setArguments(args);
return fragment;
}
private void sendResult(int resultCode) {
if (getTargetFragment() == null)
return;
Intent i = new Intent();
i.putExtra(EXTRA_DATE, mDate);
getTargetFragment().onActivityResult(getTargetRequestCode(),
resultCode, i);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
mDate = (Date) getArguments().getSerializable(EXTRA_DATE);
// Create a Calendar to get the year, month, and day
final Calendar calendar = Calendar.getInstance();
// calendar.setTime(mDate);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
View v = getActivity().getLayoutInflater().inflate(
R.layout.dialog_date, null);
DatePicker datePicker = (DatePicker) v
.findViewById(R.id.dialog_date_datePicker);
datePicker.init(year, month, day, new OnDateChangedListener() {
public void onDateChanged(DatePicker view, int year, int month,
int day) {
// Translate year, month, day into a Date object using a
// calendar
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
mDate = new GregorianCalendar(year, month, day, hour, minute)
.getTime();
// Update argument to preserve selected value on rotation
getArguments().putSerializable(EXTRA_DATE, mDate);
}
});
return new AlertDialog.Builder(getActivity())
.setView(v)
.setTitle(R.string.date_picker_title)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
sendResult(Activity.RESULT_OK);
}
}).create();
}
}
答案 0 :(得分:1)
问题不在于Fragments之间的通信,而是由于某种原因,Lollipop中的默认CalendarView DatePicker从不调用OnDateChanged()方法,因此DatePickerFragment.java中的mDate永远不会被更改; DatePickerFragment向CrimeFragment发送与从CrimeFragment收到的值相同的值,因此它看起来只是两个片段之间的通信不起作用。
Lollipop DatePicker在SpinnerView模式下调用OnDateChanged(),因此CrimeFragment的日期将得到正确更新。不幸的是,Lollipop忽略了dialog_date.xml文件中DatePicker标签中的android:calendarViewShown =“false”指令。强制DatePicker显示为微调器的唯一方法是在DatePicker的xml标记中包含android:datePickerMode =“spinner”指令。您将收到警告,该指令仅在API 21中受支持,但在5.0之前运行Android的设备将被忽略。您必须为5.0之前的设备保留calendarViewShown =“false”指令。
DatePickerDialog似乎已在Android 5.0中得到修复,因此您也可以在DatePickerFragment中使用该资源来使其工作。