美文网首页
CriminalIntent项目总结(二)

CriminalIntent项目总结(二)

作者: YTY尹尹尹 | 来源:发表于2017-10-14 15:36 被阅读14次

    为CriminalIntent应用添加对话框

    对话框既能引起用户的注意也可以接收用户的输入,为其添加对话框,以便用户修改crime记录日期,用户点击CrimeFragment中的日期按钮时,应用会弹出如下图所示的对话框。


    可选择crime日期的对话框
    创建DialogFragment
    由CrimePagerActivity托管的两个fragment对象

    总结下来,要实现对话框显示,首先应完成以下任务:
    (1)创建DatePickeFragment类;
    (2)创建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、创建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 间的数据传递
    CrimeFragment与DatePickerFragment间的对话

    要传递crime的记录日期给DatePickerFragment,需实现一个newInstance(Date)方法,然后将Date作为argument附加给fragment。
    为返回新日期给CrimeFragment,并实现模型层以及对应视图的更新,需将日期打包为extra并附加到Intent上,然后调用CrimeFragment.onActivityResult( )方法,并传入准备好的Intent参数,如下图。

    CrimeFragment与DatePickerFragment间的事件流

    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应用创建工具栏菜单

    工具栏 工具栏
    重要代码

    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、创建菜单资源(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>
    
    为工具栏创建图片

    在项目工具窗口中,右键单击drawable目录,选择New → Image Asset菜单项


    Asset Studio

    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应用中,后退按钮导航和向上按钮导航执行同样的操作。在 CrimePagerActivity
    界面,无论按哪个按钮导航,都是回到 CrimeListActivity 界面。虽然结果一样,但它们各自的后台实现机制却大不相同。知道这一点很重要,因为取决于具体应用,向上导航很可能会让用户迷失在众多activity中(这里指回退栈内的众多activity)。
    用户点击向上按钮自 CrimePagerActivity 界面向上导航时,如下的intent会被创建:

    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出现在栈顶(显示在屏幕上)


    工作中的FLAG_ACTIVITY_CLEAR_TOP

    总而言之,显示子标题并旋转设备,可以看到依然正确

    横屏

    SQLite数据库

    定义schema

    crimes数据表
    重要代码

    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、创建 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
    • 创建模型对象

    Cursor 是个神奇的表数据处理工具,其任务就是封装数据表中的原始字段值

    总结

    这三章的内容主要是一些基础的功能实现,所以有的代码没有具体贴,相对而言还是比较简单的部分,跟着书完成还是算得上零失误的,写起来也很欢乐,但博客写的真的是宛如流水帐...还是希望能有所收获有所进步吧!

    相关文章

      网友评论

          本文标题:CriminalIntent项目总结(二)

          本文链接:https://www.haomeiwen.com/subject/flbxuxtx.html