Android APP——实用Android程序Criminallnent Application

来源:互联网 发布:单片机数字式温度计 编辑:程序博客网 时间:2024/06/03 22:51

例子来自Android Programming 2th Edtion,这是一个很好的学习Android APP编写的例子,不像其它书籍那样都是很短的程序介绍每一个功能,这本书的例子最开始便把骨架建立完成,所以理解其中的例子需要一定的面向对象基础,后面所有的材料都往里填充。基本上涉及到编写实用APP的基础,比如一个应用程序启动另外一个应用程序。下面贴出来的代码只是布局文件和主程序的,如果想要实现这个程序,可以按照书上的步骤一步一步来。

activity_crime_pager.xml

<?xml version="1.0" encoding="utf-8"?><android.support.v4.view.ViewPager    xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/activity_crime_pager_view_pager"    android:layout_width="match_parent"    android:layout_height="match_parent"></android.support.v4.view.ViewPager>

activity_fragment.xml

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/fragment_container"    android:layout_width="match_parent"    android:layout_height="match_parent"></FrameLayout>

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_date_picker"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:calendarViewShown="false"></DatePicker>

experiment_layout.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              android:layout_width="match_parent"              android:layout_height="match_parent"></LinearLayout>

fragment_crime.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              android:layout_width="match_parent"              android:layout_height="match_parent"    android:orientation="vertical">    <include        layout="@layout/view_camera_and_title"/>    <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="@string/crime_details_label"        style="?android:listSeparatorTextViewStyle"/>    <EditText        android:id="@+id/crime_title"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:hint="@string/crime_title_hint"/>    <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="@string/crime_details_label"        style="?android:listSeparatorTextViewStyle"/>    <Button        android:id="@+id/crime_date"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="16dp"        android:layout_marginRight="16dp"/>    <CheckBox        android:id="@+id/crime_solved"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="16dp"        android:layout_marginRight="16dp"        android:text="@string/crime_solved_label"/>    <Button        android:id="@+id/crime_suspect"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="16dp"        android:layout_marginRight="16dp"        android:text="@string/crime_suspect_text"/>    <Button        android:id="@+id/crime_report"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="16dp"        android:layout_marginRight="16dp"        android:text="@string/crime_report_text"/></LinearLayout>

fragment_crime_list.xml

    <android.support.v7.widget.RecyclerView        xmlns:android="http://schemas.android.com/apk/res/android"        android:id="@+id/crime_recycler_view"        android:layout_width="match_parent"        android:layout_height="match_parent">    </android.support.v7.widget.RecyclerView>

list_item_crime.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"                android:layout_width="match_parent"                android:layout_height="wrap_content">    <CheckBox        android:id="@+id/list_item_crime_sloved_check_box"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentRight="true"        android:padding="4dp"/>    <TextView        android:id="@+id/list_item_crime_title_text_view"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_toLeftOf="@id/list_item_crime_sloved_check_box"        android:textStyle="bold"        android:padding="4dp"        android:text="Crime Title"/>    <TextView        android:id="@+id/list_item_crime_date_text_view"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_toLeftOf="@id/list_item_crime_sloved_check_box"        android:layout_below="@id/list_item_crime_title_text_view"        android:padding="4dp"        android:text="Crime Date"/></RelativeLayout>

view_camera_and_title.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              android:layout_width="match_parent"              android:layout_height="wrap_content"    android:layout_marginLeft="16dp"    android:layout_marginTop="16dp">    <LinearLayout        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:orientation="vertical"        android:layout_marginRight="4dp">        <ImageView            android:id="@+id/crime_photo"            android:layout_width="80dp"            android:layout_height="80dp"            android:scaleType="centerInside"            android:background="@android:color/darker_gray"            android:cropToPadding="true"/>        <ImageButton            android:id="@+id/crime_camera"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:src="@android:drawable/ic_menu_camera"/>    </LinearLayout>    <LinearLayout        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:orientation="vertical"        android:layout_weight="1">        <TextView            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:text="@string/crime_title_label"            style="?android:listSeparatorTextViewStyle"/>        <EditText            android:id="@+id/crime_title"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_marginRight="16dp"            android:hint="@string/crime_title_hint"/>    </LinearLayout></LinearLayout>

