package com.huangfei.criminalintent;
import java.util.Date;
import java.util.UUID;
public class Crime {
private UUID mId;
private String mTitle;
private Date mDate;
private boolean mSolved;
public Crime(){
//生成唯一标识符
mId = UUID.randomUUID();
setDate(new Date());
}
public String getTitle() {
return mTitle;
}
public void setTitle(String title) {
mTitle = title;
}
public UUID getId() {
return mId;
}
public Date getDate() {
return mDate;
}
public void setDate(Date date) {
mDate = date;
}
public boolean isSolved() {
return mSolved;
}
public void setSolved(boolean solved) {
mSolved = solved;
}
@Override
public String toString() {
return mTitle;
}
}
package com.huangfei.criminalintent;
import java.util.ArrayList;
import java.util.UUID;
import android.content.Context;
/** * * @author huangfeihong * CrimeLab类是单例模式。应用能在内存里存在多久,单例就能存在多久,因此将对象列表保存在单例里可保持crime数据的一直存在, * 不管activity、fragment及它们的生命周期发生什么变化。 */
public class CrimeLab {
private ArrayList<Crime> mCrimes;
private static CrimeLab sCrimeLab;
private Context mAppContext;
private CrimeLab(Context appContext){
mAppContext = appContext;
mCrimes = new ArrayList<Crime>();
for (int i = 0; i < 100; i++) {
Crime crime = new Crime();
crime.setTitle("Crime #" + i);
crime.setSolved(i % 2 == 0);
mCrimes.add(crime);
}
}
/** * 在get(Context)方法里,我们并没有直接将Context参数传递给构造方法。该Context可能是一个Activity,也可能是另一个Context对象, * 如Serivie。在应用的整个生命周期里,我们无法保证只要CrimeLab需要用到Context对象,Context就一定存在。 * 因此,为保证单例总是有Context可以使用,可调用getApplicationContext()方法,将不确定是否存在的Context对象替换成 application context。 * application context是针对应用的全局性Context。任何时候,只要应用层面的单例,就该一直使用application context。 */
public static CrimeLab get(Context c){
if(sCrimeLab == null){
sCrimeLab = new CrimeLab(c.getApplicationContext());
}
return sCrimeLab;
}
public ArrayList<Crime> getCrimes() {
return mCrimes;
}
public Crime getCrime(UUID id){
for (Crime crime : mCrimes) {
if(crime.getId().equals(id))//UUID之间比较方式
return crime;
}
return null;
}
}
package com.huangfei.criminalintent;
import java.util.ArrayList;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
/** * * @author huangfeihong 无需覆盖onCreateView(...)方法或为CrimeListFragment生成布局。 * ListFragment类默认实现方法已经生成了一个全屏ListView布局。 */
public class CrimeListFragment extends ListFragment {
private static final String TAG = "CrimeListFragment";
private ArrayList<Crime> mCrimes;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置操作栏(旧版本设备为标题栏)上的标题文字
getActivity().setTitle(R.string.crimes_title);
mCrimes = CrimeLab.get(getActivity()).getCrimes();
/** * android.R.layout.simple_list_item_1是Android * SDK提供的预定义布局资源。该布局拥有一个TextView根元素。 也可指定其他布局,只要满足布局的根元素是TextView即可。 * * 默认的ArrayAdapter<T>.getView(...)实现方法依赖于toString()方法。它首先生成布局视图, * 然后找到指定位置的Crime对象并对其调用 toString()方法,最后得到字符串信息并传递给TextView。 */
// ArrayAdapter<Crime> adapter = new ArrayAdapter<Crime>(getActivity(),
// android.R.layout.simple_list_item_1, mCrimes);
CrimeAdapter adapter = new CrimeAdapter(mCrimes);
// 该方法是ListFragment类的便利方法,使用它可为CrimeListFragment管理的内置ListView设置adapter。
setListAdapter(adapter);
}
/** * 响应用户对列表项的点击事件 */
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Crime crime = (Crime) getListAdapter().getItem(position);
Log.d(TAG, crime.getTitle() + "was clicked");
}
private class CrimeAdapter extends ArrayAdapter<Crime> {
public CrimeAdapter(ArrayList<Crime> crimes) {
/** * 这里调用超类的构造方法来绑定Crime对象的数组列表。由于不打算使用预定义布局, 我们传入0作为布局参数。 */
super(getActivity(), 0, crimes);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
convertView = getActivity().getLayoutInflater().inflate(
R.layout.list_item_crime, null);
Crime crime = getItem(position);
TextView titleTextView = (TextView) convertView
.findViewById(R.id.crime_list_item_titleTextView);
titleTextView.setText(crime.getTitle());
TextView dateTextView = (TextView) convertView
.findViewById(R.id.crime_list_item_dateTextView);
dateTextView.setText(crime.getDate().toLocaleString());
/** * CheckBox默认是聚焦的。这意味着,点击列表项会被解读为切换CheckBox的状态,自然也就无法触发onListItemClick(...)方法了。 * 由于ListView的这种内部特点,出现在列表项布局内的任何可聚焦组件(如CheckBox或Button)都应设置为非聚焦状态(android:focusable="false"), * 从而保证用户点击列表项后能够获得预期效果。 */
CheckBox solvedCheckBox = (CheckBox) convertView
.findViewById(R.id.crime_list_item_solvedCheckBox);
solvedCheckBox.setChecked(crime.isSolved());
return convertView;
}
}
}
package com.huangfei.criminalintent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
/** * * @author huangfeihong * 普通托管Fragment的通用Activity */
public abstract class SingleFragmentActivity extends FragmentActivity {
protected abstract Fragment createFragment();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment);
/** * 因为使用了支持库及FragmentActivity类,因此这里调用的方法是getSupportFragmentManager()。如果不考虑Honeycomb以前版本的兼容性问题, * 可直接继承Activity类并调用getFragmentManager()方法。 * * FragmentManager类负责管理fragment并将它们的视图添加到activity的视图层级结构中。 * FragmentManager类具体管理的是: * 1、fragment队列; * 2、fragment事务的回退栈。 */
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);
if(fragment == null){
fragment = createFragment();
/** * 这段代码创建并提交一个fragment事务。 * fragment事务被用来添加、移除、附加、分离或替换fragment队列中的fragment。这是使用fragment * 在运行时组装和重新组装用户界面的核心方式。FragmentManager管理着fragment事务的回退栈。 * * add(容器视图资源ID, 新创建的fragment) * 容器视图资源ID的作用: * 1、告知FragmentManagerfragment视图应该出现在activity视图的什么地方; * 2、是FragmentManager队列中fragment的唯一标识符,见第25行代码’ */
fm.beginTransaction().add(R.id.fragmentContainer, fragment).commit();
}
}
}
public class CrimeListActivity extends SingleFragmentActivity {
@Override
protected Fragment createFragment() {
return new CrimeListFragment();
}
}
代码地址