├── .classpath ├── .gitattributes ├── .gitignore ├── .idea └── gradle.xml ├── .project ├── .settings └── org.eclipse.jdt.core.prefs ├── README.md ├── app ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ ├── com │ │ └── viewpagerindicator │ │ │ ├── CirclePageIndicator.java │ │ │ └── PageIndicator.java │ └── me │ │ └── li2 │ │ └── update_replace_fragment_in_viewpager │ │ ├── ContainerFragment.java │ │ ├── MainActivity.java │ │ ├── Page0Fragment.java │ │ ├── Page1Fragment.java │ │ ├── Page2Fragment.java │ │ ├── Page3Fragment.java │ │ └── SimpleBackPage.java │ └── res │ ├── drawable-hdpi │ └── ic_launcher.png │ ├── drawable-mdpi │ └── ic_launcher.png │ ├── drawable-xhdpi │ └── ic_launcher.png │ ├── drawable-xxhdpi │ └── ic_launcher.png │ ├── layout │ ├── activity_main.xml │ ├── fragment_container.xml │ ├── fragment_page0.xml │ ├── fragment_page1.xml │ ├── fragment_page2.xml │ └── fragment_page3.xml │ ├── values-v11 │ └── styles.xml │ ├── values-v14 │ └── styles.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── ids.xml │ ├── strings.xml │ ├── styles.xml │ ├── vpi__attrs.xml │ └── vpi__defaults.xml ├── build.gradle ├── build ├── generated │ └── mockable-android-22.jar └── intermediates │ └── dex-cache │ └── cache.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── import-summary.txt ├── settings.gradle ├── update_fragment_in_viewpager_demo.gif ├── update_fragment_in_viewpager_log.gif ├── 图11-3FragmentStatePagerAdapter的fragment管理-方法调用.png └── 图11-4-FragmentPagerAdapter的fragment管理-方法调用.png /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | /*/build/ 3 | 4 | # Crashlytics configuations 5 | com_crashlytics_export_strings.xml 6 | 7 | # Local configuration file (sdk path, etc) 8 | local.properties 9 | 10 | # Gradle generated files 11 | .gradle/ 12 | 13 | # Signing files 14 | .signing/ 15 | 16 | # User-specific configurations 17 | .idea/libraries/ 18 | .idea/workspace.xml 19 | .idea/tasks.xml 20 | .idea/.name 21 | .idea/compiler.xml 22 | .idea/copyright/profiles_settings.xml 23 | .idea/encodings.xml 24 | .idea/misc.xml 25 | .idea/modules.xml 26 | .idea/scopes/scope_settings.xml 27 | .idea/vcs.xml 28 | *.iml 29 | 30 | # OS-specific files 31 | .DS_Store 32 | .DS_Store? 33 | ._* 34 | .Spotlight-V100 35 | .Trashes 36 | ehthumbs.db 37 | Thumbs.db 38 | 39 | # Windows image file caches 40 | Thumbs.db 41 | ehthumbs.db 42 | 43 | # Folder config file 44 | Desktop.ini 45 | 46 | # Recycle Bin used on file shares 47 | $RECYCLE.BIN/ 48 | 49 | # Windows Installer files 50 | *.cab 51 | *.msi 52 | *.msm 53 | *.msp 54 | 55 | # Windows shortcuts 56 | *.lnk 57 | 58 | # ========================= 59 | # Operating System Files 60 | # ========================= 61 | 62 | # OSX 63 | # ========================= 64 | 65 | .DS_Store 66 | .AppleDouble 67 | .LSOverride 68 | 69 | # Thumbnails 70 | ._* 71 | 72 | # Files that might appear on external disk 73 | .Spotlight-V100 74 | .Trashes 75 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24 | 25 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | UpdateReplaceFragmentInViewPager 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 3 | org.eclipse.jdt.core.compiler.compliance=1.6 4 | org.eclipse.jdt.core.compiler.source=1.6 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # How to update and replace fragment in viewpager? 2 | 3 | ## ListView的工作原理 4 | 5 | 在了解ViewPager的工作原理之前,先回顾ListView的工作原理: 6 | 7 | > 1. ListView只有在需要显示某些列表项时,它才会去申请可用的视图对象;如果为所有的列表项数据创建视图对象,会浪费内存; 8 | > 2. ListView找谁去申请视图对象呢? 答案是adapter。**adapter是一个控制器对象,负责从模型层获取数据,创建并填充必要的视图对象,将准备好的视图对象返回给ListView**; 9 | > 3. 首先,通过调用adapter的getCount()方法,ListView询问数组列表中包含多少个对象(为避免出现数组越界的错误);紧接着ListView就调用adapter的getView(int, View, ViewGroup)方法。 10 | 11 | ViewPager某种程度上类似于ListView,区别在于:ListView通过`ArrayAdapter.getView(int position, View convertView, ViewGroup parent)`填充视图;ViewPager通过`FragmentPagerAdapter.getItem(int position)`生成指定位置的fragment. 12 | 13 | 而我们需要关注的是: 14 | 15 | 16 | ## ViewPager和它的adapter是如何配合工作的? 17 | 18 | **声明:本文内容针对android.support.v4.app.*** 19 | ViewPager有两个adapter:FragmentPagerAdapter和FragmentStatePagerAdapter: 20 | - [android.support.v4.app.FragmentPagerAdapter](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/support/v4/app/FragmentPagerAdapter.java#FragmentPagerAdapter) 21 | > 继承自android.support.v4.view.PagerAdapter,每页都是一个Fragment,并且所有的Fragment实例一直保存在Fragment manager中。所以它适用于少量固定的fragment,比如一组用于分页显示的标签。除了当Fragment不可见时,它的视图层(view hierarchy)有可能被销毁外,每页的Fragment都会被保存在内存中。(翻译自代码文件的注释部分) 22 | - [android.support.v4.app.FragmentStatePagerAdapter](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/support/v4/app/FragmentStatePagerAdapter.java#FragmentStatePagerAdapter) 23 | > 继承自android.support.v4.view.PagerAdapter,每页都是一个Fragment,当Fragment不被需要时(比如不可见),整个Fragment都会被销毁,除了saved state被保存外(保存下来的bundle用于恢复Fragment实例)。所以它适用于很多页的情况。(翻译自代码文件的注释部分) 24 | 25 | 它俩的子类,需要实现`getItem(int)` 和 `android.support.v4.view.PagerAdapter.getCount()`. 26 | 27 | ### 先通过一段代码了解ViewPager和FragmentPagerAdapter的典型用法 28 | 29 | 稍后做详细分析: 30 | 31 | ```java 32 | // Set a PagerAdapter to supply views for this pager. 33 | ViewPager viewPager = (ViewPager) findViewById(R.id.my_viewpager_id); 34 | viewPager.setAdapter(mMyFragmentPagerAdapter); 35 | 36 | private FragmentPagerAdapter mMyFragmentPagerAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) { 37 | @Override 38 | public int getCount() { 39 | return 2; // Return the number of views available. 40 | } 41 | 42 | @Override 43 | public Fragment getItem(int position) { 44 | return new MyFragment(); // Return the Fragment associated with a specified position. 45 | } 46 | 47 | // Called when the host view is attempting to determine if an item's position has changed. 48 | @Override 49 | public int getItemPosition(Object object) { 50 | if (object instanceof MyFragment) { 51 | ((MyFragment)object).updateView(); 52 | } 53 | return super.getItemPosition(object); 54 | } 55 | }; 56 | 57 | private class MyFragment extends Fragment { 58 | @Override 59 | public void onCreate(Bundle savedInstanceState) { 60 | super.onCreate(savedInstanceState); 61 | // do something such as init data 62 | } 63 | 64 | @Override 65 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 66 | View view = inflater.inflate(R.layout.fragment_my, container, false); 67 | // init view in the fragment 68 | return view; 69 | } 70 | 71 | public void updateView() { 72 | // do something to update the fragment 73 | } 74 | } 75 | ``` 76 | 77 | FragmentPagerAdapter和FragmentStatePagerAdapter对Fragment的管理略有不同,在详细考察二者区别之前,我们通过两种较为直观的方式先感受下: 78 | 79 | ### 通过两张图片直观的对比FragmentPagerAdapter和FragmentStatePagerAdapter的区别 80 | 81 | *说明:这两张图片来自于《Android权威编程指南》,原图有3个Fragment,我增加了1个Fragment,以及被调到的方法。* 82 | FragmentPagerAdapter的Fragment管理: 83 | 84 | ![image-11-4-FragmentPagerAdapter的fragment管理-方法调用](https://github.com/li2/Update_Replace_Fragment_In_ViewPager/blob/master/图11-4-FragmentPagerAdapter的fragment管理-方法调用.png) 85 | 86 | 87 | FragmentStatePageAdapter的Fragment管理: 88 | ![image-11-3FragmentStatePagerAdapter的fragment管理-方法调用](https://github.com/li2/Update_Replace_Fragment_In_ViewPager/blob/master/图11-3FragmentStatePagerAdapter的fragment管理-方法调用.png) 89 | 90 | 91 | ### 详细分析 adapter method和fragment lifecycle method 的调用情况 92 | 93 | 好啦,感受完毕,我们需要探究其详情,梳理adapter创建、销毁Fragment的过程,过程中adapter method和fragment lifecycle method哪些被调到,有哪些一样,有哪些不一样。 94 | 95 | 最开始处于第0页时,adapter不仅为第0页创建Fragment实例,还为相邻的第1页创建了Fragment实例: 96 | 97 | ```java 98 | // 刚开始处在page0 99 | D/Adapter (25946): getItem(0) 100 | D/Fragment0(25946): newInstance(2015-09-10) // 注释:newInstance()调用了Fragment的构造器方法,下同。 101 | D/Adapter (25946): getItem(1) 102 | D/Fragment1(25946): newInstance(Hello World, I'm li2.) 103 | D/Fragment0(25946): onAttach() 104 | D/Fragment0(25946): onCreate() 105 | D/Fragment0(25946): onCreateView() 106 | D/Fragment1(25946): onAttach() 107 | D/Fragment1(25946): onCreate() 108 | D/Fragment1(25946): onCreateView() 109 | ``` 110 | 第1次从第0页滑到第1页,adapter同样会为相邻的第2页创建Fragment实例; 111 | 112 | ```java 113 | // 第1次滑到page1 114 | D/Adapter (25946): onPageSelected(1) 115 | D/Adapter (25946): getItem(2) 116 | D/Fragment2(25946): newInstance(true) 117 | D/Fragment2(25946): onAttach() 118 | D/Fragment2(25946): onCreate() 119 | D/Fragment2(25946): onCreateView() 120 | ``` 121 | 122 | > FragmentPagerAdapter和FragmentStatePagerAdapter齐声说:呐,请主公贰放心,属下定会为您准备好相邻的下一页视图哒!么么哒! 123 | 它俩对待下一页的态度是相同的,但对于上上页,它俩做出了不一样的事情: 124 | > FragmentPagerAdapter说:**上上页的实例还保留着,只是销毁了它的视图**: 125 | 126 | ```java 127 | // 第N次(N不等于1)向右滑动选中page2 128 | D/Adapter (25946): onPageSelected(2) 129 | D/Adapter (25946): destroyItem(0) // 销毁page0的视图 130 | D/Fragment0(25946): onDestroyView() 131 | D/Fragment3(25946): onCreateView() // page3的Fragment实例仍保存在FragmentManager中,所以只需创建它的视图 132 | ``` 133 | > FragmentStatePagerAdapter说:**上上页的实例和视图都被俺销毁啦**: 134 | 135 | ```java 136 | // 第N次(N不等于1)向右滑选中page2 137 | D/Adapter (27880): onPageSelected(2) 138 | D/Adapter (27880): destroyItem(0) // 销毁page0的实例和视图 139 | D/Adapter (27880): getItem(3) // 创建page3的Fragment 140 | D/Fragment3(27880): newInstance() 141 | D/Fragment0(27880): onDestroyView() 142 | D/Fragment0(27880): onDestroy() 143 | D/Fragment0(27880): onDetach() 144 | D/Fragment3(27880): onAttach() 145 | D/Fragment3(27880): onCreate() 146 | D/Fragment3(27880): onCreateView() 147 | ``` 148 | 149 | ### Fragment getItem(int position) 150 | 151 | ```java 152 | // Return the Fragment associated with a specified position. 153 | public abstract Fragment getItem(int position); 154 | ``` 155 | 当adapter需要一个指定位置的Fragment,并且这个Fragment不存在时,getItem就被调到,返回一个Fragment实例给adapter。 156 | 所以,有必要再次强调,**getItem是创建一个新的Fragment,但是这个方法名可能会被误认为是返回一个已经存在的Fragment**。 157 | 对于FragmentPagerAdapter,当每页的Fragment被创建后,这个函数就不会被调到了。对于FragmentStatePagerAdapter,由于Fragment会被销毁,所以它仍会被调到。 158 | 由于我们必须在getItem中实例化一个Fragment,所以当getItem()被调用后,Fragment相应的生命周期函数也就被调到了: 159 | 160 | ```java 161 | D/Adapter (25946): getItem(1) 162 | D/Fragment1(25946): newInstance(Hello World, I'm li2.) // newInstance()调用了Fragment的构造器方法; 163 | D/Fragment1(25946): onAttach() 164 | D/Fragment1(25946): onCreate() 165 | D/Fragment1(25946): onCreateView() 166 | ``` 167 | 168 | ### void destroyItem(ViewGroup container, int position, Object object) 169 | 170 | ```java 171 | // Remove a page for the given position. 172 | public void FragmentPagerAdapter.destroyItem(ViewGroup container, int position, Object object) { 173 | mCurTransaction.detach((Fragment)object); 174 | } 175 | 176 | public void FragmentStatePagerAdapter.destroyItem(ViewGroup container, int position, Object object) { 177 | mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment)); 178 | mFragments.set(position, null); 179 | mCurTransaction.remove(fragment); 180 | } 181 | ``` 182 | 销毁指定位置的Fragment。从源码中可以看出二者的区别,一个detach,一个remove,这将调用到不同的Fragment生命周期函数: 183 | 184 | ```java 185 | // 对于FragmentPagerAdapter 186 | D/Adapter (25946): onPageSelected(2) 187 | D/Adapter (25946): destroyItem(0) 188 | D/Fragment0(25946): onDestroyView() // 销毁视图 189 | 190 | // 对于FragmentStatePagerAdapter 191 | D/Adapter (27880): onPageSelected(2) 192 | D/Adapter (27880): destroyItem(0) 193 | D/Fragment0(27880): onDestroyView() // 销毁视图 194 | D/Fragment0(27880): onDestroy() // 销毁实例 195 | D/Fragment0(27880): onDetach() 196 | ``` 197 | ### FragmentPagerAdapter和FragmentStatePagerAdapter对比总结 198 | > 二者使用方法基本相同,唯一的区别就在卸载不再需要的fragment时,采用的处理方式不同: 199 | > 200 | > - 使用FragmentStatePagerAdapter会**销毁掉不需要的fragment**。事务提交后,可将fragment从activity的FragmentManager中彻底移除。类名中的“state”表明:在销毁fragment时,它会将其onSaveInstanceState(Bundle) 方法中的Bundle信息保存下来。用户切换回原来的页面后,保存的实例状态可用于恢复生成新的fragment. 201 | > - FragmentPagerAdapter的做法大不相同。对于不再需要的fragment,FragmentPagerAdapter则选择调用事务的detach(Fragment) 方法,而非remove(Fragment)方法来处理它。也就是说,FragmentPagerAdapter**只是销毁了fragment的视图**,但仍将fragment实例保留在FragmentManager中。因此, FragmentPagerAdapter创建的fragment永远不会被销毁。 202 | > 203 | > (摘抄自《Android权威编程指南11.1.4》) 204 | 205 | ### 更新ViewPager中的Fragment 206 | 调用`notifyDataSetChanged()`时,2个adapter的方法的调用情况相同,**当前页和相邻的两页的getItemPosition都会被调用到**。 207 | 208 | ```java 209 | // Called when the host view is attempting to determine if an item's position has changed. Returns POSITION_UNCHANGED if the position of the given item has not changed or POSITION_NONE if the item is no longer present in the adapter. 210 | public int getItemPosition(Object object) { 211 | return POSITION_UNCHANGED; 212 | } 213 | ``` 214 | 215 | [从网上找到的解决办法是](http://stackoverflow.com/questions/18088076/update-fragment-from-viewpager/),覆写getItemPosition使其返POSITION_NONE,以触发Fragment的销毁和重建。可是这将导致Fragment频繁的销毁和重建,并不是最佳的方法。 216 | 后来我把注意力放在了入口参数`object`上,"representing an item", 实际上就是Fragment,只需要为Fragment提供一个更新view的public方法: 217 | 218 | ``` 219 | @Override 220 | // To update fragment in ViewPager, we should override getItemPosition() method, 221 | // in this method, we call the fragment's public updating method. 222 | public int getItemPosition(Object object) { 223 | Log.d(TAG, "getItemPosition(" + object.getClass().getSimpleName() + ")"); 224 | if (object instanceof Page0Fragment) { 225 | ((Page0Fragment) object).updateDate(mDate); 226 | } else if (object instanceof Page1Fragment) { 227 | ((Page1Fragment) object).updateContent(mContent); 228 | } else if (object instanceof Page2Fragment) { 229 | ((Page2Fragment) object).updateCheckedStatus(mChecked); 230 | } else if (...) { 231 | } 232 | return super.getItemPosition(object); 233 | }; 234 | 235 | // 更新界面时方法的调用情况 236 | // 当前页为0时 237 | D/Adapter (21517): notifyDataSetChanged(+0) 238 | D/Adapter (21517): getItemPosition(Page0Fragment) 239 | D/Fragment0(21517): updateDate(2015-09-12) 240 | D/Adapter (21517): getItemPosition(Page1Fragment) 241 | D/Fragment1(21517): updateContent(Hello World, I am li2.) 242 | 243 | // 当前页为1时 244 | D/Adapter (21517): notifyDataSetChanged(+1) 245 | D/Adapter (21517): getItemPosition(Page0Fragment) 246 | D/Fragment0(21517): updateDate(2015-09-13) 247 | D/Adapter (21517): getItemPosition(Page1Fragment) 248 | D/Fragment1(21517): updateContent(Hello World, I am li2.) 249 | D/Adapter (21517): getItemPosition(Page2Fragment) 250 | D/Fragment2(21517): updateCheckedStatus(true) 251 | ``` 252 | 253 | **在最开始调用notifyDataSetChanged试图更新Fragment时,我是这样做的:用arraylist保存所有的Fragment,当需要更新时,就从arraylist中取出Fragment,然后调用该Fragment的update方法。这种做法非常鱼唇,当时完全不懂得adapter的Fragment manager在替我管理所有的Fragment**。而我只需要: 254 | 255 | - 覆写getCount告诉adapter有几个Fragment; 256 | - 覆写getItem以实例化一个指定位置的Fragment返回给adapter; 257 | - 覆写getItemPosition,把入口参数强制转型成自定义的Fragment,然后调用该Fragment的update方法以完成更新。 258 | 259 | **只需要覆写这几个adapter的方法,adapter会为你完成所有的管理工作,不需要自己保存、维护Fragment**。 260 | 261 | ### 替换ViewPager中的Fragment 262 | 应用场景可能是这样,比如有一组按钮,Day/Month/Year,有一个包含几个Fragment的ViewPager。点击不同的按钮,需要秀出不同的Fragment。 263 | 具体怎么实现,请参考下面的代码: 264 | [github.com/li2/Update_Replace_Fragment_In_ViewPager/ContainerFragment.java](https://github.com/li2/Update_Replace_Fragment_In_ViewPager/blob/master/src/me/li2/update_replace_fragment_in_viewpager/ContainerFragment.java) 265 | 266 | ### 一些误区 267 | `ViewPager.getChildCount()` 返回的是当前ViewPager所管理的没有被销毁视图的Fragment,并不是所有的Fragment。想要获取所有的Fragment数量,应该调用`ViewPager.getAdapter().getCount()`. 268 | 269 | ### 一个Demo 270 | 为了总结ViewPager的用法,以及写这篇笔记,我写了一个demo,[你可以从这里获取它的源码 github.com/li2/](https://github.com/li2/Update_Replace_Fragment_In_ViewPager) 271 | 272 | 这一张gif图片,演示了一个包含4个Fragment的ViewPager,通过上面的date+-1 button、EditText、Checkbox来更新前3个Fragment的界面;最后一个Fragment嵌套着2个Fragment,通过ToggleButton来切换。 273 | 274 | ![image-update_fragment_in_viewpager_demo](https://github.com/li2/Update_Replace_Fragment_In_ViewPager/blob/master/update_fragment_in_viewpager_demo.gif) 275 | 276 | 277 | 这一张gif演示了切换ViewPager页以及更新Fragment时,相关的方法调用。通过一个ScrollView和TextView展示出来。 278 | 279 | ![image-update_fragment_in_viewpager_withlog](https://github.com/li2/Update_Replace_Fragment_In_ViewPager/blob/master/update_fragment_in_viewpager_log.gif) 280 | 281 | 282 | ## 参考 283 | - [为什么调用 FragmentPagerAdapter.notifyDataSetChanged() 并不能更新其 Fragment? - Dancefire](http://www.cnblogs.com/dancefire/archive/2013/01/02/why-notifydatasetchanged-does-not-work.html) 284 | **这篇博文详细地解释了notifyDataSetChanged不能更新Fragment的原因,非常好。** 285 | 286 | - [android - Update Fragment from ViewPager - Stack Overflow](http://stackoverflow.com/a/18088509/2722270) 287 | **这个stackoverflow问答给出了两种更新Fragment的方法,非常好。** 288 | 289 | - [HowTo: ListView, Adapter, getView and different list items’ layouts in one ListView | Android Tales](http://android.amberfog.com/?p=296) 290 | **这篇博文详细地解释了ListView和它的Adapter是如何配合工作的,以及实现不同的listitem layout. 非常好。** 291 | 292 | - [android - R etrieve a fragment from ViewPager - Stack Overflow](http://stackoverflow.com/questions/8785221/retrieve-a-fragment-from-a-viewpager) 293 | 这个statckoverflow问答讨论怎样从ViewPager中获取一个Fragment,但我目前还不知道拿到Fragment要做什么。 294 | 295 | - [android Fragments详解四:管理fragment - nkmnkm的csdn博客](http://blog.csdn.net/niu_gao/article/details/7172483) 296 | 这是一篇翻译文章。 297 | 298 | - 这些博文、问答的思路类似,讨论Fragment的tag,通过一个list 存储所有Fragment的tag,然后再adapter里通过fm.findFragmentByTag获取Fragment,然后调用Fragment的update方法更新; 299 | 或者是通过一个list自己来管理所有的Fragment: 300 | [ViewPager Fragment 数据更新问题 - shadow066的csnd专栏](http://blog.csdn.net/shadow066/article/details/17298675) 301 | [关于ViewPager的数据更新问题小结 - leo8573的csdn专栏](http://blog.csdn.net/leo8573/article/details/7893841) 302 | [Viewpager+fragment数据更新问题解析 | 姜糖水](http://www.cnphp6.com/archives/61068) 303 | [android - How to get existing fragments when using FragmentPagerAdapter - Stack Overflow](http://stackoverflow.com/questions/14035090/how-to-get-existing-fragments-when-using-fragmentpageradapter) 304 | [android - Retrieve a Fragment from a ViewPager - Stack Overflow](http://stackoverflow.com/questions/8785221/retrieve-a-fragment-from-a-viewpager) 305 | [android - support FragmentPagerAdapter holds reference to old fragments - Stack Overflow]( 306 | http://stackoverflow.com/questions/9727173/support-fragmentpageradapter-holds-reference-to-old-fragments/9745935#9745935) 307 | **其中,这个问题的答案解释的特别好:However, the ones that are added to the fragment manager now are NOT the ones you have in your fragments list in your Activity. 企图这样更新界面是行不通的:`pagerAdapter.getItem(1)).update(id, name)`** 308 | 309 | - [android - Display fragment viewpager within a fragment - Stack Overflow](http://stackoverflow.com/questions/7700226/display-fragment-viewpager-within-a-fragment) 310 | Fragment里有一个ViewPager,ViewPager里有多个Fragment. 311 | 312 | - 这些是**Android Fragment相关的源码文件**: 313 | [Android源码仓库](http://grepcode.com/project/repository.grepcode.com/java/ext/com.google.android/android/) 314 | [android.support.v4.app.Fragment](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/support/v4/app/Fragment.java) 315 | [android.support.v4.view.PagerAdapter](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/support/v4/view/PagerAdapter.java) 316 | [android.support.v4.app.FragmentPagerAdapter](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/support/v4/app/FragmentPagerAdapter.java) 317 | [android.support.v4.app.FragmentStatePagerAdapter](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/support/v4/app/FragmentStatePagerAdapter.java) 318 | 319 | ## 关于作者 320 | 321 | Copyright (C) 2015 WeiYi Li (li21) weiyi.just2@gmail.com li2.me 322 | **特别声明:禁止转载** -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | applicationId "me.li2.update_replace_fragment_in_viewpager" 9 | minSdkVersion 14 10 | targetSdkVersion 21 11 | } 12 | 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile 'com.android.support:support-v4:22.2.1' 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/viewpagerindicator/CirclePageIndicator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Patrik Akerfeldt 3 | * Copyright (C) 2011 Jake Wharton 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.viewpagerindicator; 18 | 19 | import static android.graphics.Paint.ANTI_ALIAS_FLAG; 20 | import static android.widget.LinearLayout.HORIZONTAL; 21 | import static android.widget.LinearLayout.VERTICAL; 22 | import me.li2.update_replace_fragment_in_viewpager.R; 23 | import android.content.Context; 24 | import android.content.res.Resources; 25 | import android.content.res.TypedArray; 26 | import android.graphics.Canvas; 27 | import android.graphics.Paint; 28 | import android.graphics.Paint.Style; 29 | import android.graphics.drawable.Drawable; 30 | import android.os.Parcel; 31 | import android.os.Parcelable; 32 | import android.support.v4.view.MotionEventCompat; 33 | import android.support.v4.view.ViewConfigurationCompat; 34 | import android.support.v4.view.ViewPager; 35 | import android.util.AttributeSet; 36 | import android.view.MotionEvent; 37 | import android.view.View; 38 | import android.view.ViewConfiguration; 39 | 40 | /** 41 | * Draws circles (one for each view). The current view position is filled and 42 | * others are only stroked. 43 | */ 44 | public class CirclePageIndicator extends View implements PageIndicator { 45 | private static final int INVALID_POINTER = -1; 46 | 47 | private float mRadius; 48 | private final Paint mPaintPageFill = new Paint(ANTI_ALIAS_FLAG); 49 | private final Paint mPaintStroke = new Paint(ANTI_ALIAS_FLAG); 50 | private final Paint mPaintFill = new Paint(ANTI_ALIAS_FLAG); 51 | private ViewPager mViewPager; 52 | private ViewPager.OnPageChangeListener mListener; 53 | private int mCurrentPage; 54 | private int mSnapPage; 55 | private float mPageOffset; 56 | private int mScrollState; 57 | private int mOrientation; 58 | private boolean mCentered; 59 | private boolean mSnap; 60 | 61 | private int mTouchSlop; 62 | private float mLastMotionX = -1; 63 | private int mActivePointerId = INVALID_POINTER; 64 | private boolean mIsDragging; 65 | 66 | 67 | public CirclePageIndicator(Context context) { 68 | this(context, null); 69 | } 70 | 71 | public CirclePageIndicator(Context context, AttributeSet attrs) { 72 | this(context, attrs, R.attr.vpiCirclePageIndicatorStyle); 73 | } 74 | 75 | public CirclePageIndicator(Context context, AttributeSet attrs, int defStyle) { 76 | super(context, attrs, defStyle); 77 | if (isInEditMode()) return; 78 | 79 | //Load defaults from resources 80 | final Resources res = getResources(); 81 | final int defaultPageColor = res.getColor(R.color.default_circle_indicator_page_color); 82 | final int defaultFillColor = res.getColor(R.color.default_circle_indicator_fill_color); 83 | final int defaultOrientation = res.getInteger(R.integer.default_circle_indicator_orientation); 84 | final int defaultStrokeColor = res.getColor(R.color.default_circle_indicator_stroke_color); 85 | final float defaultStrokeWidth = res.getDimension(R.dimen.default_circle_indicator_stroke_width); 86 | final float defaultRadius = res.getDimension(R.dimen.default_circle_indicator_radius); 87 | final boolean defaultCentered = res.getBoolean(R.bool.default_circle_indicator_centered); 88 | final boolean defaultSnap = res.getBoolean(R.bool.default_circle_indicator_snap); 89 | 90 | //Retrieve styles attributes 91 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CirclePageIndicator, defStyle, 0); 92 | 93 | mCentered = a.getBoolean(R.styleable.CirclePageIndicator_centered, defaultCentered); 94 | mOrientation = a.getInt(R.styleable.CirclePageIndicator_android_orientation, defaultOrientation); 95 | mPaintPageFill.setStyle(Style.FILL); 96 | mPaintPageFill.setColor(a.getColor(R.styleable.CirclePageIndicator_pageColor, defaultPageColor)); 97 | mPaintStroke.setStyle(Style.STROKE); 98 | mPaintStroke.setColor(a.getColor(R.styleable.CirclePageIndicator_strokeColor, defaultStrokeColor)); 99 | mPaintStroke.setStrokeWidth(a.getDimension(R.styleable.CirclePageIndicator_strokeWidth, defaultStrokeWidth)); 100 | mPaintFill.setStyle(Style.FILL); 101 | mPaintFill.setColor(a.getColor(R.styleable.CirclePageIndicator_fillColor, defaultFillColor)); 102 | mRadius = a.getDimension(R.styleable.CirclePageIndicator_radius, defaultRadius); 103 | mSnap = a.getBoolean(R.styleable.CirclePageIndicator_snap, defaultSnap); 104 | 105 | Drawable background = a.getDrawable(R.styleable.CirclePageIndicator_android_background); 106 | if (background != null) { 107 | setBackgroundDrawable(background); 108 | } 109 | 110 | a.recycle(); 111 | 112 | final ViewConfiguration configuration = ViewConfiguration.get(context); 113 | mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); 114 | } 115 | 116 | 117 | public void setCentered(boolean centered) { 118 | mCentered = centered; 119 | invalidate(); 120 | } 121 | 122 | public boolean isCentered() { 123 | return mCentered; 124 | } 125 | 126 | public void setPageColor(int pageColor) { 127 | mPaintPageFill.setColor(pageColor); 128 | invalidate(); 129 | } 130 | 131 | public int getPageColor() { 132 | return mPaintPageFill.getColor(); 133 | } 134 | 135 | public void setFillColor(int fillColor) { 136 | mPaintFill.setColor(fillColor); 137 | invalidate(); 138 | } 139 | 140 | public int getFillColor() { 141 | return mPaintFill.getColor(); 142 | } 143 | 144 | public void setOrientation(int orientation) { 145 | switch (orientation) { 146 | case HORIZONTAL: 147 | case VERTICAL: 148 | mOrientation = orientation; 149 | requestLayout(); 150 | break; 151 | 152 | default: 153 | throw new IllegalArgumentException("Orientation must be either HORIZONTAL or VERTICAL."); 154 | } 155 | } 156 | 157 | public int getOrientation() { 158 | return mOrientation; 159 | } 160 | 161 | public void setStrokeColor(int strokeColor) { 162 | mPaintStroke.setColor(strokeColor); 163 | invalidate(); 164 | } 165 | 166 | public int getStrokeColor() { 167 | return mPaintStroke.getColor(); 168 | } 169 | 170 | public void setStrokeWidth(float strokeWidth) { 171 | mPaintStroke.setStrokeWidth(strokeWidth); 172 | invalidate(); 173 | } 174 | 175 | public float getStrokeWidth() { 176 | return mPaintStroke.getStrokeWidth(); 177 | } 178 | 179 | public void setRadius(float radius) { 180 | mRadius = radius; 181 | invalidate(); 182 | } 183 | 184 | public float getRadius() { 185 | return mRadius; 186 | } 187 | 188 | public void setSnap(boolean snap) { 189 | mSnap = snap; 190 | invalidate(); 191 | } 192 | 193 | public boolean isSnap() { 194 | return mSnap; 195 | } 196 | 197 | @Override 198 | protected void onDraw(Canvas canvas) { 199 | super.onDraw(canvas); 200 | 201 | if (mViewPager == null) { 202 | return; 203 | } 204 | final int count = mViewPager.getAdapter().getCount(); 205 | if (count == 0) { 206 | return; 207 | } 208 | 209 | if (mCurrentPage >= count) { 210 | setCurrentItem(count - 1); 211 | return; 212 | } 213 | 214 | int longSize; 215 | int longPaddingBefore; 216 | int longPaddingAfter; 217 | int shortPaddingBefore; 218 | if (mOrientation == HORIZONTAL) { 219 | longSize = getWidth(); 220 | longPaddingBefore = getPaddingLeft(); 221 | longPaddingAfter = getPaddingRight(); 222 | shortPaddingBefore = getPaddingTop(); 223 | } else { 224 | longSize = getHeight(); 225 | longPaddingBefore = getPaddingTop(); 226 | longPaddingAfter = getPaddingBottom(); 227 | shortPaddingBefore = getPaddingLeft(); 228 | } 229 | 230 | final float threeRadius = mRadius * 3; 231 | final float shortOffset = shortPaddingBefore + mRadius; 232 | float longOffset = longPaddingBefore + mRadius; 233 | if (mCentered) { 234 | longOffset += ((longSize - longPaddingBefore - longPaddingAfter) / 2.0f) - ((count * threeRadius) / 2.0f); 235 | } 236 | 237 | float dX; 238 | float dY; 239 | 240 | float pageFillRadius = mRadius; 241 | if (mPaintStroke.getStrokeWidth() > 0) { 242 | pageFillRadius -= mPaintStroke.getStrokeWidth() / 2.0f; 243 | } 244 | 245 | //Draw stroked circles 246 | for (int iLoop = 0; iLoop < count; iLoop++) { 247 | float drawLong = longOffset + (iLoop * threeRadius); 248 | if (mOrientation == HORIZONTAL) { 249 | dX = drawLong; 250 | dY = shortOffset; 251 | } else { 252 | dX = shortOffset; 253 | dY = drawLong; 254 | } 255 | // Only paint fill if not completely transparent 256 | if (mPaintPageFill.getAlpha() > 0) { 257 | canvas.drawCircle(dX, dY, pageFillRadius, mPaintPageFill); 258 | } 259 | 260 | // Only paint stroke if a stroke width was non-zero 261 | if (pageFillRadius != mRadius) { 262 | canvas.drawCircle(dX, dY, mRadius, mPaintStroke); 263 | } 264 | } 265 | 266 | //Draw the filled circle according to the current scroll 267 | float cx = (mSnap ? mSnapPage : mCurrentPage) * threeRadius; 268 | if (!mSnap) { 269 | cx += mPageOffset * threeRadius; 270 | } 271 | if (mOrientation == HORIZONTAL) { 272 | dX = longOffset + cx; 273 | dY = shortOffset; 274 | } else { 275 | dX = shortOffset; 276 | dY = longOffset + cx; 277 | } 278 | canvas.drawCircle(dX, dY, mRadius, mPaintFill); 279 | } 280 | 281 | public boolean onTouchEvent(android.view.MotionEvent ev) { 282 | if (super.onTouchEvent(ev)) { 283 | return true; 284 | } 285 | if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) { 286 | return false; 287 | } 288 | 289 | final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; 290 | switch (action) { 291 | case MotionEvent.ACTION_DOWN: 292 | mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 293 | mLastMotionX = ev.getX(); 294 | break; 295 | 296 | case MotionEvent.ACTION_MOVE: { 297 | final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); 298 | final float x = MotionEventCompat.getX(ev, activePointerIndex); 299 | final float deltaX = x - mLastMotionX; 300 | 301 | if (!mIsDragging) { 302 | if (Math.abs(deltaX) > mTouchSlop) { 303 | mIsDragging = true; 304 | } 305 | } 306 | 307 | if (mIsDragging) { 308 | mLastMotionX = x; 309 | if (mViewPager.isFakeDragging() || mViewPager.beginFakeDrag()) { 310 | mViewPager.fakeDragBy(deltaX); 311 | } 312 | } 313 | 314 | break; 315 | } 316 | 317 | case MotionEvent.ACTION_CANCEL: 318 | case MotionEvent.ACTION_UP: 319 | if (!mIsDragging) { 320 | final int count = mViewPager.getAdapter().getCount(); 321 | final int width = getWidth(); 322 | final float halfWidth = width / 2f; 323 | final float sixthWidth = width / 6f; 324 | 325 | if ((mCurrentPage > 0) && (ev.getX() < halfWidth - sixthWidth)) { 326 | if (action != MotionEvent.ACTION_CANCEL) { 327 | mViewPager.setCurrentItem(mCurrentPage - 1); 328 | } 329 | return true; 330 | } else if ((mCurrentPage < count - 1) && (ev.getX() > halfWidth + sixthWidth)) { 331 | if (action != MotionEvent.ACTION_CANCEL) { 332 | mViewPager.setCurrentItem(mCurrentPage + 1); 333 | } 334 | return true; 335 | } 336 | } 337 | 338 | mIsDragging = false; 339 | mActivePointerId = INVALID_POINTER; 340 | if (mViewPager.isFakeDragging()) mViewPager.endFakeDrag(); 341 | break; 342 | 343 | case MotionEventCompat.ACTION_POINTER_DOWN: { 344 | final int index = MotionEventCompat.getActionIndex(ev); 345 | mLastMotionX = MotionEventCompat.getX(ev, index); 346 | mActivePointerId = MotionEventCompat.getPointerId(ev, index); 347 | break; 348 | } 349 | 350 | case MotionEventCompat.ACTION_POINTER_UP: 351 | final int pointerIndex = MotionEventCompat.getActionIndex(ev); 352 | final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); 353 | if (pointerId == mActivePointerId) { 354 | final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 355 | mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); 356 | } 357 | mLastMotionX = MotionEventCompat.getX(ev, MotionEventCompat.findPointerIndex(ev, mActivePointerId)); 358 | break; 359 | } 360 | 361 | return true; 362 | } 363 | 364 | @Override 365 | public void setViewPager(ViewPager view) { 366 | if (mViewPager == view) { 367 | return; 368 | } 369 | if (mViewPager != null) { 370 | mViewPager.setOnPageChangeListener(null); 371 | } 372 | if (view.getAdapter() == null) { 373 | throw new IllegalStateException("ViewPager does not have adapter instance."); 374 | } 375 | mViewPager = view; 376 | mViewPager.setOnPageChangeListener(this); 377 | invalidate(); 378 | } 379 | 380 | @Override 381 | public void setViewPager(ViewPager view, int initialPosition) { 382 | setViewPager(view); 383 | setCurrentItem(initialPosition); 384 | } 385 | 386 | @Override 387 | public void setCurrentItem(int item) { 388 | if (mViewPager == null) { 389 | throw new IllegalStateException("ViewPager has not been bound."); 390 | } 391 | mViewPager.setCurrentItem(item); 392 | mCurrentPage = item; 393 | invalidate(); 394 | } 395 | 396 | @Override 397 | public void notifyDataSetChanged() { 398 | invalidate(); 399 | } 400 | 401 | @Override 402 | public void onPageScrollStateChanged(int state) { 403 | mScrollState = state; 404 | 405 | if (mListener != null) { 406 | mListener.onPageScrollStateChanged(state); 407 | } 408 | } 409 | 410 | @Override 411 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 412 | mCurrentPage = position; 413 | mPageOffset = positionOffset; 414 | invalidate(); 415 | 416 | if (mListener != null) { 417 | mListener.onPageScrolled(position, positionOffset, positionOffsetPixels); 418 | } 419 | } 420 | 421 | @Override 422 | public void onPageSelected(int position) { 423 | if (mSnap || mScrollState == ViewPager.SCROLL_STATE_IDLE) { 424 | mCurrentPage = position; 425 | mSnapPage = position; 426 | invalidate(); 427 | } 428 | 429 | if (mListener != null) { 430 | mListener.onPageSelected(position); 431 | } 432 | } 433 | 434 | @Override 435 | public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { 436 | mListener = listener; 437 | } 438 | 439 | /* 440 | * (non-Javadoc) 441 | * 442 | * @see android.view.View#onMeasure(int, int) 443 | */ 444 | @Override 445 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 446 | if (mOrientation == HORIZONTAL) { 447 | setMeasuredDimension(measureLong(widthMeasureSpec), measureShort(heightMeasureSpec)); 448 | } else { 449 | setMeasuredDimension(measureShort(widthMeasureSpec), measureLong(heightMeasureSpec)); 450 | } 451 | } 452 | 453 | /** 454 | * Determines the width of this view 455 | * 456 | * @param measureSpec 457 | * A measureSpec packed into an int 458 | * @return The width of the view, honoring constraints from measureSpec 459 | */ 460 | private int measureLong(int measureSpec) { 461 | int result; 462 | int specMode = MeasureSpec.getMode(measureSpec); 463 | int specSize = MeasureSpec.getSize(measureSpec); 464 | 465 | if ((specMode == MeasureSpec.EXACTLY) || (mViewPager == null)) { 466 | //We were told how big to be 467 | result = specSize; 468 | } else { 469 | //Calculate the width according the views count 470 | final int count = mViewPager.getAdapter().getCount(); 471 | result = (int)(getPaddingLeft() + getPaddingRight() 472 | + (count * 2 * mRadius) + (count - 1) * mRadius + 1); 473 | //Respect AT_MOST value if that was what is called for by measureSpec 474 | if (specMode == MeasureSpec.AT_MOST) { 475 | result = Math.min(result, specSize); 476 | } 477 | } 478 | return result; 479 | } 480 | 481 | /** 482 | * Determines the height of this view 483 | * 484 | * @param measureSpec 485 | * A measureSpec packed into an int 486 | * @return The height of the view, honoring constraints from measureSpec 487 | */ 488 | private int measureShort(int measureSpec) { 489 | int result; 490 | int specMode = MeasureSpec.getMode(measureSpec); 491 | int specSize = MeasureSpec.getSize(measureSpec); 492 | 493 | if (specMode == MeasureSpec.EXACTLY) { 494 | //We were told how big to be 495 | result = specSize; 496 | } else { 497 | //Measure the height 498 | result = (int)(2 * mRadius + getPaddingTop() + getPaddingBottom() + 1); 499 | //Respect AT_MOST value if that was what is called for by measureSpec 500 | if (specMode == MeasureSpec.AT_MOST) { 501 | result = Math.min(result, specSize); 502 | } 503 | } 504 | return result; 505 | } 506 | 507 | @Override 508 | public void onRestoreInstanceState(Parcelable state) { 509 | SavedState savedState = (SavedState)state; 510 | super.onRestoreInstanceState(savedState.getSuperState()); 511 | mCurrentPage = savedState.currentPage; 512 | mSnapPage = savedState.currentPage; 513 | requestLayout(); 514 | } 515 | 516 | @Override 517 | public Parcelable onSaveInstanceState() { 518 | Parcelable superState = super.onSaveInstanceState(); 519 | SavedState savedState = new SavedState(superState); 520 | savedState.currentPage = mCurrentPage; 521 | return savedState; 522 | } 523 | 524 | static class SavedState extends BaseSavedState { 525 | int currentPage; 526 | 527 | public SavedState(Parcelable superState) { 528 | super(superState); 529 | } 530 | 531 | private SavedState(Parcel in) { 532 | super(in); 533 | currentPage = in.readInt(); 534 | } 535 | 536 | @Override 537 | public void writeToParcel(Parcel dest, int flags) { 538 | super.writeToParcel(dest, flags); 539 | dest.writeInt(currentPage); 540 | } 541 | 542 | @SuppressWarnings("UnusedDeclaration") 543 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 544 | @Override 545 | public SavedState createFromParcel(Parcel in) { 546 | return new SavedState(in); 547 | } 548 | 549 | @Override 550 | public SavedState[] newArray(int size) { 551 | return new SavedState[size]; 552 | } 553 | }; 554 | } 555 | } 556 | -------------------------------------------------------------------------------- /app/src/main/java/com/viewpagerindicator/PageIndicator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Patrik Akerfeldt 3 | * Copyright (C) 2011 Jake Wharton 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.viewpagerindicator; 19 | 20 | import android.support.v4.view.ViewPager; 21 | 22 | /** 23 | * A PageIndicator is responsible to show an visual indicator on the total views 24 | * number and the current visible view. 25 | */ 26 | public interface PageIndicator extends ViewPager.OnPageChangeListener { 27 | /** 28 | * Bind the indicator to a ViewPager. 29 | * 30 | * @param view 31 | */ 32 | void setViewPager(ViewPager view); 33 | 34 | /** 35 | * Bind the indicator to a ViewPager. 36 | * 37 | * @param view 38 | * @param initialPosition 39 | */ 40 | void setViewPager(ViewPager view, int initialPosition); 41 | 42 | /** 43 | *

Set the current page of both the ViewPager and indicator.

44 | * 45 | *

This must be used if you need to set the page before 46 | * the views are drawn on screen (e.g., default start page).

47 | * 48 | * @param item 49 | */ 50 | void setCurrentItem(int item); 51 | 52 | /** 53 | * Set a page change listener which will receive forwarded events. 54 | * 55 | * @param listener 56 | */ 57 | void setOnPageChangeListener(ViewPager.OnPageChangeListener listener); 58 | 59 | /** 60 | * Notify the indicator that the fragment list has changed. 61 | */ 62 | void notifyDataSetChanged(); 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/me/li2/update_replace_fragment_in_viewpager/ContainerFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by WeiYi Li 3 | * 2015-08-07 4 | * weiyi.just2@gmail.com 5 | * li2.me 6 | */ 7 | package me.li2.update_replace_fragment_in_viewpager; 8 | 9 | import java.text.SimpleDateFormat; 10 | import java.util.Date; 11 | import java.util.Locale; 12 | 13 | import android.app.Activity; 14 | import android.os.Bundle; 15 | import android.support.v4.app.Fragment; 16 | import android.support.v4.app.FragmentManager; 17 | import android.support.v4.app.FragmentTransaction; 18 | import android.util.Log; 19 | import android.view.LayoutInflater; 20 | import android.view.View; 21 | import android.view.ViewGroup; 22 | import android.widget.FrameLayout; 23 | 24 | public class ContainerFragment extends Fragment { 25 | 26 | private static final String TAG = "Fragment4"; 27 | private static final String EXTRA_FRAGMENT_TO_SHOW = "me.li2.update_replace_fragment_in_viewpager.extra_fragment_to_show"; 28 | private static final String EXTRA_DATE = "me.li2.update_replace_fragment_in_viewpager.extra_date"; 29 | private static final String EXTRA_CONTENT = "me.li2.update_replace_fragment_in_viewpager.extra_content"; 30 | 31 | private int mFragmentToShow; 32 | private Date mDate; 33 | private String mContent; 34 | private int mFragmentContainerId; 35 | 36 | public static ContainerFragment newInstance(int fragmentToShow, Date date, String content) { 37 | Log.d(TAG, String.format("newInstance(fragmentToShow=%d, Date=%s, Content=%s", fragmentToShow, formatDate(date), content)); 38 | Bundle args = new Bundle(); 39 | args.putInt(EXTRA_FRAGMENT_TO_SHOW, fragmentToShow); 40 | args.putLong(EXTRA_DATE, date.getTime()); 41 | args.putString(EXTRA_CONTENT, content); 42 | 43 | ContainerFragment fragment = new ContainerFragment(); 44 | fragment.setArguments(args); 45 | return fragment; 46 | } 47 | 48 | @Override 49 | public void onCreate(Bundle savedInstanceState) { 50 | Log.d(TAG, "onCreate()"); 51 | super.onCreate(savedInstanceState); 52 | mFragmentToShow = getArguments().getInt(EXTRA_FRAGMENT_TO_SHOW); 53 | mDate = new Date(getArguments().getLong(EXTRA_DATE)); 54 | mContent = getArguments().getString(EXTRA_CONTENT); 55 | } 56 | 57 | @Override 58 | public void onDestroy() { 59 | super.onDestroy(); 60 | Log.d(TAG, "onDestroy()"); 61 | } 62 | 63 | @Override 64 | public void onAttach(Activity activity) { 65 | super.onAttach(activity); 66 | Log.d(TAG, "onAttach()"); 67 | } 68 | 69 | @Override 70 | public void onDetach() { 71 | super.onDetach(); 72 | Log.d(TAG, "onDetach()"); 73 | } 74 | 75 | @Override 76 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 77 | Log.d(TAG, "onCreateView()"); 78 | View view = inflater.inflate(R.layout.fragment_container, container, false); 79 | // To avoid overlapping, every fragment in the container in ViewPager should has an unique ID. http://stackoverflow.com/a/26079878/2722270 80 | FrameLayout fragmentContainer = (FrameLayout) view.findViewById(R.id.fragmentContainer); 81 | int fragmentContainerId = R.id.fragmentContainer0; 82 | mFragmentContainerId = fragmentContainerId; 83 | fragmentContainer.setId(fragmentContainerId); 84 | 85 | FragmentManager fm = getFragmentManager(); 86 | FragmentTransaction ft = fm.beginTransaction(); 87 | Fragment oldFragment = fm.findFragmentById(fragmentContainerId); 88 | Fragment newFragment; 89 | if (oldFragment != null) { 90 | ft.remove(oldFragment); 91 | } 92 | if (mFragmentToShow == 0) { 93 | newFragment = Page0Fragment.newInstance(mDate); 94 | } else { 95 | newFragment = Page1Fragment.newInstance(mContent); 96 | } 97 | ft.add(fragmentContainerId, newFragment); 98 | ft.commit(); 99 | Log.d(TAG, "add fragment " + newFragment.getClass().getSimpleName()); 100 | 101 | return view; 102 | } 103 | 104 | @Override 105 | public void onDestroyView() { 106 | super.onDestroyView(); 107 | Log.d(TAG, "onDestroyView()"); 108 | } 109 | 110 | // To replace fragment in ViewPager, we implement a fragment with a framelayout, we call it as ContainerFragment, 111 | // We pass a variable "fragmentToShow" to nofity the ContainerFragment, 112 | // depending on "fragmentToShow", the ContainerFragment decide whether replace old fragment with new fragment, or 113 | // update old fragment. 114 | public void updateData(int fragmentToShow, Date date, String content) { 115 | Log.d(TAG, String.format("updateData(fragmentToShow=%d, Date=%s, Content=%s", fragmentToShow, formatDate(date), content)); 116 | mDate = date; 117 | mContent = content; 118 | 119 | FragmentManager fm = getFragmentManager(); 120 | FragmentTransaction ft = fm.beginTransaction(); 121 | if (mFragmentToShow != fragmentToShow) { 122 | Log.d(TAG, "replace fragment"); 123 | mFragmentToShow = fragmentToShow; 124 | if (mFragmentToShow == 0) { 125 | ft.replace(mFragmentContainerId, Page0Fragment.newInstance(mDate)); 126 | } else { 127 | ft.replace(mFragmentContainerId, Page1Fragment.newInstance(mContent)); 128 | } 129 | ft.commit(); 130 | } else { 131 | Fragment oldFragment = fm.findFragmentById(mFragmentContainerId); 132 | if (oldFragment != null) { 133 | Log.d(TAG, "update fragment: " + oldFragment.getClass().getSimpleName()); 134 | if (oldFragment instanceof Page0Fragment) { 135 | ((Page0Fragment) oldFragment).updateDate(mDate); 136 | } else if (oldFragment instanceof Page1Fragment) { 137 | ((Page1Fragment) oldFragment).updateContent(mContent); 138 | } 139 | } 140 | } 141 | } 142 | 143 | private static String formatDate(Date date) { 144 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.US); 145 | return sdf.format(date); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /app/src/main/java/me/li2/update_replace_fragment_in_viewpager/MainActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by WeiYi Li 3 | * 2015-08-07 4 | * weiyi.just2@gmail.com 5 | * li2.me 6 | */ 7 | package me.li2.update_replace_fragment_in_viewpager; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.IOException; 11 | import java.io.InputStreamReader; 12 | import java.util.Date; 13 | 14 | import android.os.Bundle; 15 | import android.support.v4.app.Fragment; 16 | import android.support.v4.app.FragmentActivity; 17 | import android.support.v4.app.FragmentPagerAdapter; 18 | import android.support.v4.view.ViewPager; 19 | import android.support.v4.view.ViewPager.OnPageChangeListener; 20 | import android.text.Editable; 21 | import android.text.TextWatcher; 22 | import android.util.Log; 23 | import android.view.View; 24 | import android.view.View.OnClickListener; 25 | import android.widget.Button; 26 | import android.widget.CheckBox; 27 | import android.widget.CompoundButton; 28 | import android.widget.CompoundButton.OnCheckedChangeListener; 29 | import android.widget.EditText; 30 | import android.widget.Switch; 31 | import android.widget.TextView; 32 | 33 | import com.viewpagerindicator.CirclePageIndicator; 34 | 35 | public class MainActivity extends FragmentActivity implements OnClickListener { 36 | 37 | private static final String TAG = "Adapter"; 38 | private static final int PAGE_COUNT = 5; 39 | private static final int LOG_COLLECT_INTERVAL = 500; // ms 40 | private ViewPager mViewPager; 41 | private Button mDayPlusButton; 42 | private Button mDayMinusButton; 43 | private EditText mEditorText; 44 | private CheckBox mCheckBox; 45 | private Switch mSwitch; 46 | private TextView mLogView; 47 | 48 | private Date mDate; 49 | private String mContent; 50 | private boolean mChecked; 51 | private int mFragmentToShow; 52 | private boolean mShouldExitLogThread; 53 | 54 | @Override 55 | protected void onCreate(Bundle savedInstanceState) { 56 | super.onCreate(savedInstanceState); 57 | setContentView(R.layout.activity_main); 58 | 59 | mViewPager = (ViewPager) findViewById(R.id.main_viewpPager); 60 | mViewPager.setAdapter(mViewPagerAdapter); 61 | mViewPager.setOnPageChangeListener(mPageChangeListener); 62 | 63 | CirclePageIndicator indicator = (CirclePageIndicator) findViewById(R.id.main_viewPager_indicator); 64 | indicator.setViewPager(mViewPager); 65 | indicator.setOnPageChangeListener(mPageChangeListener); 66 | 67 | mDayPlusButton = (Button) findViewById(R.id.main_dayPlusButton); 68 | mDayMinusButton = (Button) findViewById(R.id.main_dayMinusButton); 69 | mDayPlusButton.setOnClickListener(this); 70 | mDayMinusButton.setOnClickListener(this); 71 | mEditorText = (EditText) findViewById(R.id.main_editContent); 72 | mEditorText.addTextChangedListener(mTextWatcher); 73 | mCheckBox = (CheckBox) findViewById(R.id.main_checkbox); 74 | mCheckBox.setOnCheckedChangeListener(mPage2CheckedChangeListener); 75 | mSwitch = (Switch) findViewById(R.id.main_switch); 76 | mSwitch.setOnCheckedChangeListener(mPage3CheckedChangeListener); 77 | mLogView = (TextView) findViewById(R.id.main_logView); 78 | 79 | mDate = new Date(); 80 | mContent = "Hello World, I'm li2."; 81 | mChecked = true; 82 | mFragmentToShow = 0; 83 | } 84 | 85 | @Override 86 | protected void onResume() { 87 | super.onResume(); 88 | mShouldExitLogThread = false; 89 | startCollectLogcatThread(); 90 | } 91 | 92 | @Override 93 | protected void onPause() { 94 | super.onPause(); 95 | mShouldExitLogThread = true; 96 | } 97 | 98 | private FragmentPagerAdapter mViewPagerAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) { 99 | @Override 100 | public int getCount() { 101 | return PAGE_COUNT; 102 | } 103 | 104 | // Return the Fragment associated with a specified position. 105 | @Override 106 | public Fragment getItem(int position) { 107 | Log.d(TAG, "getItem(" + position + ")"); 108 | if (position == 0) { 109 | return Page0Fragment.newInstance(mDate); 110 | } else if (position == 1) { 111 | return Page1Fragment.newInstance(mContent); 112 | } else if (position == 2) { 113 | return Page2Fragment.newInstance(mChecked); 114 | } else if (position == 3) { 115 | // return Page3Fragment.newInstance(); 116 | return getFragment(3); 117 | } else if (position == 4) { 118 | return ContainerFragment.newInstance(0, mDate, mContent); 119 | } 120 | 121 | return null; 122 | } 123 | 124 | private Fragment getFragment(int pageValue) { 125 | SimpleBackPage page = SimpleBackPage.getPageValue(pageValue); 126 | Fragment fragment; 127 | try { 128 | fragment = (Fragment) page.getCls().newInstance(); 129 | return fragment; 130 | } catch (InstantiationException e) { 131 | e.printStackTrace(); 132 | } catch (IllegalAccessException e) { 133 | e.printStackTrace(); 134 | } 135 | return null; 136 | } 137 | 138 | // Remove a page for the given position. The adapter is responsible for removing the view from its container. 139 | @Override 140 | public void destroyItem(android.view.ViewGroup container, int position, Object object) { 141 | super.destroyItem(container, position, object); 142 | Log.d(TAG, "destroyItem(" + position + ")"); 143 | }; 144 | 145 | @Override 146 | // To update fragment in ViewPager, we should override getItemPosition() method, 147 | // in this method, we call the fragment's public updating method. 148 | public int getItemPosition(Object object) { 149 | Log.d(TAG, "getItemPosition(" + object.getClass().getSimpleName() + ")"); 150 | if (object instanceof Page0Fragment) { 151 | ((Page0Fragment) object).updateDate(mDate); 152 | } else if (object instanceof Page1Fragment) { 153 | ((Page1Fragment) object).updateContent(mContent); 154 | } else if (object instanceof Page2Fragment) { 155 | ((Page2Fragment) object).updateCheckedStatus(mChecked); 156 | } else if (object instanceof ContainerFragment) { 157 | ((ContainerFragment) object).updateData(mFragmentToShow, mDate, mContent); 158 | } 159 | return super.getItemPosition(object); 160 | }; 161 | }; 162 | 163 | 164 | private ViewPager.OnPageChangeListener mPageChangeListener = new OnPageChangeListener() { 165 | @Override 166 | public void onPageSelected(int position) { 167 | Log.d(TAG, "\nonPageSelected(" + position + ")"); 168 | // notifyViewPagerDataSetChanged(); 169 | } 170 | 171 | @Override 172 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} 173 | 174 | @Override 175 | public void onPageScrollStateChanged(int state) {} 176 | }; 177 | 178 | 179 | /** 180 | * To update fragment in ViewPager, we should call PagerAdapter.notifyDataSetChanged() when data changed. 181 | * we should also override FragmentPagerAdapter.getItemPosition(), and 182 | * implement a public method for updating fragment. 183 | * Refer to [Update Fragment from ViewPager](http://stackoverflow.com/a/18088509/2722270) 184 | */ 185 | private void notifyViewPagerDataSetChanged() { 186 | Log.d(TAG, "\nnotifyDataSetChanged()"); 187 | mViewPagerAdapter.notifyDataSetChanged(); 188 | } 189 | 190 | 191 | @Override 192 | // page 0 data changed 193 | public void onClick(View v) { 194 | int id = v.getId(); 195 | if (id == R.id.main_dayPlusButton) { 196 | mDate = new Date((mDate.getTime() + 24*3600*1000)); 197 | notifyViewPagerDataSetChanged(); 198 | } else if (id == R.id.main_dayMinusButton) { 199 | mDate = new Date((mDate.getTime() - 24*3600*1000)); 200 | notifyViewPagerDataSetChanged(); 201 | } 202 | } 203 | 204 | // page 1 data changed 205 | private TextWatcher mTextWatcher = new TextWatcher() { 206 | @Override 207 | public void onTextChanged(CharSequence s, int start, int before, int count) {} 208 | 209 | @Override 210 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {} 211 | 212 | @Override 213 | public void afterTextChanged(Editable s) { 214 | mContent = s.toString(); 215 | notifyViewPagerDataSetChanged(); 216 | } 217 | }; 218 | 219 | // page 2 data changed 220 | private OnCheckedChangeListener mPage2CheckedChangeListener = new OnCheckedChangeListener() { 221 | @Override 222 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 223 | mChecked = isChecked; 224 | notifyViewPagerDataSetChanged(); 225 | } 226 | }; 227 | 228 | // page 3 data changed 229 | private OnCheckedChangeListener mPage3CheckedChangeListener = new OnCheckedChangeListener() { 230 | @Override 231 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 232 | mFragmentToShow = (isChecked) ? 1 : 0; 233 | notifyViewPagerDataSetChanged(); 234 | } 235 | }; 236 | 237 | 238 | // Collect all logcat of this app then display in scroll textview, 239 | // to show the detail of PagerAdapter method and Fragment life cycle 240 | // when user scroll or change page. 241 | private void startCollectLogcatThread() { 242 | clearLogcat(); 243 | new Thread(new Runnable() { 244 | @Override 245 | public void run() { 246 | while(!mShouldExitLogThread) { 247 | collectLogcat(); 248 | try { 249 | Thread.sleep(LOG_COLLECT_INTERVAL); 250 | } catch (InterruptedException e) { 251 | e.printStackTrace(); 252 | } 253 | } 254 | } 255 | }).start();; 256 | } 257 | 258 | private void clearLogcat() { 259 | String cmd = "logcat -c"; 260 | try { 261 | Runtime.getRuntime().exec(cmd); 262 | } catch (IOException e) { 263 | e.printStackTrace(); 264 | } 265 | } 266 | 267 | // Colllect logcat and display in TextView 268 | // http://tanxiaoya105.blog.163.com/blog/static/2103280192012101392053176 269 | // [logcat with mutiple tags at one time](http://stackoverflow.com/a/16995884/2722270) 270 | private void collectLogcat() { 271 | try { 272 | String cmd = "logcat -d Adapter:D Fragment0:D Fragment1:D Fragment2:D Fragment3:D Fragment4:D *:S"; 273 | Process process = Runtime.getRuntime().exec(cmd); 274 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); 275 | StringBuilder log = new StringBuilder(); 276 | String line = ""; 277 | while ((line = bufferedReader.readLine()) != null) { 278 | log.append(line + "\n"); 279 | } 280 | updateLogView(log.toString()); 281 | } catch (IOException e) { 282 | e.printStackTrace(); 283 | } 284 | } 285 | 286 | private void updateLogView(final String log) { 287 | runOnUiThread(new Runnable() { 288 | @Override 289 | public void run() { 290 | mLogView.setText(log); 291 | } 292 | }); 293 | } 294 | } 295 | -------------------------------------------------------------------------------- /app/src/main/java/me/li2/update_replace_fragment_in_viewpager/Page0Fragment.java: -------------------------------------------------------------------------------- 1 | package me.li2.update_replace_fragment_in_viewpager; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | import java.util.Locale; 6 | 7 | import android.app.Activity; 8 | import android.os.Bundle; 9 | import android.support.v4.app.Fragment; 10 | import android.util.Log; 11 | import android.view.LayoutInflater; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.widget.TextView; 15 | 16 | public class Page0Fragment extends Fragment { 17 | 18 | private static final String TAG = "Fragment0"; 19 | private static final String EXTRA_DATE = "me.li2.update_replace_fragment_in_viewpager.extra_date"; 20 | private Date mDate; 21 | private TextView mTextView; 22 | 23 | public static Page0Fragment newInstance(Date date) { 24 | Log.d(TAG, "newInstance(" + formatDate(date) + ")"); 25 | Bundle args = new Bundle(); 26 | args.putLong(EXTRA_DATE, date.getTime()); 27 | 28 | Page0Fragment fragment = new Page0Fragment(); 29 | fragment.setArguments(args); 30 | return fragment; 31 | } 32 | 33 | @Override 34 | public void onCreate(Bundle savedInstanceState) { 35 | Log.d(TAG, "onCreate()"); 36 | super.onCreate(savedInstanceState); 37 | mDate = new Date(getArguments().getLong(EXTRA_DATE)); 38 | } 39 | 40 | @Override 41 | public void onDestroy() { 42 | super.onDestroy(); 43 | Log.d(TAG, "onDestroy()"); 44 | } 45 | 46 | @Override 47 | public void onAttach(Activity activity) { 48 | super.onAttach(activity); 49 | Log.d(TAG, "onAttach()"); 50 | } 51 | 52 | @Override 53 | public void onDetach() { 54 | super.onDetach(); 55 | Log.d(TAG, "onDetach()"); 56 | } 57 | 58 | @Override 59 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 60 | Log.d(TAG, "onCreateView()"); 61 | View view = inflater.inflate(R.layout.fragment_page0, container, false); 62 | mTextView = (TextView) view.findViewById(R.id.page0_date); 63 | mTextView.setText(mDate.toString()); 64 | return view; 65 | } 66 | 67 | @Override 68 | public void onDestroyView() { 69 | super.onDestroyView(); 70 | Log.d(TAG, "onDestroyView()"); 71 | } 72 | 73 | // To update fragment in ViewPager, we should implement a public method for the fragment, 74 | // and do updating stuff in this method. 75 | public void updateDate(Date date) { 76 | Log.d(TAG, "updateDate(" + formatDate(date) + ")"); 77 | mDate = date; 78 | mTextView.setText(mDate.toString()); 79 | } 80 | 81 | private static String formatDate(Date date) { 82 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.US); 83 | return sdf.format(date); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/me/li2/update_replace_fragment_in_viewpager/Page1Fragment.java: -------------------------------------------------------------------------------- 1 | package me.li2.update_replace_fragment_in_viewpager; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.util.Log; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | public class Page1Fragment extends Fragment { 13 | 14 | private static final String TAG = "Fragment1"; 15 | private static final String EXTRA_CONTENT = "me.li2.update_replace_fragment_in_viewpager.extra_content"; 16 | private String mContent; 17 | private TextView mTextView; 18 | 19 | public static Page1Fragment newInstance(String content) { 20 | Log.d(TAG, "newInstance(" + content + ")"); 21 | Bundle args = new Bundle(); 22 | args.putString(EXTRA_CONTENT, content); 23 | 24 | Page1Fragment fragment = new Page1Fragment(); 25 | fragment.setArguments(args); 26 | return fragment; 27 | } 28 | 29 | @Override 30 | public void onCreate(Bundle savedInstanceState) { 31 | Log.d(TAG, "onCreate()"); 32 | super.onCreate(savedInstanceState); 33 | mContent = getArguments().getString(EXTRA_CONTENT); 34 | } 35 | 36 | @Override 37 | public void onDestroy() { 38 | super.onDestroy(); 39 | Log.d(TAG, "onDestroy()"); 40 | } 41 | 42 | @Override 43 | public void onAttach(Activity activity) { 44 | super.onAttach(activity); 45 | Log.d(TAG, "onAttach()"); 46 | } 47 | 48 | @Override 49 | public void onDetach() { 50 | super.onDetach(); 51 | Log.d(TAG, "onDetach()"); 52 | } 53 | 54 | @Override 55 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 56 | Log.d(TAG, "onCreateView()"); 57 | View view = inflater.inflate(R.layout.fragment_page1, container, false); 58 | mTextView = (TextView) view.findViewById(R.id.page1_content); 59 | mTextView.setText(mContent); 60 | return view; 61 | } 62 | 63 | @Override 64 | public void onDestroyView() { 65 | super.onDestroyView(); 66 | Log.d(TAG, "onDestroyView()"); 67 | } 68 | 69 | // To update fragment in ViewPager, we should implement a public method for the fragment, 70 | // and do updating stuff in this method. 71 | public void updateContent(String content) { 72 | Log.d(TAG, "updateContent(" + content + ")"); 73 | mContent = content; 74 | mTextView.setText(mContent); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/me/li2/update_replace_fragment_in_viewpager/Page2Fragment.java: -------------------------------------------------------------------------------- 1 | package me.li2.update_replace_fragment_in_viewpager; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.util.Log; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.CheckBox; 11 | 12 | public class Page2Fragment extends Fragment { 13 | 14 | private static final String TAG = "Fragment2"; 15 | private static final String EXTRA_CHECKED = "me.li2.update_replace_fragment_in_viewpager.extra_checked"; 16 | private boolean mChecked; 17 | private CheckBox mCheckBox; 18 | 19 | public static Page2Fragment newInstance(boolean checked) { 20 | Log.d(TAG, "newInstance(" + checked + ")"); 21 | Bundle args = new Bundle(); 22 | args.putBoolean(EXTRA_CHECKED, checked); 23 | 24 | Page2Fragment fragment = new Page2Fragment(); 25 | fragment.setArguments(args); 26 | return fragment; 27 | } 28 | 29 | @Override 30 | public void onCreate(Bundle savedInstanceState) { 31 | Log.d(TAG, "onCreate()"); 32 | super.onCreate(savedInstanceState); 33 | mChecked = getArguments().getBoolean(EXTRA_CHECKED); 34 | } 35 | 36 | @Override 37 | public void onDestroy() { 38 | super.onDestroy(); 39 | Log.d(TAG, "onDestroy()"); 40 | } 41 | 42 | @Override 43 | public void onAttach(Activity activity) { 44 | super.onAttach(activity); 45 | Log.d(TAG, "onAttach()"); 46 | } 47 | 48 | @Override 49 | public void onDetach() { 50 | super.onDetach(); 51 | Log.d(TAG, "onDetach()"); 52 | } 53 | 54 | @Override 55 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 56 | Log.d(TAG, "onCreateView()"); 57 | View view = inflater.inflate(R.layout.fragment_page2, container, false); 58 | mCheckBox = (CheckBox) view.findViewById(R.id.page2_selected); 59 | mCheckBox.setChecked(mChecked); 60 | return view; 61 | } 62 | 63 | @Override 64 | public void onDestroyView() { 65 | super.onDestroyView(); 66 | Log.d(TAG, "onDestroyView()"); 67 | } 68 | 69 | // To update fragment in ViewPager, we should implement a public method for the fragment, 70 | // and do updating stuff in this method. 71 | public void updateCheckedStatus(boolean checked) { 72 | Log.d(TAG, "updateCheckedStatus(" + checked + ")"); 73 | mChecked = checked; 74 | mCheckBox.setChecked(mChecked); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/me/li2/update_replace_fragment_in_viewpager/Page3Fragment.java: -------------------------------------------------------------------------------- 1 | package me.li2.update_replace_fragment_in_viewpager; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.util.Log; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | 11 | public class Page3Fragment extends Fragment { 12 | 13 | private static final String TAG = "Fragment3"; 14 | 15 | public Page3Fragment() { 16 | super(); 17 | } 18 | 19 | public static Page3Fragment newInstance() { 20 | Log.d(TAG, "newInstance()"); 21 | return new Page3Fragment(); 22 | } 23 | 24 | @Override 25 | public void onCreate(Bundle savedInstanceState) { 26 | Log.d(TAG, "onCreate()"); 27 | super.onCreate(savedInstanceState); 28 | } 29 | 30 | @Override 31 | public void onDestroy() { 32 | super.onDestroy(); 33 | Log.d(TAG, "onDestroy()"); 34 | } 35 | 36 | @Override 37 | public void onAttach(Activity activity) { 38 | super.onAttach(activity); 39 | Log.d(TAG, "onAttach()"); 40 | } 41 | 42 | @Override 43 | public void onDetach() { 44 | super.onDetach(); 45 | Log.d(TAG, "onDetach()"); 46 | } 47 | 48 | @Override 49 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 50 | Log.d(TAG, "onCreateView()"); 51 | return inflater.inflate(R.layout.fragment_page3, container, false); 52 | } 53 | 54 | @Override 55 | public void onDestroyView() { 56 | super.onDestroyView(); 57 | Log.d(TAG, "onDestroyView()"); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/me/li2/update_replace_fragment_in_viewpager/SimpleBackPage.java: -------------------------------------------------------------------------------- 1 | package me.li2.update_replace_fragment_in_viewpager; 2 | 3 | 4 | public enum SimpleBackPage { 5 | 6 | PAGE3(3, R.string.page1_title, Page3Fragment.class); 7 | 8 | private int values; 9 | private int title; 10 | private Class cls; 11 | 12 | private SimpleBackPage(int values, int title, Class cls) { 13 | this.values = values; 14 | this.title = title; 15 | this.cls = cls; 16 | } 17 | 18 | public int getValues() { 19 | return values; 20 | } 21 | 22 | public void setValues(int values) { 23 | this.values = values; 24 | } 25 | 26 | public Class getCls() { 27 | return cls; 28 | } 29 | 30 | public void setCls(Class cls) { 31 | this.cls = cls; 32 | } 33 | 34 | public int getTitle() { 35 | return title; 36 | } 37 | 38 | public void setTitle(int title) { 39 | this.title = title; 40 | } 41 | 42 | public static SimpleBackPage getPageValue(int val) { 43 | for (SimpleBackPage p : values()) { 44 | if (p.getValues() == val) { 45 | return p; 46 | } 47 | } 48 | return null; 49 | } 50 | } 51 | 52 | /* 53 | 54 | 求问Fragment fragment = (Fragment) page.getCls().newInstance(); 55 | http://segmentfault.com/q/1010000003967198/a-1020000003967414 56 | 57 | ## 根据问题追加的代码Update 58 | 59 | SimpleBackPage是enum类型,意图是**通过数字获取对应的Fragment类**: 60 | 61 | ```java 62 | SimpleBackPage page = SimpleBackPage.getPageValue(pageValue); 63 | // 如果pageValue=1,getCls返回的就是FeedBackFragment.class 64 | // 如果pageVaule=2,getCls返回的就是AboutFrament.class 65 | page.getCls(); 66 | 67 | public enum SimpleBackPage { 68 | FEEDBACK(1, R.string.setting_about, FeedBackFragment.class), 69 | ABOUT(2, R.string.setting_about, AboutFrament.class); 70 | 71 | private SimpleBackPage(int values, int title, Class cls) { 72 | this.values = values; 73 | this.title = title; 74 | this.cls = cls; 75 | } 76 | public Class getCls() { 77 | return cls; 78 | } 79 | ``` 80 | ------ 81 | 82 | ## 当拿到Fragment类后 83 | 84 | `Fragment.class.newInstance()` 通过调用该类的无参数构造器,创建并返回该类的一个实例。 85 | 从结果上看等价于:`new Fragment();` 86 | 87 | > Returns a new instance of the class represented by this Class, created by invoking the default (that is, zero-argument) constructor. If there is no such constructor, or if the creation fails (either because of a lack of available memory or because an exception is thrown by the constructor), an InstantiationException is thrown. If the default constructor exists but is not accessible from the context where this method is invoked, an IllegalAccessException is thrown. 88 | 89 | 感觉上`Fragment.class.newInstance()`不如`new Fragment()`清楚明了。而且你还要为其添加try/catch `exception type IllegalAccessException`. 90 | 91 | */ 92 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/li2/update-and-replace-fragment-in-viewpager/944d6cf509690e104db24d4ed9aa5caad1c5708d/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/li2/update-and-replace-fragment-in-viewpager/944d6cf509690e104db24d4ed9aa5caad1c5708d/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/li2/update-and-replace-fragment-in-viewpager/944d6cf509690e104db24d4ed9aa5caad1c5708d/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/li2/update-and-replace-fragment-in-viewpager/944d6cf509690e104db24d4ed9aa5caad1c5708d/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | 16 | 20 | 21 |