Android编程权威指南 - 第10章 使用fragment
2016-12-08 本文已影响487人
JMasche
目标
本章的目标效果是,在列表中点击一项,弹出明细fragment界面。
此界面可以修改后,并保存返回列表fragment界面。
类的调用关系如下:
启动明细界面CrimeFragment
CrimeListFragment类中启动调用
- 启动是在点击列表的某一项之后,所以在onListItemClick函数中启动
- 和Activity启动另外一个Activity函数一样,通过显示的声明一个Intent对象,对象指定了调用类和被调用类。需要说明的是,仍旧调用的是包含目标fragment的Activity,而不是直接调用fragment。
- 仍旧通过intent的putExtra来传递信息。由于明细是要显示对应的对象内容的,所以我们传递了具体的Crime对象给被调用者。并且设置了其对应的key为CrimeFragment.EXTRA_CRIME_ID常量。
- 通过startActivity()来启动
具体代码如下
@Override
public void onListItemClick(ListView a, View v, int position, long id) {
Crime c = ((CrimeAdapter)getListAdapter()).getItem(position);
Log.d(TAG, c.getTitle() + " was clicked.");
// Start CrimeActivity
Intent i = new Intent(getActivity(), CrimeActivity.class);
i.putExtra(CrimeFragment.EXTRA_CRIME_ID, c.getId());
startActivity(i);
}
CrimeFragment类的设计
获取Intent内容
和Activity一样,通过activity的getSerializableExtra来获得Intent传递的对象
UUID crimeId = (UUID)this.getIntent().getSerializableExtra(CrimeFragment.EXTRA_CRIME_ID);
获取Intent并处理的设计
在哪获取Intent传递的消息信息?
我们可以直接在CrimeFragment类中使用上面的代码获取Intent的内容,并生成具体的Crime对象,然后刷新明细界面。
但是这样做的问题在于,牺牲了CrimeFragment的封装性,使得其无法再被其他的activity进行调用。
所以,我们应该在Activity就处理掉Intent信息,并将获取的信息作为参数传递给Fragment。传递此参数的对象就是Bundle。
用于传递参数的Bundle对象
- 每一个Fragment都有一个对应的Bundle对象,我们可以将要使用的参数塞进Bundle对象中,需要的时候再取出来使用。
- Bundle的参数是key-value形式存储的。
最终的设计
- CrimeFragment类中创建一个newInstance的静态方法用于生成CrimeFragment实例。最重要的是,这个方法里包含了Bundle对象的生成和参数的设置。
public static CrimeFragment newInstance(UUID crimeId) {
Bundle args = new Bundle();
args.putSerializable(EXTRA_CRIME_ID, crimeId);
CrimeFragment fragment = new CrimeFragment();
fragment.setArguments(args);
return fragment;
}
- 这时,我们可以在包含fragment的CrimeActivity类中,获取Intent中的参数。然后调用newInstance生成CrimeFragment实例,并且将Intent中的参数设置进Bundle中。
public class CrimeActivity extends SingleFragmentActivity {
@Override
protected Fragment createFragment() {
UUID crimeId = (UUID)this.getIntent().getSerializableExtra(CrimeFragment.EXTRA_CRIME_ID);
return CrimeFragment.newInstance(crimeId);
}
}
- 我们再在CrimeFragment类的onCreate函数中,获取Bundle中的参数,并生成刷新界面需要的Crime对象。
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UUID crimeId = (UUID)getArguments().getSerializable(EXTRA_CRIME_ID);
mCrime = CrimeLab.get(getActivity()).getCrime(crimeId);
}
- 在CrimeFragment类的onCreateView函数中设置要显示的界面
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_crime, parent, false);
mTitleField = (EditText)v.findViewById(R.id.crime_title);
mTitleField.setText(mCrime.getTitle());
..........................................................
mSolvedCheckBox = (CheckBox)v.findViewById(R.id.crime_solved);
mSolvedCheckBox.setChecked(mCrime.isSolved());
...........................................................
return v;
}
最终效果
选中列表的Cime 4点击,出现如下明细界面
明细界面列表界面显示明细的修改
- 我们在明细界面可以修改Title这样的参数,点击返回按钮,默认是不会显示修改信息的。如果需要显示,则需要做相关的处理。
- 我们只需要一行代码就可以实现这样的功能了。
((CrimeAdapter)getListAdapter()).notifyDataSetChanged();
这确实挺神奇的,毕竟在明细界面完全没有配置相关代码,Adapter是需要好好研究的类。
-
实现功能语句放在哪?
当我们跳转到CrimeFragment(CrimeActiviy)时,CrimeListActivity和CrimeListFragment是处于暂停的状态。所以当返回时,系统会调用onResume来进行恢复。
也就是说实现显示变化的语句应该放在CrimeListFragment类的onResume函数中。
@Override
public void onResume() {
super.onResume();
((CrimeAdapter)getListAdapter()).notifyDataSetChanged();
}
通过fragment获取返回结果
- 在CrimeListFragment类中,启动时用的是Fragment的startActivityForResult方法,而不是Activity的此方法;获取返回值并处理时,覆写的是Fragment的onActivityResult方法,而不是Activity的此方法。
public class CrimeListFragment extends ListFragment {
private ArrayList<Crime> mCrimes;
private static final String TAG = "CrimeListFragment";
private static final int REQUEST_CRIME = 1;
@Override
public void onListItemClick(ListView a, View v, int position, long id) {
Crime c = ((CrimeAdapter)getListAdapter()).getItem(position);
Log.d(TAG, c.getTitle() + " was clicked.");
// Start CrimeActivity
Intent i = new Intent(getActivity(), CrimeActivity.class);
i.putExtra(CrimeFragment.EXTRA_CRIME_ID, c.getId());
startActivityForResult(i, REQUEST_CRIME);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CRIME) {
// Handle result
}
}
}
- Fragment可以获取返回结果,但是不能产生返回结果。只能通知托管其的Activity来设置返回结果。
public class CrimeFragment extends Fragment {
public void returnResult() {
getActivity().setResult(Activity.RESULT_OK, null);
}
}
具体的应用在20章才会详细介绍*