介绍:CriminalIntent应用能记录陋习的标题,日期以及照片,也支持在联系人当中查找当事人,通过E-mail,Twitter,FaceBook或其他应用提出抗议。把陋习处理完,有了好心情,就可以继续专心做手头上的工作。
• 第7章:项目初步搭建mvc模式,fragment的介绍,生命周期,托管方式,使用fragment的理由。
• 第8章:Crimefragment界面升级,水平模式布局,
• 第9章:创建单例CrimeLab(容纳Crime对象),抽象activity类,RecycleView使用,相应点击时间
• 第10章:fragment数据传递—fragment argument,刷新RecycleView,通过fragment获取返回结果
• 第11章:Viewpager使用,FragmentStatePagerAdapter与FragmentPagerAdapter
思维导图
UI fragment与fragment管理器
fragment的生命周期
1. 使用fragment的前提是,activity知道如何管理fragment,FragmentActivity类知道如何管理支持版本的fragment.
2. Fragment生命周期与activity生命周期的一个关键区别,fragment的生命周期方法是由托管activity而不是操作系统调用,操作系统不关心activity用来管理视图的fragment,fragment的使用是activity内部的事情.
3. 托管的两种方式
• 使用布局fragment,简单但是不够灵活,在activity布局中添加fragment,就等同于将fragment及其视图与activity的视图绑定在一起,并且在activity的生命周期过程中,无法切换fragment视图
• 比较复杂,但是也是唯一可以在运行时控制,fragment的方式,.自行决定何时添加fragment以及随后可以完成何种具体任务,也可以移除fragment,用其他fragment代替,然后重新添加已移除的fragment
4. Fragment.Create(Bundle)是公共方法Activity.onCreate(Bundle)是保护方法.Fragment.oncreate方法以及其他Fragment生命周期方法必须是公共方法,因为托管fragment的activity要调用它们
5. Activity的FragmentManager负责调用队列中fragment的生命周期方法.添加fragment供fragmentManager管理时,onAttach(Activity),oncreate(),onAcivityCreate()方法也会被调用
6. 在activity处在运行状态时,添加fragment, FragmentManager立即驱使fragment行动,执行必要方法, 与activity的最新状态保持同步,一旦fragment的状态与activity的状态保持了同步,托管activity的FragmentManager就会边接收操作系统的调用指令,边调用其他生命周期方法,以保持fragment与activity的状态一致
使用RecyclerView显示列表
1.升级CriminalInent应用的模型层
2.使用抽象activity托管fragment
1.使用抽象类
2.新建控制类:CrimeListActivity和CrlmeListFragment
3.在配置文件中申明CrimeListActivity
...
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
android:label="@string/app_name">
运行界面图:
使用布局与组件创建用户界面
运行结果图:
使用fragment argument
1.附加argument给fragment
编写newInstance(UUID)方法:
public class CrimeFragment extends Fragment {
private static final String ARG_CRIME_ID ="crime_id";
private Crime mCrime;
private EditText mTitleField;
private Button mDateButton;
private CheckBox mSolvedCheckbox;
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;
}
...
}
使用newInstance(UUID)方法:
public class CrimeActivity extends SingleFragmentActivity {
public static final String EXTRA_CRIME_ID =
"com.bignerdranch.android.criminalintent.crime_id";
private static final String EXTRA_CRIME_ID =
"com.bignerdranch.android.criminalintent.crime_id";
...
@Override
protected Fragment createFragment() {
return new CrimeFragment();
UUID crimeId = (UUID) getIntent()
.getSerializableExtra(EXTRA_CRIME_ID);
return CrimeFragment.newInstance(crimeId);
}
}
CrimeFragment视图:
刷新显示列表项,应用对象图解更新后:
2.为何要用fragment argument?
Fragment argument的使用还有有点复杂,为什么不直接在CrimeFragment,里创建一个实例变量呢?
创建实例变量的方式并不可靠,因为,操作系统重建fragment时,设备配置发生改变时,用户暂时离开当前应用时,甚至操作系统按需回收内存时,任何实例变量不复存在了,尤其是内存不够,杀掉应用的情况,可以说你无人能挡. 因此,可以说,fragment argument就是为应对上述场景而生.
还有另一个应对上述场景,就是实例状态保存机制,onsaveInstanceState(Bundle)方法, 然而,这种解决方案维护成本高,若干年后,再回头修改老代码,只需一眼就知道,crime id是以argument保存和传递使用,而很可能忘记在onSaveInstanceState(Bundle)方法里保存下来
使用ViewPager
为UI添加ViewPager后,用户可以左右滑动屏幕,切换查看不同列表项的明细页面,如图:
需要完成以下任务:
1.创建CrimePagerActivity类;
2.定义包含ViewPager的视图层级结构;
3.在CrimePagerActivity类中关联使用ViewPager及其Adapter;
4.修改CrimeHolder.onClick(...)方法,转而启动CrimePagerActivity。
创建ViewPager
public class CrimePagerActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crime_pager);
}
}
设置pager adapter
public class CrimePagerActivity extends FragmentActivity {
private ViewPager mViewPager;
private List mCrimes;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crime_pager);
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(intposition) {
Crime crime = mCrimes.get(position);
return CrimeFragment.newInstance(crime.getId());
}
@Override
public int getCount() {
return mCrimes.size();
}
});
}
}
易错点
1.导错包:例如:
package com.bignerdranch.android.criminalintent;
import android.support.v4.app.Fragment;
public class CrimeFragment extends Fragment {
}
很有可能导成android.app.Fragment
2.单词拼写错误
3.尽管fragment有自己的statrtActivityForResult()和onActivityResult()方法,但却没有setResult方法,要用activity中的setResult方法
4.DateFormat.getTimeFormat(this).format(new Date());时分
DateFormat.getDateFormat(this).format(new Date());年月日