Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信


我前两天写过一篇博客《Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信》(http://www.cnblogs.com/tiantianbyconan/p/3360938.html),实现了Tab切换时保留当前Fragment状态,并在切换前自动回调onPause()方法,在切换后自动调用onResume(),这样就做到了跟TahHost一样的功能。

今天来实现下ViewPager的功能,google提供了一个FragmentPagerAdapter这么一个适配器,蛋疼的是,碰到了跟上次类似的问题。比如ViewPager有5个page,刚打开的时候,会加载page1和page2,我们手动切换到page2的时候,会加载page3,切换到page3的时候,加载page4的同时会destory掉page1,所以,还是面临同样的问题,page的状态无法保存,于是,咱还是自己来实现下好了,自己动手,丰衣足食嘛!(同样 有朋友知道解决办法的话,希望联系我,赐教下哈

先来看下整个demo的结构,跟上次实现TabHost的例子差不多:

TabAFm到TabEFm都是Fragment,并且每个Fragment对应一个布局文件。

TabAFm.java:

 



 1 package com.wangjie.fragmentviewpagertest;
2
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.support.v4.app.Fragment;
6 import android.view.LayoutInflater;
7 import android.view.View;
8 import android.view.ViewGroup;
9
10 /*
11 Created with IntelliJ IDEA.
12 Author: wangjie email:tiantian.china.2@gmail.com
13 Date: 13-6-14
14 Time: 下午2:39
15 /
16 public class TabAFm extends Fragment{
17 @Override
18 public void onAttach(Activity activity) {
19 super.onAttach(activity);
20 System.out.println(“AAAAAAAAAAonAttach”);
21 }
22
23 @Override
24 public void onCreate(Bundle savedInstanceState) {
25 super.onCreate(savedInstanceState);
26 System.out.println(“AAAAAAAAAA
onCreate”);
27 }
28
29 @Override
30 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
31 System.out.println(“AAAAAAAAAAonCreateView”);
32 return inflater.inflate(R.layout.tab_a, container, false);
33 }
34
35 @Override
36 public void onActivityCreated(Bundle savedInstanceState) {
37 super.onActivityCreated(savedInstanceState);
38 System.out.println(“AAAAAAAAAA
onActivityCreated”);
39 }
40
41 @Override
42 public void onStart() {
43 super.onStart();
44 System.out.println(“AAAAAAAAAAonStart”);
45 }
46
47 @Override
48 public void onResume() {
49 super.onResume();
50 System.out.println(“AAAAAAAAAA
onResume”);
51 }
52
53 @Override
54 public void onPause() {
55 super.onPause();
56 System.out.println(“AAAAAAAAAAonPause”);
57 }
58
59 @Override
60 public void onStop() {
61 super.onStop();
62 System.out.println(“AAAAAAAAAA
onStop”);
63 }
64
65 @Override
66 public void onDestroyView() {
67 super.onDestroyView();
68 System.out.println(“AAAAAAAAAAonDestroyView”);
69 }
70
71 @Override
72 public void onDestroy() {
73 super.onDestroy();
74 System.out.println(“AAAAAAAAAA
onDestroy”);
75 }
76
77 @Override
78 public void onDetach() {
79 super.onDetach();
80 System.out.println(“AAAAAAAAAA____onDetach”);
81 }
82 }


View Code

如上述代码所示,TabAFm是一个Fragment,对应的布局文件是tab_a.xml,并实现了他的所有的生命周期回调函数并打印,便于调试

tab_a.xml布局中有个EditText

其他的Fragment大同小异,这里就不贴出代码了

 

现在来看MainActivity:



 1 package com.wangjie.fragmentviewpagertest;
2
3 import android.os.Bundle;
4 import android.support.v4.app.Fragment;
5 import android.support.v4.app.FragmentActivity;
6 import android.support.v4.view.ViewPager;
7
8 import java.util.ArrayList;
9 import java.util.List;
10
11 public class MainActivity extends FragmentActivity {
12 private ViewPager viewPager;
13 public List<Fragment> fragments = new ArrayList<Fragment>();
14 public String hello = “hello “;
15
16 @Override
17 public void onCreate(Bundle savedInstanceState) {
18 super.onCreate(savedInstanceState);
19 setContentView(R.layout.main);
20
21 fragments.add(new TabAFm());
22 fragments.add(new TabBFm());
23 fragments.add(new TabCFm());
24 fragments.add(new TabDFm());
25 fragments.add(new TabEFm());
26
27 viewPager = (ViewPager) findViewById(R.id.viewPager);
28 FragmentViewPagerAdapter adapter = new FragmentViewPagerAdapter(this.getSupportFragmentManager(), viewPager,fragments);
29 adapter.setOnExtraPageChangeListener(new FragmentViewPagerAdapter.OnExtraPageChangeListener(){
30 @Override
31 public void onExtraPageSelected(int i) {
32 System.out.println(“Extra…i: “ + i);
33 }
34 });
35
36 }
37
38 }


View Code

MainActivity上述代码所示

MainActivity是包含Fragment的Activity(也就是这里的5个Fragment)

他继承了FragmentActivity(因为我这里用的是android-support-v4.jar)

用一个List<Fragment>去维护5个Fragment,也就是5个page。

MainActivity的布局很简单,就一个ViewPager,main.xml如下:



 1 <?xml version=”1.0” encoding=”utf-8”?>
2 <LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android
3 android:orientation=”vertical”
4 android:layout_width=”fill_parent”
5 android:layout_height=”fill_parent”
6 >
7 <android.support.v4.view.ViewPager
8 android:id=”@+id/viewPager”
9 android:layout_width=”match_parent”
10 android:layout_height=”match_parent”
11 />
12
13 </LinearLayout>


View Code

 

现在回到MainActivity中,下面这个FragmentViewPagerAdapter类是关键,是我自己编写的用于绑定和处理fragments和ViewPager之间的逻辑关系


FragmentViewPagerAdapter adapter = new FragmentViewPagerAdapter(this.getSupportFragmentManager(), viewPager,fragments);

 

现在看下FragmentViewPagerAdapter:



  1 package com.wangjie.fragmentviewpagertest;
2
3 import android.support.v4.app.Fragment;
4 import android.support.v4.app.FragmentManager;
5 import android.support.v4.app.FragmentTransaction;
6 import android.support.v4.view.PagerAdapter;
7 import android.support.v4.view.ViewPager;
8 import android.view.View;
9 import android.view.ViewGroup;
10
11 import java.util.List;
12
13 /
14 为ViewPager添加布局(Fragment),绑定和处理fragments和viewpager之间的逻辑关系
15
16 Created with IntelliJ IDEA.
17 Author: wangjie email:tiantian.china.2@gmail.com
18 Date: 13-10-11
19 Time: 下午3:03
20 */
21 public class FragmentViewPagerAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener{
22 private List<Fragment> fragments; // 每个Fragment对应一个Page
23 private FragmentManager fragmentManager;
24 private ViewPager viewPager; // viewPager对象
25 private int currentPageIndex = 0; // 当前page索引(切换之前)
26
27 private OnExtraPageChangeListener onExtraPageChangeListener; // ViewPager切换页面时的额外功能添加接口
28
29 public FragmentViewPagerAdapter(FragmentManager fragmentManager, ViewPager viewPager , List<Fragment> fragments) {
30 this.fragments = fragments;
31 this.fragmentManager = fragmentManager;
32 this.viewPager = viewPager;
33 this.viewPager.setAdapter(this);
34 this.viewPager.setOnPageChangeListener(this);
35 }
36
37 @Override
38 public int getCount() {
39 return fragments.size();
40 }
41
42 @Override
43 public boolean isViewFromObject(View view, Object o) {
44 return view == o;
45 }
46
47 @Override
48 public void destroyItem(ViewGroup container, int position, Object object) {
49 container.removeView(fragments.get(position).getView()); // 移出viewpager两边之外的page布局
50 }
51
52 @Override
53 public Object instantiateItem(ViewGroup container, int position) {
54 Fragment fragment = fragments.get(position);
55 if(!fragment.isAdded()){ // 如果fragment还没有added
56 FragmentTransaction ft = fragmentManager.beginTransaction();
57 ft.add(fragment, fragment.getClass().getSimpleName());
58 ft.commit();
59 /
60 在用FragmentTransaction.commit()方法提交FragmentTransaction对象后
61 会在进程的主线程中,用异步的方式来执行。
62 如果想要立即执行这个等待中的操作,就要调用这个方法(只能在主线程中调用)。
63 要注意的是,所有的回调和相关的行为都会在这个调用中被执行完成,因此要仔细确认这个方法的调用位置。
64 /
65 fragmentManager.executePendingTransactions();
66 }
67
68 if(fragment.getView().getParent() == null){
69 container.addView(fragment.getView()); // 为viewpager增加布局
70 }
71
72 return fragment.getView();
73 }
74
75 /**
76 当前page索引(切换之前)
77 @return
78 /
79 public int getCurrentPageIndex() {
80 return currentPageIndex;
81 }
82
83 public OnExtraPageChangeListener getOnExtraPageChangeListener() {
84 return onExtraPageChangeListener;
85 }
86
87 /
88 设置页面切换额外功能监听器
89 @param onExtraPageChangeListener
90 */
91 public void setOnExtraPageChangeListener(OnExtraPageChangeListener onExtraPageChangeListener) {
92 this.onExtraPageChangeListener = onExtraPageChangeListener;
93 }
94
95 @Override
96 public void onPageScrolled(int i, float v, int i2) {
97 if(null != onExtraPageChangeListener){ // 如果设置了额外功能接口
98 onExtraPageChangeListener.onExtraPageScrolled(i, v, i2);
99 }
100 }
101
102 @Override
103 public void onPageSelected(int i) {
104 fragments.get(currentPageIndex).onPause(); // 调用切换前Fargment的onPause()
105 // fragments.get(currentPageIndex).onStop(); // 调用切换前Fargment的onStop()
106 if(fragments.get(i).isAdded()){
107 // fragments.get(i).onStart(); // 调用切换后Fargment的onStart()
108 fragments.get(i).onResume(); // 调用切换后Fargment的onResume()
109 }
110 currentPageIndex = i;
111
112 if(null != onExtraPageChangeListener){ // 如果设置了额外功能接口
113 onExtraPageChangeListener.onExtraPageSelected(i);
114 }
115
116 }
117
118 @Override
119 public void onPageScrollStateChanged(int i) {
120 if(null != onExtraPageChangeListener){ // 如果设置了额外功能接口
121 onExtraPageChangeListener.onExtraPageScrollStateChanged(i);
122 }
123 }
124
125
126 /
127 page切换额外功能接口
128 /
129 static class OnExtraPageChangeListener{
130 public void onExtraPageScrolled(int i, float v, int i2){}
131 public void onExtraPageSelected(int i){}
132 public void onExtraPageScrollStateChanged(int i){}
133 }
134
135
136 }


View Code

这里解决Fragment切换重新加载布局的办法,用的是把几个Fragment全部Add,然后根据要显示的哪个Fragment就把哪个Fragment的View给添加到“ViewGroup container”上去。

效果输出:

// 以下打开程序后,加载PageA和PageB

10-12 09:42:46.671: INFO/System.out(27248): AAAAAAAAAAonAttach
10-12 09:42:46.671: INFO/System.out(27248): AAAAAAAAAA
onCreate
10-12 09:42:46.671: INFO/System.out(27248): AAAAAAAAAAonCreateView
10-12 09:42:46.761: INFO/System.out(27248): AAAAAAAAAA
onActivityCreated
10-12 09:42:46.765: INFO/System.out(27248): AAAAAAAAAAonStart
10-12 09:42:46.765: INFO/System.out(27248): AAAAAAAAAA
onResume
10-12 09:42:46.847: INFO/System.out(27248): BBBBBBBBBBBonAttach
10-12 09:42:46.847: INFO/System.out(27248): BBBBBBBBBBB
onCreate
10-12 09:42:46.851: INFO/System.out(27248): BBBBBBBBBBBonCreateView
10-12 09:42:46.867: INFO/System.out(27248): BBBBBBBBBBB
onActivityCreated
10-12 09:42:46.867: INFO/System.out(27248): BBBBBBBBBBBonStart
10-12 09:42:46.867: INFO/System.out(27248): BBBBBBBBBBB
onResume

// 以下切换到PageB

10-12 09:42:57.285: INFO/System.out(27248): AAAAAAAAAAonPause    // 切换到PageB前会调用PageA的onPause()方法
10-12 09:42:57.285: INFO/System.out(27248): BBBBBBBBBBB
onResume  // 切换到PageB后会调用PageB的onResume()方法
10-12 09:42:57.285: INFO/System.out(27248): Extra…i: 1            // 切换页面时会调用切换额外功能接口(用户可以自己写需要的逻辑)
10-12 09:42:57.582: INFO/System.out(27248): CCCCCCCCCConAttach    // 切换到PageB后会加载PageC
10-12 09:42:57.586: INFO/System.out(27248): CCCCCCCCCC
onCreate
10-12 09:42:57.586: INFO/System.out(27248): CCCCCCCCCConCreateView
10-12 09:42:57.675: INFO/System.out(27248): CCCCCCCCCC
onActivityCreated
10-12 09:42:57.675: INFO/System.out(27248): CCCCCCCCCConStart
10-12 09:42:57.675: INFO/System.out(27248): CCCCCCCCCC
onResume

// 以下切换到PageC

10-12 09:43:18.261: INFO/System.out(27248): BBBBBBBBBBBonPause     // 切换到PageC前会调用PageB的onPause()方法
10-12 09:43:18.261: INFO/System.out(27248): CCCCCCCCCC
onResume    // 切换到PageC后会调用PageC的onResume()方法
10-12 09:43:18.261: INFO/System.out(27248): Extra…i: 2              // 切换页面时会调用切换额外功能接口(用户可以自己写需要的逻辑)
10-12 09:43:18.726: INFO/System.out(27248): DDDDDDDDDonAttach      // 切换到PageC后会加载PageD
10-12 09:43:18.726: INFO/System.out(27248): DDDDDDDDD
onCreate
10-12 09:43:18.726: INFO/System.out(27248): DDDDDDDDDonCreateView
10-12 09:43:18.738: INFO/System.out(27248): DDDDDDDDD
onActivityCreated
10-12 09:43:18.738: INFO/System.out(27248): DDDDDDDDDonStart
10-12 09:43:18.742: INFO/System.out(27248): DDDDDDDDD
onResume

// 以下切换到PageB
10-12 09:43:20.742: INFO/System.out(27248): CCCCCCCCCConPause      // 切换到PageB前会调用PageC的onPause()方法
10-12 09:43:20.742: INFO/System.out(27248): BBBBBBBBBBB
onResume    // 切换到PageB后会调用PageB的onResume()方法
10-12 09:43:20.746: INFO/System.out(27248): Extra…i: 1              // 切换页面时会调用切换额外功能接口(用户可以自己写需要的逻辑)

 

好了,到此为止,我们已经用Fragment实现了ViewPager的功能了,同样,下面来看下各个Fragment之间的通信

现在的情况是TabAFm中有个EditText,TabBFm中有个Button,MainActivity中有个变量“hello”

要做的是,切换到A,输入“I’m PageA”,切换到B,点击Button后,Toast显示“hello I’m PageA”

MainActivity中没什么好说的,就一个hello变量:


public String hello = “hello “;

TabBFm中:



 1 @Override
2 public void onActivityCreated(Bundle savedInstanceState) {
3 super.onActivityCreated(savedInstanceState);
4 System.out.println(“BBBBBBBBBBB____onActivityCreated”);
5 this.getView().findViewById(R.id.clickme).setOnClickListener(new View.OnClickListener() {
6 @Override
7 public void onClick(View view) {
8 // 获得绑定的FragmentActivity
9 MainActivity activity = ((MainActivity)getActivity());
10 // 获得TabAFm的控件
11 EditText editText = (EditText) activity.fragments.get(0).getView().findViewById(R.id.edit);
12
13 Toast.makeText(activity, activity.hello + editText.getText(), Toast.LENGTH_SHORT).show();
14 }
15 });
16 }


View Code

 

最终效果图:

 

demo下载:http://pan.baidu.com/s/1stGQ7



来源博客:Wang Jie's Blog's Blog
本文链接:https://blog.wangjiegulu.com/2013/10/12/Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信/
版权声明:本博客所有文章除特别声明外,均采用 CC BY 4.0 CN协议 许可协议。转载请注明出处。