為CriminalIntent應用添加對話框
對話框既能引起用戶的注意也可以接收用戶的輸入伴鳖,為其添加對話框,以便用戶修改crime記錄日期粱甫,用戶點擊CrimeFragment中的日期按鈕時醇蝴,應用會彈出如下圖所示的對話框物邑。
創(chuàng)建DialogFragment
總結下來弃理,要實現對話框顯示,首先應完成以下任務:
(1)創(chuàng)建DatePickeFragment類屎蜓;
(2)創(chuàng)建AlertDialog痘昌;
(3)通過FragmentManager在屏幕上顯示對話框。
重要代碼
1炬转、為對話框標題添加字符串資源(values/strings.xml)
<resources>
<string name="crime_solve_label">Solved</string>
<string name="date_picker_title">Date of crime:</string>
</resources>
2辆苔、創(chuàng)建DialogFragment(DialogFragment.java)
public class DatePickerFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.date_picker_title)
.setPositiveButton(android.R.string.ok,null)
.create();
}
}
其中DialogFragment超類為支持庫中android.support.v4.app.DialogFragment類
而AlertDialog需要import android.support.v7.app.AlertDialog;
3、顯示DialogFragment(CrimeFragment.java)
public class CrimeFragment extends Fragment {
private static final String ARG_CRIME_ID = "crime_id";
private static final String DIALOG_DATE = "DialogDate";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
mDateButton = (Button) v.findViewById(R.id.crime_date);
mDateButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
FragmentManager manager= getFragmentManager();
DatePickerFragment dialog = DatePickerFragment.newInstance(mCrime.getDate());
dialog.setTargetFragment(CrimeFragment.this,REQUEST_DATE);
dialog.show(manager,DIALOG_DATE);
}
});
mSolvedCheckbox = (CheckBox) v.findViewById(R.id.crime_solved);
...
return v;
}
}
4扼劈、DatePicker布局(layout/dialog_date.xml)
<?xml version="1.0" encoding="utf-8"?>
<DatePicker
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialog_date_picker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:calendarViewShown="false">
</DatePicker>
5驻啤、給AlertDialog添加DatePicker(DatePickerFragment.java)
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View v = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_date,null);
return new AlertDialog.Builder(getActivity())
.setView(v)
.setTitle(R.string.date_picker_title)
.setPositiveButton(android.R.string.ok,null)
.create();
}
fragment 間的數據傳遞
要傳遞crime的記錄日期給DatePickerFragment,需實現一個newInstance(Date)方法荐吵,然后將Date作為argument附加給fragment骑冗。
為返回新日期給CrimeFragment,并實現模型層以及對應視圖的更新先煎,需將日期打包為extra并附加到Intent上贼涩,然后調用CrimeFragment.onActivityResult( )方法,并傳入準備好的Intent參數薯蝎,如下圖遥倦。
6、添加newInstance(Date)方法(DatePickerFragment.java)
public class DatePickerFragment extends DialogFragment {
private static final String ARG_DATE = "date";
private DatePicker mDatePicker;
public static DatePickerFragment newInstance(Date date){
Bundle args = new Bundle();
args.putSerializable(ARG_DATE,date);
DatePickerFragment fragment = new DatePickerFragment();
fragment.setArguments(args);
return fragment;
}
}
7占锯、獲取Date對象并初始化DatePicker(DatePickerFragment.java)
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Date date = (Date) getArguments().getSerializable(ARG_DATE);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
final int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
View v = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_date,null);
mDatePicker = (DatePicker) v.findViewById(R.id.dialog_date_picker);
mDatePicker.init(year,month,day,null);
return new AlertDialog.Builder(getActivity())
.setView(v)
.setTitle(R.string.date_picker_title)
.setPositiveButton(android.R.string.ok,null)
.create();
}
返回數據給CrimeFragment
1袒哥、設置目標fragment
類似于activity間的關聯,可將CrimeFragment設置成DatePickerFragment的目標 fragment消略。要建立這種關聯堡称,可調用以下Fragment方法:
public void setTargetFragment(Fragment fragment, int requestCode)
2、傳遞數據給目標fragment
建立CrimeFragment與DatePickerFragment間的聯系后艺演,需將數據返還給CrimeFragment粮呢。返回的日期數據將作為extra附加給Intent。
8钞艇、回調目標fragment(DatePickerFragment.java)
public class DatePickerFragment extends DialogFragment {
public static final String EXTRA_DATE = "com.bignerdranch.android.criminalintent.date";
private static final String ARG_DATE = "date";
...
@Override
public Dialog onCreateDialog(Bundle saveInstanceState{
...
}
private void sendResult(int resultCode,Date date){
if(getTargetFragment() == null){
return;
}
Intent intent = new Intent();
intent.putExtra(EXTRA_DATE,date);
getTargetFragment()
.onActivityResult(getTargetRequestCode(),resultCode,intent);
}
}
10啄寡、一切是否都OK?(DatePickerFragment.java)
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
...
return new AlertDialog.Builder(getActivity())
.setView(v)
.setTitle(R.string.date_picker_title)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
int year = mDatePicker.getYear();
int month = mDatePicker.getMonth();
int day = mDatePicker.getDayOfMonth();
Date date = new GregorianCalendar(year,month,day).getTime();
sendResult(Activity.RESULT_OK,date);
}
})
.create();
}
11哩照、響應DatePicker對話框(CrimeFragment.java)
@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);
mDateButton.setText(mCrime.getDate().toString());
}
}
}
為CriminalIntent應用創(chuàng)建工具欄菜單
重要代碼
1挺物、添加字符串資源(values/strings.xml)
<resources>
<string name="new_crime">New Crime</string>
<string name="show_subtitle">Show Subtitle</string>
<string name="hide_subtitle">Hide Subtitle</string>
<string name="subtitle_format">%1$d crimes</string>
</resources>
在 XML 文件中定義菜單
在項目工具窗口中,右鍵單擊res目錄飘弧,選擇New → Android resource file菜單項识藤。在彈出的窗
口界面砚著,選擇Menu資源類型,并命名資源文件為fragment_crime_list痴昧,點擊OK按鈕確認
2稽穆、創(chuàng)建菜單資源(fragment_crime_list.xml)
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_item_new_crime"
android:icon="@android:drawable/ic_menu_add"
android:title="@string/new_crime"
app:showAsAction="ifRoom|withText"/>
</menu>
為工具欄創(chuàng)建圖片
在項目工具窗口中,右鍵單擊drawable目錄赶撰,選擇New → Image Asset菜單項
3舌镶、引用資源(menu/fragment_crime_list.xml)
<item
android:id="@+id/menu_item_new_crime"
android:icon="@drawable/ic_menu_add"
android:title="@string/new_crime"
app:showAsAction="ifRoom|withText"/>
4、實例化選項菜單(CrimeListFragment.java)
@Override
public void onResume() {
super.onResume();
updateUI();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.fragment_crime_list, menu);
}
5豪娜、 調用 SetHasOptionsMenu 方法(CrimeListFragment.java)
...
private RecyclerView mCrimeRecyclerView;
private CrimeAdapter mAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
...
6餐胀、響應菜單項選擇事件(CrimeListFragment.java)
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.fragment_crime_list, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_new_crime:
Crime crime = new Crime();
CrimeLab.get(getActivity()).addCrime(crime);
Intent intent = CrimePagerActivity
.newIntent(getActivity(), crime.getId());
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
層級式導航的工作原理
CriminalIntent應用中,后退按鈕導航和向上按鈕導航執(zhí)行同樣的操作瘤载。在 CrimePagerActivity
界面否灾,無論按哪個按鈕導航,都是回到 CrimeListActivity 界面鸣奔。雖然結果一樣墨技,但它們各自的后臺實現機制卻大不相同。知道這一點很重要挎狸,因為取決于具體應用健提,向上導航很可能會讓用戶迷失在眾多activity中(這里指回退棧內的眾多activity)。
用戶點擊向上按鈕自 CrimePagerActivity 界面向上導航時伟叛,如下的intent會被創(chuàng)建:
Intent intent = new Intent(this, CrimeListActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
FLAG_ACTIVITY_CLEAR_TOP 指示Android在回退棧中尋找指定的activity實例私痹。如存在,則彈出
棧內所有其他activity统刮,讓啟動的目標activity出現在棧頂(顯示在屏幕上)
總而言之紊遵,顯示子標題并旋轉設備,可以看到依然正確
SQLite數據庫
定義schema
重要代碼
1侥蒙、定義 CrimeTable 內部類(CrimeDbSchema.java)
public class CrimeDbSchema {
public static final class CrimeTable {
public static final String NAME = "crimes";
}
}
2痢艺、定義數據表字段(CrimeDbSchema.java)
public class CrimeDbSchema {
public static final class CrimeTable{
public static final String NAME = "crimes";
public static final class Cols{
public static final String UUID = "uuid";
public static final String TITLE = "title";
public static final String DATE = "date";
public static final String SOLVED = "solved";
public static final String SUSPECT = "suspect";
}
}
3兴猩、創(chuàng)建 CrimeBaseHelper 類(CrimeBaseHelper.java)
public class CrimeBaseHelper extends SQLiteOpenHelper {
private static final int VERSION = 1;
private static final String DATABASE_NAME = "crimeBase.db";
public CrimeBaseHelper(Context context) {
super(context, DATABASE_NAME, null, VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
4瓶殃、寫入數據庫
- 使用ContentValues
- 插入和更新記錄
負責處理數據庫寫入和更新操作的輔助類是 ContentValues 射赛。它是個鍵值存儲類,類似于Java的 HashMap 和前面用過的 Bundle 论衍。不同的是瑞佩, ContentValues 只能用于處理SQLite數據。
5坯台、讀取數據庫
- 使用CursorWrapper
- 創(chuàng)建模型對象
Cursor 是個神奇的表數據處理工具炬丸,其任務就是封裝數據表中的原始字段值
總結
這三章的內容主要是一些基礎的功能實現,所以有的代碼沒有具體貼蜒蕾,相對而言還是比較簡單的部分稠炬,跟著書完成還是算得上零失誤的焕阿,寫起來也很歡樂,但博客寫的真的是宛如流水帳...還是希望能有所收獲有所進步吧首启!