第二个项目CriminalIntent应用开发阶段总结(一)
第二个项目CriminalIntent应用开发阶段总结(一)
fragment的使用
采用fragment而不是activity来管理应用UI,可绕开Android系统activity使用规则的限制。fragment必须依赖activity使用,fragment是一种控制器对象,activity可委派它执行任务。
- 创建fragment容器布局
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fragment_container">
</FrameLayout>
- 定义用户界面布局文件
<TextView
style="?android:listSeparatorTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/crime_title_label"/>
<EditText
android:id="@+id/crime_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/crime_title_hint"/>
<TextView
style="?android:listSeparatorTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/crime_details_label"/>
<Button
android:id="@+id/crime_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="80dp"/>
<CheckBox
android:id="@+id/crime_solved"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/crime_solved_label"/>
- 创建fragment类并设置其视图为定义的布局
//继承Fragment类
public class CrimeFragment extends Fragment{}
//覆盖Fragment.onCreate(Bundle)方法
private Crime mCrime;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCrime = CrimeLab.get(getActivity()).getCrime(crimeId);
}
//覆盖onCreateView(...)方法
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState){
View v = inflater.inflate(R.layout.fragment_crime,container,false);
return v;
}
- 实例化组件
//生成并使用EditText组件
private EditText mTitleField;
mTitleField = (EditText)v.findViewById(R.id.crime_title);
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 too
}
});
//设置Button文字
private Button mDateButton;
mDateButton = (Button) v.findViewById(R.id.crime_date);
mDateButton.setText(mCrime.getDate().toString());
mDateButton.setEnabled(false);
//监听CheckBox的变化
private CheckBox mSolvedCheckBox;
mSolvedCheckBox = (CheckBox)v.findViewById(R.id.crime_solved);
mSolvedCheckBox.setOnCheckedChangeListener(
new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(
CompoundButton buttonView, boolean isChecked) {
mCrime.setSolved(isChecked);
}
});
- 向FragmentManager添加UI fragment
//获取FragmentManager
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();
}
fragment的生命周期
fragment的生命周期类似于activity的生命周期,它具有停止,暂停以及运行状态,也拥有可以覆盖的方法,用来在关键节点完成一些任务。
fragment生命周期与activity生命周期的一个关键区别就在于,fragment的生命周期方法由托管activity而不是操作系统调用。
RecyclerView显示列表
单例
crime数组对象将存储在一个单例里。单例是特殊的java类,在创建实例时,一个单例类仅允许创建一个实例。应用能在内存里活多久,单例就能活多久。因此将对象列表保存在单例里的话,就能随时获取crime数据,不管activity和fragment的生命周期怎么变化。
//创建单例
public class CrimeLab {
private static CrimeLab sCrimeLab;
public static CrimeLab get(Context context) {
if (sCrimeLab == null){
sCrimeLab = new CrimeLab(context);
}
return sCrimeLab;
}
private CrimeLab(Context context){}
}
//创建可容纳Crime对象的List
private List<Crime> mCrimes;
mCrimes = new ArrayList<>();
public List<Crime> getCrimes() {
return mCrimes;
}
public Crime getCrime(UUID id){
for (Crime crime:mCrimes){
if (crime.getId().equals(id)){
return crime;
}
}
return null;
}
RecyclerView,ViewHolder和Adapter
RecyclerView是ViewGroup的子类,每一个列表项都是作为一个View子对象显示的。RecyclerView只创建刚好充满屏幕的View,而不是100个。用户滑动屏幕切换视图时,上一个视图会回收利用。
-
ViewHolder和Adapter
RecyclerView的任务仅限于回收和定位屏幕上的View。列表项View能够显示数据还离不开另外两个类的支持:ViewHolder子类和Adapter子类。ViewHolder只做一件事:容纳View视图
Adapter是一个控制器对象,从模型层获取数据,然后提供给RecyclerView显示,是沟通的桥梁。
-
使用RecyclerView
//在布局文件中添加RecyclerView视图
<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>
//为CrimeListFragment配置视图
private RecyclerView mCrimeRecyclerView;
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(getContext()));
return view;
}
- 实现ViewHolder和Adapter
//定义ViewHolder内部类
private class CrimeHolder extends RecyclerView.ViewHolder{
public CrimeHolder(LayoutInflater inflater,ViewGroup parent) {
super(inflater.inflate(R.layout.list_item_crime,parent,false));
}
}
//创建Adapter内部类
private class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder>{
private List<Crime> mCrimes;
public CrimeAdapter(List<Crime> crimes){
mCrimes = crimes;
}
}
//武装CrimeAdapter
@Override
public CrimeHolder onCreateViewHolder(ViewGroup parent,int viewType){
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
return new CrimeHolder(layoutInflater,parent);
}
@Override
public void onBindViewHolder(CrimeHolder holder,int position){
Crime crime = mCrimes.get(position);
holder.bind(crime);
}
@Override
public int getItemCount(){
return mCrimes.size();
}
//设置Adapter
private CrimeAdapter mAdapter;
updareUI();
private void updareUI() {
CrimeLab crimeLab = CrimeLab.get(getActivity());
List<Crime> crimes = crimeLab.getCrimes();
if (mAdapter == null){
mAdapter = new CrimeAdapter(crimes);
mCrimeRecyclerView.setAdapter(mAdapter);
}else {
mAdapter.notifyDataSetChanged();
}
updateSubtitle();
}
- 绑定列表项
//在构造方法中实例化视图组件
private TextView mTitleTextView;
private TextView mDateTextView;
mTitleTextView = (TextView) itemView.findViewById(R.id.crime_title);
mDateTextView = (TextView) itemView.findViewById(R.id.crime_date);
//实现bind(Crime)方法
private Crime mCrime;
public void bind(Crime crime){
mCrime = crime;
mTitleTextView.setText(mCrime.getTitle());
mDateTextView.setText(mCrime.getDate().toString());
}
//调用bind(Crime)方法
@Override
public void onBindViewHolder(CrimeHolder holder,int position){
Crime crime = mCrimes.get(position);
holder.bind(crime);
}
- 响应点击
private class CrimeHolder extends RecyclerView.ViewHolder implements View.OnClickListener{}
itemView.setOnClickListener(this);
使用图形布局工具布局
图形布局工具界面的中间区域是布局的界面预览窗口。右边紧挨的是蓝图视图。它能显示各个组件视图的轮廓。可以看出各个组件视图的大小比例。