Fragment的解析和使用(二)

参考大部分内容来源于http://blog.csdn.net/lmj623565791/article/details/37992017,感谢大神

本文系个人学习后的总结

一.管理Fragment回退栈

目的:按回退键会回到上一个Fragment
FragmentTransaction.addToBackStack(String)

1.效果图:



2.主要代码(只是效果测试,没考虑代码的优化)

MainActivity.java
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();
	}

}

FragMentOne.java
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被销毁了");
	    }
	  
	  
	}  



FragmentThree.java

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方法,,replaceremoveadd的合体,并且如果不添加事务到回退栈,前一个Fragment实例会被销毁。这里很明显,我们调用tx.addToBackStack(null);将当前的事务添加到了回退栈,所以FragmentOne实例不会被销毁,但是视图层次依然会被销毁,即会调用onDestoryViewonCreateView,证据就是:仔细看上面的效果图,我们在跳转前在文本框输入的内容,在用户Back得到第一个界面的时候不见了。

去掉布局中的EditText的id,就可以达到预想的效果,如果有id就不能达到效果(具体原因待查???找到了例如,EditText 小工具保存用户输入的任何文本,CheckBox 小工具保存复选框的选中或未选中状态。您只需为想要保存其状态的每个小工具提供一个唯一的 ID(通过 android:id 属性)。如果小工具没有 ID,则系统无法保存其状态。(Android官方开发文档上面写的)

这里点击时,我们没有使用replace,而是先隐藏了当前的Fragment,然后添加了FragmentThree的实例,最后将事务添加到回退栈。这样做的目的是为了给大家提供一种方案:如果不希望视图重绘该怎么做,请再次仔细看效果图,我们在FragmentTwoEditText填写的内容,用户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>

我们直接在FragmentonCreate中,拿到宿主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中进行获取;

这样就完成了FragmentActivity间的解耦。当然了这里需要注意:

setArguments方法必须在fragment创建以后,添加给Activity前完成。千万不要,首先调用了add,然后设置arguments

源码后面会有(待添加)

三.fragment与Activity之间通信

方法1.

如果你Activity中包含自己管理的Fragment的引用,可以通过引用直接访问所有的Fragmentpublic方法

方法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,这就是出现的原因。
 

那么如何解决呢:

其实通过检查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>

现在无论进行多次旋转都只会有一个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.主要代码

ListTitleFragment.java
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拥有返回结果



从ContentFragment到弹出对话框,可以看做是一个activity中的两个fragment之间的通信(点下dialog中条目,contentFragment中的吐司会弹出对应的信息)
EvaluateDialog.java
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;
    }

}


ContentActivity.java
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中重复的部分大大减小,否则代码就会如下(复杂版,重复了很多)
ListTileActiviyt.java
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();  
        }  
  
    }  
}  

ContentActivity.java
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>  

------------------------------------------------------------------------复杂版----------------------------------------------------------------------------------
源码待上传

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值