Crime.java

package com.android.testrecord;import java.util.Date;import java.util.UUID;/** * Created by wang on 16-10-23. */public class Crime {    private UUID mId;    private String mTitle;    private Date mDate;    private boolean mSolved;    private String mSuspect;    public Date getDate() {        return mDate;    }    public void setDate(Date date) {        mDate = date;    }    public boolean isSolved() {        return mSolved;    }    public void setSolved(boolean solved) {        mSolved = solved;    }    public String getSuspect() {        return mSuspect;    }    public void setSuspect(String suspect) {        mSuspect = suspect;    }    public String getPhotoFilename() {        return "IMG_" + getId().toString() + ".jpg";    }    public Crime() {        this(UUID.randomUUID());        // mId = UUID.randomUUID();        // mDate = new Date();    }    public Crime(UUID id) {        mId = id;        mDate = new Date();    }    public UUID getId() {        return mId;    }    public String getTitle() {        return mTitle;    }    public void setTitle(String title) {        mTitle = title;    }}

CrimeActivity.java

package com.android.testrecord;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentManager;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.support.v4.app.FragmentActivity;import java.util.UUID;public class CrimeActivity extends SingleFragmentActivity {    public static final String EXTRA_CRIME_ID =            "com.android.testrecord.ciminalintent.crime_id";    public static Intent newIntent(Context packageContext, UUID crimeId) {        Intent intent = new Intent(packageContext, CrimeActivity.class);        intent.putExtra(EXTRA_CRIME_ID, crimeId);        return intent;    }    @Override    protected Fragment createFragment() {        // return new CrimeFragment();        UUID crimeId = (UUID) getIntent().getSerializableExtra(EXTRA_CRIME_ID);        return CrimeFragment.newInstance(crimeId);    }}
CrimeBaseHelper.java

package com.android.testrecord;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;/** * Created by wang on 16-10-24. */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) {        db.execSQL("create table " + CrimeDbSchema.CrimeTable.NAME + "(" +        " _id integer primary key autoincrement, " +        CrimeDbSchema.CrimeTable.Cols.UUID + ", " +                CrimeDbSchema.CrimeTable.Cols.TITLE + ", " +                CrimeDbSchema.CrimeTable.Cols.DATE + ", " +        CrimeDbSchema.CrimeTable.Cols.SOLVED + ", " +                CrimeDbSchema.CrimeTable.Cols.SUSPECT + ")");    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {    }}

CrimeCursorWrapper.java

package com.android.testrecord;import android.database.Cursor;import android.database.CursorWrapper;import java.util.Date;import java.util.UUID;/** * Created by wang on 16-10-24. */public class CrimeCursorWrapper extends CursorWrapper {    /**     * Creates a cursor wrapper.     *     * @param cursor The underlying cursor to wrap.     */    public CrimeCursorWrapper(Cursor cursor) {        super(cursor);    }    public Crime getCrime() {        String uuidString = getString(getColumnIndex(CrimeDbSchema.CrimeTable.Cols.UUID));        String title = getString(getColumnIndex(CrimeDbSchema.CrimeTable.Cols.TITLE));        long date = getLong(getColumnIndex(CrimeDbSchema.CrimeTable.Cols.DATE));        int isSolved = getInt(getColumnIndex(CrimeDbSchema.CrimeTable.Cols.SOLVED));        String suspect = getString(getColumnIndex(CrimeDbSchema.CrimeTable.Cols.SUSPECT));        Crime crime = new Crime(UUID.fromString(uuidString));        crime.setTitle(title);        crime.setDate(new Date(date));        crime.setSolved(isSolved != 0);        crime.setSuspect(suspect);        // return null;        return crime;    }}

CrimeDbSchema.java

package com.android.testrecord;/** * Created by wang on 16-10-24. */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";        }    }}

CrimeFragment.java

package com.android.testrecord;import android.app.Activity;import android.content.Intent;import android.content.pm.PackageManager;import android.database.Cursor;import android.graphics.Bitmap;import android.net.Uri;import android.provider.ContactsContract;import android.provider.MediaStore;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentManager;import android.os.Bundle;import android.text.Editable;import android.text.TextWatcher;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.EditText;import android.text.format.DateFormat;import android.widget.ImageButton;import android.widget.ImageView;import java.io.File;import java.util.Date;import java.util.UUID;import static java.text.DateFormat.*;/** * Created by wang on 16-10-23. */public class CrimeFragment extends Fragment {    private Crime mCrime;    private File mPhotoFile;    private EditText mTitleField;    private Button mDateButton;    private CheckBox mSolvedCheckBox;    private Button mReportButton;    private Button mSuspectButton;    private ImageButton mPhotoButton;    private ImageView mPhotoView;    private static final String ARG_CRIME_ID = "crime_id";    private static final String DIALOG_DATE = "DialogDate";    private static final int REQUEST_DATE = 0;    private static final int REQUEST_CONTACT = 1;    private static final int REQUEST_PHOTO = 2;    public static CrimeFragment newInstance(UUID crimeId) {        Bundle args = new Bundle();        args.putSerializable(ARG_CRIME_ID,crimeId);        CrimeFragment fragment = new CrimeFragment();        fragment.setArguments(args);        return fragment;    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // mCrime = new Crime();        // UUID crimeId = (UUID) getActivity().getIntent().getSerializableExtra(CrimeActivity.EXTRA_CRIME_ID);        UUID crimeId = (UUID) getArguments().getSerializable(ARG_CRIME_ID);        mCrime = CrimeLab.get(getActivity()).getCrime(crimeId);        mPhotoFile = CrimeLab.get(getActivity()).getPhotoFile(mCrime);    }    @Override    public void onPause() {        super.onPause();        CrimeLab.get(getActivity())                .updateCrime(mCrime);    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        View v = inflater.inflate(R.layout.fragment_crime, container, false);        mTitleField = (EditText)v.findViewById(R.id.crime_title);        mTitleField.setText(mCrime.getTitle());        mTitleField.addTextChangedListener(new TextWatcher() {            @Override            public void beforeTextChanged(CharSequence s, int start, int count, int after) {                // This space intentionally left blank            }            @Override            public void onTextChanged(CharSequence s, int start, int before, int count) {                mCrime.setTitle(s.toString());            }            @Override            public void afterTextChanged(Editable s) {                // This one to            }        });        mDateButton = (Button)v.findViewById(R.id.crime_date);        updateDate();        // mDateButton.setEnabled(false);        mDateButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                FragmentManager manager = getFragmentManager();                // DatePickerFragment dialog = new DatePickerFragment();                DatePickerFragment dialog = DatePickerFragment                        .newInstance(mCrime.getDate());                dialog.setTargetFragment(CrimeFragment.this, REQUEST_DATE);                dialog.show(manager, DIALOG_DATE);            }        });        mReportButton = (Button) v.findViewById(R.id.crime_report);        mReportButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Intent i = new Intent(Intent.ACTION_SEND);                i.setType("text/plain");                i.putExtra(Intent.EXTRA_TEXT, getCrimeReport());                i.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.crime_report_subject));                i = Intent.createChooser(i, getString(R.string.send_report));                startActivity(i);            }        });        final Intent pickContact = new Intent(Intent.ACTION_PICK,                ContactsContract.Contacts.CONTENT_URI);        mSuspectButton = (Button) v.findViewById(R.id.crime_suspect);        mSuspectButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                startActivityForResult(pickContact, REQUEST_CONTACT);            }        });        if (mCrime.getSuspect() != null) {            mSuspectButton.setText(mCrime.getSuspect());        }        mSolvedCheckBox = (CheckBox)v.findViewById(R.id.crime_solved);        mSolvedCheckBox.setChecked(mCrime.isSolved());        mSolvedCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {            @Override            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {                // Set the crime's solved property                mCrime.setSolved(isChecked);            }        });        PackageManager packageManager = getActivity().getPackageManager();        if (packageManager.resolveActivity(pickContact,                PackageManager.MATCH_DEFAULT_ONLY) == null) {            mSuspectButton.setEnabled(false);        }        mPhotoButton = (ImageButton) v.findViewById(R.id.crime_camera);        final Intent captureImage = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);            boolean canTakePhoto = mPhotoFile != null &&                captureImage.resolveActivity(packageManager) != null;        // Always enabled        // mPhotoButton.setEnabled(canTakePhoto);        if (canTakePhoto) {            Uri uri = Uri.fromFile(mPhotoFile);            captureImage.putExtra(MediaStore.EXTRA_OUTPUT, uri);        }        mPhotoButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                startActivityForResult(captureImage, REQUEST_PHOTO);            }        });        mPhotoView = (ImageView) v.findViewById(R.id.crime_photo);        updatePhotoView();        return v;    }    @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);            updateDate();        } else if (requestCode == REQUEST_CONTACT && data != null) {            Uri contactUri = data.getData();            // Specify which fields you want your query to return            // values for.            String[] queryFields = new String[] {                    ContactsContract.Contacts.DISPLAY_NAME            };            // Perform your query - the contactUri is like a "where"            // clause here            Cursor c = getActivity().getContentResolver()                    .query(contactUri, queryFields, null, null, null);            try {                // Double-check that you actually got results                if (c.getCount() == 0) {                    return;                }                // Pull out the first column of the first row of data -                // that is your suspect's name.                c.moveToFirst();                String suspect = c.getString(0);                mCrime.setSuspect(suspect);                mSuspectButton.setText(suspect);            } finally {                c.close();            }        } else if(requestCode == REQUEST_PHOTO) {            updatePhotoView();        }    }    private void updateDate() {        mDateButton.setText(mCrime.getDate().toString());    }    private String getCrimeReport() {        String solvedString = null;        if (mCrime.isSolved()) {            solvedString = getString(R.string.crime_report_solved);        } else            solvedString = getString(R.string.crime_report_unsolved);        String dateFormat = "EEE, MMM dd";        String dateString = DateFormat.format(dateFormat, mCrime.getDate()).toString();        String suspect = mCrime.getSuspect();        if (suspect == null) {            suspect = getString(R.string.crime_report_no_suspect);        } else {            suspect = getString(R.string.crime_report_suspect, suspect);        }        String report = getString(R.string.crime_report, mCrime.getTitle(), dateString, solvedString, suspect);        return report;    }    private void updatePhotoView() {        if (mPhotoFile == null || !mPhotoFile.exists()) {            mPhotoView.setImageDrawable(null);        } else {            Bitmap bitmap = PictureUtils.getScaleBitmap(                    mPhotoFile.getPath(), getActivity());            mPhotoView.setImageBitmap(bitmap);        }    }}

CrimeLab.java

package com.android.testrecord;import android.content.ContentValues;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.os.Environment;import java.io.File;import java.util.ArrayList;import java.util.List;import java.util.UUID;/** * Created by wang on 16-10-23. */public class CrimeLab {    private static CrimeLab sCrimeLab;    // private List<Crime> mCrimes;    private Context mContext;    private SQLiteDatabase mDatabase;    public static CrimeLab get(Context context) {        if (sCrimeLab == null) {            sCrimeLab = new CrimeLab(context);        }        return sCrimeLab;    }    private CrimeLab(Context context) {        mContext = context.getApplicationContext();        mDatabase = new CrimeBaseHelper(mContext)                .getWritableDatabase();        // mCrimes = new ArrayList<>();       /* for (int i = 0; i < 100; i++) {            Crime crime = new Crime();            crime.setTitle("Crime #" + i);            crime.setSolved(i % 2 == 0);    // Every other one            mCrimes.add(crime);        } */    }    public void addCrime(Crime c)    {        ContentValues values = getContentValues(c);        mDatabase.insert(CrimeDbSchema.CrimeTable.NAME, null, values);        // mCrimes.add(c);    }    public List<Crime> getCrimes()    {        // return mCrimes;        // return new ArrayList<>();        List<Crime> crimes = new ArrayList<>();        CrimeCursorWrapper cursor = queryCrimes(null, null);        try {            cursor.moveToFirst();            while (!cursor.isAfterLast()) {                crimes.add(cursor.getCrime());                cursor.moveToNext();            }        } finally {            cursor.close();        }        return crimes;    }    public Crime getCrime(UUID id) {        /* for (Crime crime : mCrimes) {            if (crime.getId().equals(id))                return crime;        } */        // return null;        CrimeCursorWrapper cursor = queryCrimes(                CrimeDbSchema.CrimeTable.Cols.UUID + " = ?",                new String[] { id.toString() }        );        try {            if (cursor.getCount() == 0) {                return null;            }            cursor.moveToFirst();            return cursor.getCrime();        } finally {            cursor.close();        }    }    public File getPhotoFile(Crime crime) {        File externFileDir = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);        if (externFileDir == null) {            return null;        }        return new File(externFileDir, crime.getPhotoFilename());    }    public void updateCrime(Crime crime) {        String uuidString = crime.getId().toString();        ContentValues values = getContentValues(crime);        mDatabase.update(CrimeDbSchema.CrimeTable.NAME, values,                CrimeDbSchema.CrimeTable.Cols.UUID + " = ?",                new String[] { uuidString });    }    private static ContentValues getContentValues(Crime crime) {        ContentValues values = new ContentValues();        values.put(CrimeDbSchema.CrimeTable.Cols.UUID, crime.getId().toString());        values.put(CrimeDbSchema.CrimeTable.Cols.TITLE, crime.getTitle());        values.put(CrimeDbSchema.CrimeTable.Cols.DATE, crime.getDate().getTime());        values.put(CrimeDbSchema.CrimeTable.Cols.SOLVED, crime.isSolved() ? 1 : 0);        values.put(CrimeDbSchema.CrimeTable.Cols.SUSPECT, crime.getSuspect());        return values;    }    // private Cursor QueryCrimes(String whereClause, String[] whereArgs) {    private CrimeCursorWrapper queryCrimes(String whereClause, String[] whereArgs) {        Cursor cursor = mDatabase.query(                CrimeDbSchema.CrimeTable.NAME,                null,   // Columns - null selects all columns                whereClause,                whereArgs,                null,   // groupBy                null,   // having                null    // orderBy        );        // return cursor;        return new CrimeCursorWrapper(cursor);    }}

CrimeListActivity.java

package com.android.testrecord;import android.support.v4.app.Fragment;/** * Created by wang on 16-10-23. */public class CrimeListActivity extends SingleFragmentActivity {    @Override    protected Fragment createFragment() {        return new CrimeListFragment();    }}
CrimeListFragment.java

package com.android.testrecord;import android.support.v4.app.Fragment;import android.content.Intent;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.text.Layout;import android.view.LayoutInflater;import android.view.Menu;import android.view.MenuInflater;import android.view.MenuItem;import android.view.View;import android.view.ViewGroup;import android.widget.CheckBox;import android.widget.TextView;import android.widget.Toast;import java.util.List;/** * Created by wang on 16-10-23. */public class CrimeListFragment extends Fragment {    // Nothing yet    private RecyclerView mCrimeRecyclerView;    private CrimeAdapter mAdapter;    private boolean mSubtitleVisible;    private static final String SAVED_SUBTITLE_VISIBLE = "subtitle";    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setHasOptionsMenu(true);    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        View view = inflater.inflate(R.layout.fragment_crime_list,container, false);        mCrimeRecyclerView = (RecyclerView) view.findViewById(R.id.crime_recycler_view);        mCrimeRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));        if (savedInstanceState != null)            mSubtitleVisible = savedInstanceState.getBoolean(SAVED_SUBTITLE_VISIBLE);        updateUI();        return view;    }    @Override    public void onResume() {        super.onResume();        updateUI();    }    @Override    public void onSaveInstanceState(Bundle outState) {        super.onSaveInstanceState(outState);        outState.putBoolean(SAVED_SUBTITLE_VISIBLE, mSubtitleVisible);    }    private void updateUI() {        CrimeLab crimeLab = CrimeLab.get(getActivity());        List<Crime> crimes = crimeLab.getCrimes();        if (mAdapter == null) {            mAdapter = new CrimeAdapter(crimes);            mCrimeRecyclerView.setAdapter(mAdapter);        } else {            mAdapter.setCrimes(crimes);            mAdapter.notifyDataSetChanged();        }        updateSubtitle();    }    private class CrimeHolder extends RecyclerView.ViewHolder        implements View.OnClickListener{        private Crime mCrime;        private TextView mTitleTextView;        private TextView mDateTextView;        private CheckBox mSolvedCheckBox;        public CrimeHolder(View itemView) {            super(itemView);            itemView.setOnClickListener(this);            mTitleTextView = (TextView) itemView.findViewById(R.id.list_item_crime_title_text_view);            mDateTextView = (TextView) itemView.findViewById(R.id.list_item_crime_date_text_view);            mSolvedCheckBox = (CheckBox) itemView.findViewById(R.id.list_item_crime_sloved_check_box);        }        public void bindCrime(Crime crime) {            mCrime = crime;            mTitleTextView.setText(mCrime.getTitle());            mDateTextView.setText(mCrime.getDate().toString());            mSolvedCheckBox.setChecked(mCrime.isSolved());        }        @Override        public void onClick(View v) {            // Toast.makeText(getActivity(), mCrime.getTitle() + " clicked!", Toast.LENGTH_SHORT).show();            // Intent intent = new Intent(getActivity(), CrimeActivity.class);            // Intent intent = CrimeActivity.newIntent(getActivity(), mCrime.getId());            Intent intent = CrimePagerActivity.newIntent(getActivity(), mCrime.getId());            startActivity(intent);        }    }    private class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder> {        private List<Crime> mCrimes;        public CrimeAdapter(List<Crime> crimes) {            mCrimes = crimes;        }        @Override        public CrimeHolder onCreateViewHolder(ViewGroup parent, int viewType) {            LayoutInflater layoutInflater = LayoutInflater.from(getActivity());            View view = layoutInflater.inflate(R.layout.list_item_crime, parent, false);            return new CrimeHolder(view);        }        @Override        public void onBindViewHolder(CrimeHolder holder, int position) {            Crime crime = mCrimes.get(position);            holder.bindCrime(crime);        }        @Override        public int getItemCount() {            return mCrimes.size();        }        public void setCrimes(List<Crime> crimes) {            mCrimes = crimes;        }    }    @Override    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {        super.onCreateOptionsMenu(menu, inflater);        inflater.inflate(R.menu.fragment_crime_list, menu);        MenuItem subtitleItem = menu.findItem(R.id.menu_item_show_crime);        if (mSubtitleVisible) {            subtitleItem.setTitle(R.string.hide_subtitle);        } else {            subtitleItem.setTitle(R.string.show_subtitle);        }    }    @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;            case R.id.menu_item_show_crime:                mSubtitleVisible = !mSubtitleVisible;                getActivity().invalidateOptionsMenu();                updateSubtitle();                return true;            default:                return super.onOptionsItemSelected(item);        }    }    private void updateSubtitle() {        CrimeLab crimeLab = CrimeLab.get(getActivity());        int crimeCount = crimeLab.getCrimes().size();        String subtitle = getString(R.string.subtitle_format, crimeCount);        if (!mSubtitleVisible) {             subtitle = null;        }        AppCompatActivity activity = (AppCompatActivity) getActivity();        activity.getSupportActionBar().setSubtitle(subtitle);    }}

CrimePagerActivity.java

package com.android.testrecord;import android.content.Context;import android.content.Intent;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentManager;import android.os.Bundle;import android.support.v4.app.FragmentActivity;import android.support.v4.app.FragmentStatePagerAdapter;import android.support.v4.view.ViewPager;import android.support.v7.app.AppCompatActivity;import java.util.List;import java.util.UUID;/** * Created by wang on 16-10-23. */public class CrimePagerActivity extends AppCompatActivity {    private static final String EXTRA_CRIME_ID =            "com.android.testrecord.criminalintent.crime_id";    private ViewPager mViewPager;    private List<Crime> mCrimes;    public static Intent newIntent(Context packageContext, UUID crimeId) {        Intent intent = new Intent(packageContext, CrimePagerActivity.class);        intent.putExtra(EXTRA_CRIME_ID, crimeId);        return intent;    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_crime_pager);        UUID crimeId =(UUID) getIntent().getSerializableExtra(EXTRA_CRIME_ID);        mViewPager = (ViewPager) findViewById(R.id.activity_crime_pager_view_pager);        mCrimes = CrimeLab.get(this).getCrimes();        FragmentManager fragmentManager = getSupportFragmentManager();        mViewPager.setAdapter(new FragmentStatePagerAdapter(fragmentManager) {            @Override            public Fragment getItem(int position) {                Crime crime = mCrimes.get(position);                return CrimeFragment.newInstance(crime.getId());            }            @Override            public int getCount() {                return mCrimes.size();            }        });        for (int i = 0; i < mCrimes.size(); i++) {            if (mCrimes.get(i).getId().equals(crimeId)) {                mViewPager.setCurrentItem(i);                break;            }        }    }}

DatePickerFragment.java

package com.android.testrecord;import android.app.Activity;import android.app.Dialog;import android.content.DialogInterface;import android.content.Intent;import android.support.v4.app.DialogFragment;import android.os.Bundle;import android.support.v7.app.AlertDialog;import android.view.LayoutInflater;import android.view.View;import android.widget.DatePicker;import java.util.Calendar;import java.util.Date;import java.util.GregorianCalendar;/** * Created by wang on 16-10-23. */public class DatePickerFragment extends DialogFragment{    public static final String EXTRA_DATE =            "com.android.testrecord.criminalintent.date";    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;    }    @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);        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_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)                .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();    }    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);    }}

PictureUtils.java

package com.android.testrecord;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Point;import java.util.Map;/** * Created by wang on 16-10-25. */public class PictureUtils {    public static Bitmap getScaleBitmap(String path, Activity activity) {        Point size = new Point();        activity.getWindowManager().getDefaultDisplay()                .getSize(size);        return getScaleBitmap(path, size.x, size.y);    }    public static Bitmap getScaleBitmap(String path, int destWidth, int destHeight) {        // Read in the dimensions of the image on disk        BitmapFactory.Options options = new BitmapFactory.Options();        options.inJustDecodeBounds = true;        BitmapFactory.decodeFile(path, options);        float srcWidth = options.outWidth;        float srcHeight = options.outHeight;        // Figure out how much to scale down by        int inSampleSize = 1;        if (srcHeight > destHeight || srcWidth > destWidth) {            if (srcWidth > srcHeight) {                inSampleSize = Math.round(srcHeight / destHeight);            } else {                inSampleSize = Math.round(srcWidth / destWidth);            }        }        options = new BitmapFactory.Options();        options.inSampleSize = inSampleSize;        // Read in and create final bitmap        return BitmapFactory.decodeFile(path, options);    }}

SingleFragmentActivity.java

package com.android.testrecord;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentManager;import android.os.Bundle;import android.support.v4.app.FragmentActivity;import android.support.v7.app.AppCompatActivity;/** * Created by wang on 16-10-23. */public abstract class SingleFragmentActivity extends AppCompatActivity{    protected abstract Fragment createFragment();    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_fragment);        FragmentManager fm = getSupportFragmentManager();        Fragment fragment = fm.findFragmentById(R.id.fragment_container);        if (fragment == null) {            fragment = createFragment();            fm.beginTransaction()                    .add(R.id.fragment_container, fragment)                    .commit();        }    }}

虚拟机上运行的样片:


0 0