参考大部分内容来源于http://blog.csdn.net/lmj623565791/article/details/37992017,感谢大神
一.管理Fragment回退栈
1.效果图:
2.主要代码(只是效果测试,没考虑代码的优化)
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.add(R.id.id_content, new FragmentOne(), "ONE");
tx.commit();
}
}
public class FragmentOne extends Fragment implements OnClickListener
{
private Button mBtn;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
System.out.println("xcqfragmentone 的view重新生成了");
View view = inflater.inflate(R.layout.fragment_one, container, false);
mBtn = (Button) view.findViewById(R.id.id_fragment_one_btn);
mBtn.setOnClickListener(this);
return view;
}
@Override
public void onClick(View v)
{
FragmentTwo fTwo = new FragmentTwo();
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.replace(R.id.id_content, fTwo, "TWO");
tx.addToBackStack(null);
tx.commit();
}
@Override
public void onDestroyView() {
super.onDestroyView();
System.out.println("xcqfragment one view被销毁了");
}
}
FragmentTwo.java
public class FragmentTwo extends Fragment implements OnClickListener
{
private Button mBtn ;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
System.out.println("xcqfragment two view被重建了");
View view = inflater.inflate(R.layout.fragment_two, container, false);
mBtn = (Button) view.findViewById(R.id.id_fragment_two_btn);
mBtn.setOnClickListener(this);
return view ;
}
@Override
public void onClick(View v)
{
FragmentThree fThree = new FragmentThree();
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.hide(this);
//如果调用这个方法就不会pao OndestroyView,也就是视图不会销毁,实例也不会销毁
tx.add(R.id.id_content , fThree, "THREE");
//如果调用这个视图和实例都会被销毁,但是由于加入后退栈中,所以实例保存下来
//但是会跑 onDestoryView
//tx.replace(R.id.id_content, fThree, "THREE");
tx.addToBackStack(null);
tx.commit();
}
@Override
public void onDestroyView() {
super.onDestroyView();
System.out.println("xcqfragment two view被销毁了");
}
}
public class FragmentThree extends Fragment implements OnClickListener
{
private Button mBtn;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_three, container, false);
mBtn = (Button) view.findViewById(R.id.id_fragment_three_btn);
mBtn.setOnClickListener(this);
return view;
}
@Override
public void onClick(View v)
{
Toast.makeText(getActivity(), " i am a btn in Fragment three", Toast.LENGTH_SHORT).show();
}
}
我们在点击FragmentOne中的按钮时,使用了replace方法,,replace是remove和add的合体,并且如果不添加事务到回退栈,前一个Fragment实例会被销毁。这里很明显,我们调用tx.addToBackStack(null);将当前的事务添加到了回退栈,所以FragmentOne实例不会被销毁,但是视图层次依然会被销毁,即会调用onDestoryView和onCreateView,证据就是:仔细看上面的效果图,我们在跳转前在文本框输入的内容,在用户Back得到第一个界面的时候不见了。
去掉布局中的EditText的id,就可以达到预想的效果,如果有id就不能达到效果(具体原因待查???找到了例如,EditText
小工具保存用户输入的任何文本,CheckBox
小工具保存复选框的选中或未选中状态。您只需为想要保存其状态的每个小工具提供一个唯一的 ID(通过 android:id
属性)。如果小工具没有 ID,则系统无法保存其状态。(Android官方开发文档上面写的))
这里点击时,我们没有使用replace,而是先隐藏了当前的Fragment,然后添加了FragmentThree的实例,最后将事务添加到回退栈。这样做的目的是为了给大家提供一种方案:如果不希望视图重绘该怎么做,请再次仔细看效果图,我们在FragmentTwo的EditText填写的内容,用户Back回来时,数据还在
二.Fragment之间的通信
1.同一个Activity中的Fragment之间的通信(待修改)(还有一种弹出dialogFragment)
(1)首先在第一个Fragment 里面拿到FragmentManger 和FragmentTransaction 代码如下。
<span style="font-weight: normal;"><span style="white-space:pre"> </span>@Override
public void onCreate(Bundle savedInstanceState) {
<span style="white-space:pre"> </span>// TODO Auto-generated method stub
<span style="white-space:pre"> </span> super.onCreate(savedInstanceState);
<span style="white-space:pre"> </span> fm = getFragmentManager();
}</span>
(2)准备要传递的数据跳转。
deptListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int postion,long arg3) {
ft = fm.beginTransaction();//注意。一个transaction 只能commit一次,所以不要定义成全局变量
long id = adapter.getDepartments().get(postion).getId();
String name = adapter.getDepartments().get(postion).getName();
DeptDocFragment df = new DeptDocFragment();
Bundle bundle = new Bundle();
bundle.putLong("id", id);
bundle.putString("name", name);
df.setArguments(bundle);
ft.replace(R.id.guide_content, df);
ft.addToBackStack(null);
ft.commit();
}
});
上面的DeptDocFragment就是我要跳转的Fragment,而传递数据跟Activity一样,用Bundle,最后通过df.setArguments(bundle);携带数据。通过replace方法切换Fragment实现跳转,最后别忘了commit 提交。
接下来就是在另一个Fragment 中获取第一个Fragment 传递过来的数据。
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
deptId = bundle.getLong("id");
deptName = bundle.getString("name");
}
</pre>在Fragment的onCreate() 方法中获取数据。然后在这个Fragment中完成你需要的逻辑。好了,整个Fragment的跳转就算是完成了。</h3><h2>2.不同Activity之间的fragment通信(也可以作为Activity和fragment之间的通信)</h2><h3><span style="font-weight:normal">假设,在一个Activity中点击一下然后会跳转到另外一个Activity中,然后把数据也传到另外一个Activity中的Fragment中。</span></h3><h3><span style="font-weight:normal">方法1:</span><p></p><pre name="code" class="java"><span style="font-weight: normal;">public class ContentFragment extends Fragment
{
private String mArgument ;
public static final String ARGUMENT ="argument";
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mArgument = getActivity().getIntent().getStringExtra(ARGUMENT);
} </span>
我们直接在Fragment的onCreate中,拿到宿主Activty,宿主Activity中肯定能通过getIntent拿到Intent,然后通过get方法,随意拿参数
这么写,功能上是实现了,但是呢?存在一个大问题:我们用Fragment的一个很大的原因,就是为了复用。你这么写,相当于这个Fragment已经完全和当前这个宿主Activity绑定了,复用直接废了(
复用失败也就是说如果,当前的这个fragment只能用在contentActivity,因为里面有getactivity.getintent,获取别人传给contentactivity, 也就是说如果这个fragment用在别的activity上,那么上面的getactivity.getintent,中穿的参数就不对应了,所以说就不能复用,所以直接让外界把参数传进来就行了
),所以上面的方法不推荐使用,我们换种方式,推荐使用arguments来创建Fragment。方法2:
1.public class ContentFragment extends Fragment
2.{
3.
4. private String mArgument;
5. public static final String ARGUMENT = "argument";
6.
7. @Override
8. public void onCreate(Bundle savedInstanceState)
9. {
10. super.onCreate(savedInstanceState);
11. // mArgument = getActivity().getIntent().getStringExtra(ARGUMENT);
12. Bundle bundle = getArguments();
13. if (bundle != null)
14. mArgument = bundle.getString(ARGUMENT);
15.
16. }
17.
18. /**
19. * 传入需要的参数,设置给arguments
20. * @param argument
21. * @return
22. */
23. public static ContentFragment newInstance(String argument)
24. {
25. Bundle bundle = new Bundle();
26. bundle.putString(ARGUMENT, argument);
27. ContentFragment contentFragment = new ContentFragment();
28. contentFragment.setArguments(bundle);
29. return contentFragment;
30. }
给Fragment添加newInstance方法,在ContentActivity中将需要的参数传入,设置到bundle中,然后setArguments(bundle),最后在onCreate中进行获取;
这样就完成了Fragment和Activity间的解耦。当然了这里需要注意:
setArguments方法必须在fragment创建以后,添加给Activity前完成。千万不要,首先调用了add,然后设置arguments。
源码后面会有(待添加)三.fragment与Activity之间通信
方法1.
如果你Activity中包含自己管理的Fragment的引用,可以通过引用直接访问所有的Fragment的public方法
方法2.(推荐)
在fragment中写一个抽象接口,里面写一个抽象方法,然后Activity去实现这个接口中的方法.
a.method1
FragmentOne.java
public class FragmentOne extends Fragment implements View.OnClickListener {
public interface FragmentOneClicklistener {
void onFgOneClick();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = View.inflate(getActivity(), R.layout.fragment_one, null);
Button bt_one = (Button) view.findViewById(R.id.bt_one);
bt_one.setOnClickListener(this);
return view;
}
//方法一:
@Override
public void onClick(View view) {
//判断有没有实现这个FragmentOneClicklistener
if (getActivity() instanceof FragmentOneClicklistener) {
((FragmentOneClicklistener) getActivity()).onFgOneClick();
}
}
}
b.method2
public class FragmentTwo extends Fragment implements View.OnClickListener {
public FragmentTwoClickListener mListener;
public void SetListener(FragmentTwoClickListener mListener){
this.mListener = mListener;
}
public interface FragmentTwoClickListener {
void onFgTwoClick();
}
public FragmentTwo() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = View.inflate(getActivity(),R.layout.fragment_two,null);
Button bt_two = (Button) view.findViewById(R.id.bt_two);
bt_two.setOnClickListener(this);
return view;
}
//方法二:
@Override
public void onClick(View view) {
if(mListener != null){
mListener.onFgTwoClick();
}
}
}
使用的Activity,MainActivity.java
public class MainActivity extends FragmentActivity implements FragmentOne.FragmentOneClicklistener, FragmentTwo.FragmentTwoClickListener {
private FragmentOne mFragmentOne;
private FragmentTwo mFragmentTwo;
private FragmentThree mFragmentThree;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if(savedInstanceState == null){
mFragmentOne = new FragmentOne();
}
ft.add(R.id.rl_fragment_container, mFragmentOne, "ONE");
ft.commit();
}
//方法一:只要Activity实现FragmentOneClicklistener就可以了
@Override
public void onFgOneClick() {
//跳到fragmentTwo
if(mFragmentTwo == null){
mFragmentTwo = new FragmentTwo();
//方法二:传入listner,然后调用方法
mFragmentTwo.SetListener(this);
}
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.rl_fragment_container,mFragmentTwo,"two");
ft.addToBackStack(null);
ft.commit();
}
@Override
public void onFgTwoClick() {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if(mFragmentThree == null){
mFragmentThree = new FragmentThree();
}
ft.replace(R.id.rl_fragment_container,mFragmentThree,"three");
ft.addToBackStack(null);
ft.commit();
}
}
源码下载
方法3.
如果Activity中未保存任何Fragment的引用,那么没关系,每个Fragment都有一个唯一的TAG或者ID,可以通过getFragmentManager.findFragmentByTag()或者findFragmentById()获得任何Fragment实例,然后进行操作。
<span style="white-space:pre"> </span>/**
* 初始化Fragment
*/
private void initFragment() {
// Fragment管理器
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();// 开始事务
// 将帧布局替换为对应的Fragment
transaction
.replace(R.id.fl_content, new ContentFragment(), TAG_CONTENT);
transaction.replace(R.id.fl_left_menu, new LeftMenuFragment(),
TAG_LEFT_MENU);
transaction.commit();// 提交事务
// fm.findFragmentByTag(TAG_CONTENT);
}
/**
* 获取侧边栏对象
*
* @return
*/
public LeftMenuFragment getLeftMenuFragment() {
FragmentManager fm = getSupportFragmentManager();
LeftMenuFragment fragment = (LeftMenuFragment) fm
.findFragmentByTag(TAG_LEFT_MENU);
return fragment;
}
/**
* 获取主页对象
*
* @return
*/
public ContentFragment getContentFragment() {
FragmentManager fm = getSupportFragmentManager();
ContentFragment fragment = (ContentFragment) fm
.findFragmentByTag(TAG_CONTENT);
return fragment;
}
总结:
代码重构结束,与开始的效果一模一样。方法二通信方式都是值得推荐的,随便选择一种自己喜欢的。这里再提一下:虽然Fragment和Activity可以通过getActivity与findFragmentByTag或者findFragmentById,进行任何操作,甚至在Fragment里面操作另外的Fragment,但是没有特殊理由是绝对不提倡的。Activity担任的是Fragment间类似总线一样的角色,应当由它决定Fragment如何操作。另外虽然Fragment不能响应Intent打开,但是Activity可以,Activity可以接收Intent,然后根据参数判断显示哪个Fragment。
四.如何处理运行时配置发生变化(重要)
运行时配置发生变化,最常见的就是屏幕发生旋转,如果你不知道如何处理屏幕变化可以参考:Android 屏幕旋转 处理 AsyncTask 和 ProgressDialog 的最佳方案
这里提一下:很多人觉得强制设置屏幕的方向就可以了,但是有一点,当你的应用被至于后台(例如用户点击了home),长时间没有返回的时候,你的应用也会被重新启动。比如上例:如果你把上面的例子你至于FragmentThree界面,然后处于后台状态,长时间后你会发现当你再次通过home打开时,上面FragmentThree与FragmentOne叠加在一起,这就是因为你的Activity重新启动,在原来的FragmentThree上又绘制了一个FragmentOne。
代码:
MainActivity.java
public class MainActivity extends Activity
{
private FragmentOne mFOne;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
mFOne = new FragmentOne();
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.add(R.id.id_content, mFOne, "ONE");
tx.commit();
}
}
FragmentOne.java
<span style="font-weight: normal;"><span style="font-size:14px;">public class FragmentOne extends Fragment
{
private static final String TAG = "FragmentOne";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
Log.e(TAG, "onCreateView");
View view = inflater.inflate(R.layout.fragment_one, container, false);
return view;
}
@Override
public void onCreate(Bundle savedInstanceState)
{
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
Log.e(TAG, "onCreate");
}
@Override
public void onDestroyView()
{
// TODO Auto-generated method stub
super.onDestroyView();
Log.e(TAG, "onDestroyView");
}
@Override
public void onDestroy()
{
// TODO Auto-generated method stub
super.onDestroy();
Log.e(TAG, "onDestroy");
}
} </span></span>
<span style="font-size:14px;"><span style="font-weight: normal;">很简单的代码,当你运行之后,不断的旋转屏幕,你会发现每旋转一次屏幕,屏幕上就多了一个FragmentOne的实例,并且后台log会打印出许多套生命周期的回调。
类似:
[html] view plaincopy
1.07-20 08:18:46.651: E/FragmentOne(1633): onCreate
2.07-20 08:18:46.651: E/FragmentOne(1633): onCreate
3.07-20 08:18:46.651: E/FragmentOne(1633): onCreate
4.07-20 08:18:46.681: E/FragmentOne(1633): onCreateView
5.07-20 08:18:46.831: E/FragmentOne(1633): onCreateView
6.07-20 08:18:46.891: E/FragmentOne(1633): onCreateView </span> </span>
这是为什么呢,因为当屏幕发生旋转,Activity发生重新启动,默认的Activity中的Fragment也会跟着Activity重新创建;这样造成当旋转的时候,本身存在的Fragment会重新启动,然后当执行Activity的onCreate时,又会再次实例化一个新的Fragment,这就是出现的原因。
<span style="font-weight: normal;"><span style="font-size:14px;">public class FragmentOne extends Fragment
{
private static final String TAG = "FragmentOne";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
Log.e(TAG, "onCreateView");
View view = inflater.inflate(R.layout.fragment_one, container, false);
return view;
}
@Override
public void onCreate(Bundle savedInstanceState)
{
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
Log.e(TAG, "onCreate");
}
@Override
public void onDestroyView()
{
// TODO Auto-generated method stub
super.onDestroyView();
Log.e(TAG, "onDestroyView");
}
@Override
public void onDestroy()
{
// TODO Auto-generated method stub
super.onDestroy();
Log.e(TAG, "onDestroy");
}
} </span></span>
<span style="font-size:14px;"><span style="font-weight: normal;">很简单的代码,当你运行之后,不断的旋转屏幕,你会发现每旋转一次屏幕,屏幕上就多了一个FragmentOne的实例,并且后台log会打印出许多套生命周期的回调。
类似:
[html] view plaincopy
1.07-20 08:18:46.651: E/FragmentOne(1633): onCreate
2.07-20 08:18:46.651: E/FragmentOne(1633): onCreate
3.07-20 08:18:46.651: E/FragmentOne(1633): onCreate
4.07-20 08:18:46.681: E/FragmentOne(1633): onCreateView
5.07-20 08:18:46.831: E/FragmentOne(1633): onCreateView
6.07-20 08:18:46.891: E/FragmentOne(1633): onCreateView </span> </span>
那么如何解决呢:
其实通过检查onCreate的参数Bundle savedInstanceState就可以判断,当前是否发生Activity的重新创建:
默认的savedInstanceState会存储一些数据,包括Fragment的实例:通过打印可以看出
<pre name="code" class="java">08:23:12.952: E/FragmentOne(1782): Bundle[{android:fragments=android.app.FragmentManagerState@40d0b7b8, android:viewHierarchyState=Bundle[{android:focusedViewId=2131230721, android:views=android.util.SparseArray@40d0af68}]}]
所以,我们简单改一下代码,只有在savedInstanceState==null时,才进行创建Fragment实例:
<span style="font-weight: normal;"><span style="font-size:14px;">public class MainActivity extends Activity
{
private static final String TAG = "FragmentOne";
private FragmentOne mFOne;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
Log.e(TAG, savedInstanceState+"");
if(savedInstanceState == null)
{
mFOne = new FragmentOne();
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.add(R.id.id_content, mFOne, "ONE");
tx.commit();
}
}
} </span></span>
<span style="font-weight: normal;"><span style="font-size:14px;">public class MainActivity extends Activity
{
private static final String TAG = "FragmentOne";
private FragmentOne mFOne;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
Log.e(TAG, savedInstanceState+"");
if(savedInstanceState == null)
{
mFOne = new FragmentOne();
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.add(R.id.id_content, mFOne, "ONE");
tx.commit();
}
}
} </span></span>
现在无论进行多次旋转都只会有一个Fragment实例在Activity中。
五.Fragment的startActivityForResult(可以看做不同Activity中的Fragment的通信,里面也包含了同一个activity中的fragment通信(dialogFragment))
依旧是一个简单的场景:两个Fragment,一个展示文章列表的Fragment(叫做ListTitleFragment),一个显示详细信息的Fragment(叫做:ContentFragment),当然了,这两个Fragment都有其宿主Activity。
现在,我们点击列表Fragment中的列表项,传入相应的参数,去详细信息的Fragment展示详细的信息,在详细信息页面,用户可以进行点评,当用户点击back以后,我们以往点评结果显示在列表的Fragment对于的列表项中;
也就是说,我们点击跳转到对应Activity的Fragment中,并且希望它能够返回参数,那么我们肯定是使用Fragment.startActivityForResult ;
在Fragment中存在startActivityForResult()以及onActivityResult()方法,但是呢,没有setResult()方法,用于设置返回的intent,这样我们就需要通过调用getActivity().setResult(ListTitleFragment.REQUEST_DETAIL, intent);。
1.效果图
2.主要代码
public class ListTitleFragment extends ListFragment {
private List<String> mTitleList = Arrays.asList("很好","一般","不好");
public static final int REQUEST_DETAIL = 0x110;
private ArrayAdapter mAdapter;
private int mClickPosition;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//给adapter填充数据
setListAdapter(mAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1,mTitleList));
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
//记录当前被点击的位置
mClickPosition = position;
//准备跳到另外一个activity
Intent intent = new Intent(getActivity(), ContentActivity.class);
//确定点的是哪个item
intent.putExtra(ContentFragment.ARGUMENT,mTitleList.get(position));
//activity之间跳转
startActivityForResult(intent,REQUEST_DETAIL);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_DETAIL){
if(data != null){
mTitleList.set(mClickPosition,mTitleList.get(mClickPosition)+"---"+data.getStringExtra(ContentFragment.RESPONSE));
//然后刷新listview
mAdapter.notifyDataSetChanged();
}
}
}
}
ContentFragment.java
public class ContentFragment extends Fragment implements OnClickListener {
public static final String ARGUMENT = "argument";
public static final String RESPONSE = "response";
public static final int REQUEST_EVALUATE = 0X111;
public static final String EVALUATE_DIALOG = "evaluate_dialog";
private String mArgument;
public static ContentFragment newInstance(String argument){
Bundle bundle = new Bundle();
bundle.putString(ARGUMENT,argument);
ContentFragment contentFragment = new ContentFragment();
//fragment把这个参数保存到bundle
contentFragment.setArguments(bundle);
return contentFragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
if (bundle != null)
{
mArgument = bundle.getString(ARGUMENT);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//写一个布局出来
TextView tv = new TextView(getActivity());
//设置随机背景颜色
Random random = new Random();
//设置布局(自己对父亲的期望)
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);
tv.setText(mArgument);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 30);
tv.setGravity(Gravity.CENTER);
tv.setLayoutParams(params);
//设置背景颜色
tv.setBackgroundColor(Color.argb(random.nextInt(100), random.nextInt(255), random.nextInt(255), random.nextInt(255)));
tv.setOnClickListener(this);
return tv;
}
@Override
public void onClick(View v) {
//点击布局就会弹出一个对话框
EvaluteDialog dialog = new EvaluteDialog();
//我们调用了Fragment.setTargetFragment ,这个方法,
// 一般就是用于当前fragment由别的fragment启动,在完成操作后返回数据的,符合我们的需求吧~~~注意,这句很重要。
//注意setTargetFragment
dialog.setTargetFragment(ContentFragment.this, REQUEST_EVALUATE);
dialog.show(getFragmentManager(), EVALUATE_DIALOG);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//点击弹出来的对话框
if(requestCode == REQUEST_EVALUATE){
if(data != null){
String evaluate = data.getStringExtra(EvaluteDialog.RESPONSE_EVALUATE);
//弹出Toast
Toast.makeText(getActivity(),evaluate,Toast.LENGTH_SHORT).show();
//回到最初的listTitleFragment并显示选中的评价
Intent intent = new Intent();
intent.putExtra(RESPONSE, evaluate);
//返回到listTitleFragment
//ListTitleFragment.REQUEST_DETAIL这个写这里没有什么用,没用到
getActivity().setResult(ListTitleFragment.REQUEST_DETAIL, intent);
//退出当前activity
getActivity().finish();
}
}
}
}
两个Fragment的代码,可以看到我们在ListTitleFragment.onListItemClick,
1.使用startActivityForResult()跳转到目标Activity,在目标Activity的Fragment(ContentFragment)中获取参数,
2.在contentFragemnt中获取参数,是通过弹出一个对话框,然后里面的条目的单个点击事件调用contentFragment的OnActivityResult,并把点击的条目参数传进去,
3.在OnActivityResult中调用getActivity().setResult(ListTitleFragment.REQUEST_DETAIL, intent);进行设置返回的数据;最后在ListTitleFragment.onActivityResult()拿到返回的数据进行回显;
为大家以后在遇到类似问题时,提供了解决方案;也说明了一个问题:fragment能够从Activity中接收返回结果,但是其自设无法产生返回结果,只有Activity拥有返回结果。
public class EvaluteDialog extends DialogFragment
{
private String[] mEvaluteVals = new String[] { "GOOD", "BAD", "NORMAL" };
public static final String RESPONSE_EVALUATE = "response_evaluate";
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Evaluate :").setItems(mEvaluteVals,
new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
setResult(which);
}
});
return builder.create();
}
// 设置返回数据
protected void setResult(int which)
{
// 判断是否设置了targetFragment
if (getTargetFragment() == null)
return;
Intent intent = new Intent();
intent.putExtra(RESPONSE_EVALUATE, mEvaluteVals[which]);
getTargetFragment().onActivityResult(ContentFragment.REQUEST_EVALUATE,
Activity.RESULT_OK, intent);
}
}
MainActivity.java
public class MainActivity extends BaseActivity {
private ListTitleFragment listTitleFragment;
@Override
public Fragment createFragment() {
//制造fragment填充
listTitleFragment = new ListTitleFragment();
return listTitleFragment;
}
}
public class ContentActivity extends BaseActivity {
private ContentFragment mContentFragment;
@Override
public Fragment createFragment() {
//获取上一个activity传递上来的数据
String title = getIntent().getStringExtra(ContentFragment.ARGUMENT);
//把传过来的数据传给ContentFragment
mContentFragment = ContentFragment.newInstance(title);
return mContentFragment;
}
}
BaseActivity.java
<span style="font-size:14px;">public abstract class BaseActivity extends FragmentActivity{
//暴露给子类去创建fragment
public abstract Fragment createFragment();
@Override
protected void onSaveInstanceState(Bundle outState)
{
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//为什么这个布局看起来没什么用??????
setContentView(R.layout.activity_my_list);
// 1、为什么需要判null呢?
// 主要是因为,当Activity因为配置发生改变(屏幕旋转)或者内存不足被系统杀死,造成重新创建时,
// 我们的fragment会被保存下来,但是会创建新的FragmentManager,
// 新的FragmentManager会首先会去获取保存下来的fragment队列,重建fragment队列,从而恢复之前的状态。
// 2、add(R.id.id_fragment_container,mContentFragment)中的布局的id有何作用?
// 一方面呢,是告知FragmentManager,此fragment的位置;另一方面是此fragment的唯一标识;
// 就像我们上面通过fm.findFragmentById(R.id.id_fragment_container)
FragmentManager fm = getSupportFragmentManager();
//根据id找到fragment布局
Fragment fragment = fm.findFragmentById(R.id.rl_fragment_container);
if(fragment == null){
fragment = createFragment();
//填充fragment
fm.beginTransaction().replace(R.id.rl_fragment_container,fragment).commit();
}
}
}</span>
------------------------------------------------------------------------复杂版----------------------------------------------------------------------------------
通过这个BaseActivity让两个Actvity中重复的部分大大减小,否则代码就会如下(复杂版,重复了很多)
public class ListTitleActivity extends FragmentActivity
{
private ListTitleFragment mListFragment;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_fragment);
FragmentManager fm = getSupportFragmentManager();
mListFragment = (ListTitleFragment) fm.findFragmentById(R.id.id_fragment_container);
if(mListFragment == null )
{
mListFragment = new ListTitleFragment();
fm.beginTransaction().add(R.id.id_fragment_container,mListFragment).commit();
}
}
}
public class ContentActivity extends FragmentActivity
{
private ContentFragment mContentFragment;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_fragment);
FragmentManager fm = getSupportFragmentManager();
mContentFragment = (ContentFragment) fm.findFragmentById(R.id.id_fragment_container);
if(mContentFragment == null )
{
String title = getIntent().getStringExtra(ContentFragment.ARGUMENT);
mContentFragment = ContentFragment.newInstance(title);
fm.beginTransaction().add(R.id.id_fragment_container,mContentFragment).commit();
}
}
}
公用的布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/id_fragment_container"
>
</RelativeLayout>
------------------------------------------------------------------------复杂版----------------------------------------------------------------------------------
源码待上传