Was it Frag-Ment to be? Luke Sleeman - Freelance Android developer - - PowerPoint PPT Presentation

was it frag ment to be
SMART_READER_LITE
LIVE PREVIEW

Was it Frag-Ment to be? Luke Sleeman - Freelance Android developer - - PowerPoint PPT Presentation

Was it Frag-Ment to be? Luke Sleeman - Freelance Android developer http://lukesleeman.com luke.sleeman@gmail.com @LukeSleeman Was it Frag-Ment to be? Intro - What are fragments? History Problems with fragments - Lifecycle, Bugs, Hard


slide-1
SLIDE 1

Was it Frag-Ment to be?

Luke Sleeman - Freelance Android developer

http://lukesleeman.com luke.sleeman@gmail.com @LukeSleeman

slide-2
SLIDE 2

Was it Frag-Ment to be?

  • Intro - What are fragments? History
  • Problems with fragments - Lifecycle, Bugs, Hard to use right
  • Best Practises: Don't use them - Places where we might have used

fragments, alternatives

  • Best Practises: Risk mitigation - Googles suggestions
  • Summary - What we learnt, key takeaways
  • Questions
slide-3
SLIDE 3

Intro

slide-4
SLIDE 4

What is a fragment?

A UI control you can compose to build responsive tablet UI’s

slide-5
SLIDE 5

What is a fragment?

A UI control you can compose to build responsive tablet UI’s

slide-6
SLIDE 6

What is a fragment?

A reusable group of Views to build our ui.

slide-7
SLIDE 7

What is a fragment?

A reusable group of Views to build our ui.

slide-8
SLIDE 8

What is a fragment?

An application component with a lifecycle

slide-9
SLIDE 9

What is a fragment?

An application component with a lifecycle

slide-10
SLIDE 10

History - Android 2.x

slide-11
SLIDE 11

History - Android 3.x

slide-12
SLIDE 12
slide-13
SLIDE 13

History - Android 4.x

slide-14
SLIDE 14

Problems

slide-15
SLIDE 15

Problem - Fragments ‘sorta’ work

slide-16
SLIDE 16

‘Sorta’ works is the worst kind of works

slide-17
SLIDE 17

Problem - Lifecycle

slide-18
SLIDE 18

Problem - Lifecycle

slide-19
SLIDE 19
  • Add in asynchronous fragment transactions
  • Child fragments
  • Viewpagers which cache state and lazy construct fragments …
  • Ultimately you have no idea what state your fragment will be in at

any point in time.

slide-20
SLIDE 20

Problem - Communication

Activity List Fragment Detail Fragment

? ? ???

slide-21
SLIDE 21

Problems - Lifecycle & Communication

private void updateTimeStamps(){
 ...
 String format = getContext().getString(R.string…) ...
 }
 
 private void newDataReceived(List<> ...){
 ...
 updateTimeStamps();
 ...
 }
 
 private void setTimeZone(TimeZone timeZone){
 ...
 updateTimeStamps();
 ...
 
 }
 
 public void startDataRefresh(){
 ...
 setTimeZone(TimeZone.getDefault());
 ...
 }

slide-22
SLIDE 22

Problems - Lifecycle & Communication

private void updateTimeStamps(){
 ...
 String format = getContext().getString(R.string…) ...
 }
 
 private void newDataReceived(List<> ...){
 ...
 updateTimeStamps();
 ...
 }
 
 private void setTimeZone(TimeZone timeZone){
 ...
 updateTimeStamps();
 ...
 
 }
 
 public void startDataRefresh(){
 ...
 setTimeZone(TimeZone.getDefault());
 ...
 }

slide-23
SLIDE 23

Problems - Lifecycle & Communication

private void updateTimeStamps(){
 ...
 String format = getContext().getString(R.string…) ...
 }
 
 private void newDataReceived(List<> ...){
 ...
 updateTimeStamps();
 ...
 }
 
 private void setTimeZone(TimeZone timeZone){
 ...
 updateTimeStamps();
 ...
 
 }
 
 public void startDataRefresh(){
 ...
 setTimeZone(TimeZone.getDefault());
 ...
 }

slide-24
SLIDE 24

Problems - Lifecycle & Communication

private void updateTimeStamps(){
 ...
 String format = getContext().getString(R.string…) ...
 }
 
 private void newDataReceived(List<> ...){
 ...
 updateTimeStamps();
 ...
 }
 
 private void setTimeZone(TimeZone timeZone){
 ...
 updateTimeStamps();
 ...
 
 }
 
 public void startDataRefresh(){
 ...
 setTimeZone(TimeZone.getDefault());
 ...
 }

slide-25
SLIDE 25

Problems (from google)

  • “Fragments are so general they become really difficult to explain to

people”

  • “A lot of times, you build up a fragment transaction, commit it, and

things work completely differently from how you expect”

  • Even more lifecycle to manage made stuff to complicated - “and the

bugs didn’t help!”

  • People think ‘they are just like views’. <fragment> tag turned out to

be a bad bit of syntactic sugar.

slide-26
SLIDE 26

Summary - Problems

  • 0. They almost work! But:
  • 1. Lifecycle makes them prone to programmer error.
  • 2. No clear use case - Replace views? Replace activities? Tablet

UIs?

  • 3. No guarantees about what state your fragment will be in.
slide-27
SLIDE 27

Best Practises

1 - Don’t use them! 2 - Mitigate the risks if you do use them

slide-28
SLIDE 28

Don’t use them - Normal Screens

slide-29
SLIDE 29

Don’t use them - Tablet UI’s

slide-30
SLIDE 30

Don’t use them - composable parts of UI

Use a ViewGroup!

(Subclass LinearLayout or FrameLayout)

slide-31
SLIDE 31

Subclass ViewGroup

public class UserSummaryView extends LinearLayout {
 
 private ImageView profileImage;
 private TextView name;
 private TextView title;
 private TextView bio;
 
 public UserSummaryView(Context context) {
 super(context);
 init(context);
 }
 
 public UserSummaryView(Context context, AttributeSet attrs) {
 super(context, attrs);
 init(context);
 }
 
 public UserSummaryView(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 init(context);
 }

slide-32
SLIDE 32

Subclass ViewGroup

public class UserSummaryView extends LinearLayout {
 
 private ImageView profileImage;
 private TextView name;
 private TextView title;
 private TextView bio;
 
 public UserSummaryView(Context context) {
 super(context);
 init(context);
 }
 
 public UserSummaryView(Context context, AttributeSet attrs) {
 super(context, attrs);
 init(context);
 }
 
 public UserSummaryView(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 init(context);
 }

slide-33
SLIDE 33

Subclass ViewGroup

public class UserSummaryView extends LinearLayout {
 
 private ImageView profileImage;
 private TextView name;
 private TextView title;
 private TextView bio;
 
 public UserSummaryView(Context context) {
 super(context);
 init(context);
 }
 
 public UserSummaryView(Context context, AttributeSet attrs) {
 super(context, attrs);
 init(context);
 }
 
 public UserSummaryView(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 init(context);
 }

slide-34
SLIDE 34

Subclass ViewGroup

private void init(Context context){

setOrientation(VERTICAL);

LayoutInflater.from(context).inflate( R.layout.view_user_summary, this);
 
 profileImage = (ImageView)findViewById(R.id.user_summary_image);
 name = (TextView)findViewById(R.id.user_summary_name);
 title = (TextView)findViewById(R.id.user_summary_title);
 bio = (TextView)findViewById(R.id.user_summary_bio);
 }
 
 public void setUser(User user){
 Picasso.with(getContext()) .load(user.getProfileImageUrl()) .into(profileImage);
 name.setText(user.getName());
 title.setText(user.getJobTitle());
 bio.setText(user.getBio());
 }

slide-35
SLIDE 35

Subclass ViewGroup

private void init(Context context){

setOrientation(VERTICAL);

LayoutInflater.from(context).inflate( R.layout.view_user_summary, this);
 
 profileImage = (ImageView)findViewById(R.id.user_summary_image);
 name = (TextView)findViewById(R.id.user_summary_name);
 title = (TextView)findViewById(R.id.user_summary_title);
 bio = (TextView)findViewById(R.id.user_summary_bio);
 }
 
 public void setUser(User user){
 Picasso.with(getContext()) .load(user.getProfileImageUrl()) .into(profileImage);
 name.setText(user.getName());
 title.setText(user.getJobTitle());
 bio.setText(user.getBio());
 }

slide-36
SLIDE 36

Subclass ViewGroup

<?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:orientation="vertical"
 android:layout_width="match_parent"
 android:layout_height="match_parent">
 
 <ImageView
 android:id="@+id/user_summary_image"
 android:layout_width="match_parent"
 android:layout_height="256dp"
 tools:src="@drawable/profile_sample"
 android:scaleType="centerCrop"
 />
 
 <TextView
 tools:text="Luke Sleeman"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:id="@+id/user_summary_name" …

slide-37
SLIDE 37

Subclass ViewGroup

<?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:orientation="vertical"
 android:layout_width="match_parent"
 android:layout_height="match_parent">
 
 <ImageView
 android:id="@+id/user_summary_image"
 android:layout_width="match_parent"
 android:layout_height="256dp"
 tools:src="@drawable/profile_sample"
 android:scaleType="centerCrop"
 />
 
 <TextView
 tools:text="Luke Sleeman"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:id="@+id/user_summary_name" …

slide-38
SLIDE 38

Subclass ViewGroup

<?xml version="1.0" encoding="utf-8"?>
 <merge xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 tools:parentTag="LinearLayout"
 tools:orientation="vertical"
 android:layout_width="match_parent"
 android:layout_height="match_parent"> 
 <ImageView
 android:id="@+id/user_summary_image"
 android:layout_width="match_parent"
 android:layout_height="256dp"
 tools:src="@drawable/profile_sample"
 android:scaleType="centerCrop"
 />
 
 <TextView
 tools:text="Luke Sleeman"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:id="@+id/user_summary_name" …

slide-39
SLIDE 39

Subclass ViewGroup

<?xml version="1.0" encoding="utf-8"?>
 <merge xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 tools:parentTag="LinearLayout"
 tools:orientation="vertical"
 android:layout_width="match_parent"
 android:layout_height="match_parent"> 
 <ImageView
 android:id="@+id/user_summary_image"
 android:layout_width="match_parent"
 android:layout_height="256dp"
 tools:src="@drawable/profile_sample"
 android:scaleType="centerCrop"
 />
 
 <TextView
 tools:text="Luke Sleeman"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:id="@+id/user_summary_name" …

slide-40
SLIDE 40

Subclass ViewGroup

… <com.example.UserSummaryView
 android:id="@+id/main_summary_view"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 /> … … @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 
 UserSummaryView summaryView = (UserSummaryView)findViewById(R.id.main_summary_view);
 summaryView.setUser(testUser);
 } …

slide-41
SLIDE 41

Subclass ViewGroup

… <com.example.UserSummaryView
 android:id="@+id/main_summary_view"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 /> … … @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 
 UserSummaryView summaryView = (UserSummaryView)findViewById(R.id.main_summary_view);
 summaryView.setUser(testUser);
 } …

slide-42
SLIDE 42

Subclass ViewGroup

… <com.example.UserSummaryView
 android:id="@+id/main_summary_view"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 /> … … @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 
 UserSummaryView summaryView = (UserSummaryView)findViewById(R.id.main_summary_view);
 summaryView.setUser(testUser);
 } …

slide-43
SLIDE 43

Don’t use them - Navigation Drawer

Use Activities!

slide-44
SLIDE 44

Navigation Drawer

public abstract class AbstractDrawerActivity extends AppCompatActivity { protected void startActivityAndCloseDrawer(Class<? extends Activity> toStart) {
 
 // Same activity, just return
 if (getActivity().getClass().equals(toStart))
 return;
 
 final Intent launchIntent = new Intent(getActivity(),toStart) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 
 drawerLayout.closeDrawer(GravityCompat.START);
 drawerLayout.postDelayed(new Runnable() {
 @Override
 public void run() {
 startActivity(launchIntent);
 getActivity().overridePendingTransition(R.anim.activity_in, R.anim.activity_out);
 }
 }, CLOSE_DELAY);
 }

slide-45
SLIDE 45

Navigation Drawer

public abstract class AbstractDrawerActivity extends AppCompatActivity { protected void startActivityAndCloseDrawer(Class<? extends Activity> toStart) {
 
 // Same activity, just return
 if (getActivity().getClass().equals(toStart))
 return;
 
 final Intent launchIntent = new Intent(getActivity(),toStart) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 
 drawerLayout.closeDrawer(GravityCompat.START);
 drawerLayout.postDelayed(new Runnable() {
 @Override
 public void run() {
 startActivity(launchIntent);
 getActivity().overridePendingTransition(R.anim.activity_in, R.anim.activity_out);
 }
 }, CLOSE_DELAY);
 }

slide-46
SLIDE 46

Navigation Drawer

public abstract class AbstractDrawerActivity extends AppCompatActivity { protected void startActivityAndCloseDrawer(Class<? extends Activity> toStart) {
 
 // Same activity, just return
 if (getActivity().getClass().equals(toStart))
 return;
 
 final Intent launchIntent = new Intent(getActivity(),toStart) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 
 drawerLayout.closeDrawer(GravityCompat.START);
 drawerLayout.postDelayed(new Runnable() {
 @Override
 public void run() {
 startActivity(launchIntent);
 getActivity().overridePendingTransition(R.anim.activity_in, R.anim.activity_out);
 }
 }, CLOSE_DELAY);
 }

slide-47
SLIDE 47

Navigation Drawer

public abstract class AbstractDrawerActivity extends AppCompatActivity { protected void startActivityAndCloseDrawer(Class<? extends Activity> toStart) {
 
 // Same activity, just return
 if (getActivity().getClass().equals(toStart))
 return;
 
 final Intent launchIntent = new Intent(getActivity(),toStart) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 
 drawerLayout.closeDrawer(GravityCompat.START);
 drawerLayout.postDelayed(new Runnable() {
 @Override
 public void run() {
 startActivity(launchIntent);
 getActivity().overridePendingTransition(R.anim.activity_in, R.anim.activity_out);
 }
 }, CLOSE_DELAY);
 }

slide-48
SLIDE 48

Navigation Drawer

public abstract class AbstractDrawerActivity extends AppCompatActivity { protected void startActivityAndCloseDrawer(Class<? extends Activity> toStart) {
 
 // Same activity, just return
 if (getActivity().getClass().equals(toStart))
 return;
 
 final Intent launchIntent = new Intent(getActivity(),toStart) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 
 drawerLayout.closeDrawer(GravityCompat.START);
 drawerLayout.postDelayed(new Runnable() {
 @Override
 public void run() {
 startActivity(launchIntent);
 getActivity().overridePendingTransition(R.anim.activity_in, R.anim.activity_out);
 }
 }, CLOSE_DELAY);
 }

slide-49
SLIDE 49

Navigation Drawer

public abstract class AbstractDrawerActivity extends AppCompatActivity { protected void startActivityAndCloseDrawer(Class<? extends Activity> toStart) {
 
 // Same activity, just return
 if (getActivity().getClass().equals(toStart))
 return;
 
 final Intent launchIntent = new Intent(getActivity(),toStart) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 
 drawerLayout.closeDrawer(GravityCompat.START);
 drawerLayout.postDelayed(new Runnable() {
 @Override
 public void run() {
 startActivity(launchIntent);
 getActivity().overridePendingTransition(R.anim.activity_in, R.anim.activity_out);
 }
 }, CLOSE_DELAY);
 }

slide-50
SLIDE 50

Navigation Drawer

<!—- Animate in —-> <set xmlns:android="http://schemas.android.com/apk/res/android">
 <alpha
 android:duration="@integer/activity_animation_duration"
 android:fromAlpha="0.0"
 android:toAlpha="1.0"
 android:interpolator="@android:anim/decelerate_interpolator"/>
 
 <translate
 android:duration="@integer/activity_animation_duration"
 android:fromYDelta="15%"
 android:toYDelta="0%"
 android:interpolator="@android:anim/decelerate_interpolator"/>
 </set> <!—- Animate out —-> <set xmlns:android="http://schemas.android.com/apk/res/android" >
 <alpha
 android:duration="@integer/activity_animation_duration"
 android:fromAlpha="1.0"
 android:toAlpha="0.0"
 android:interpolator="@android:anim/accelerate_interpolator"/>
 
 <translate
 android:duration="@integer/activity_animation_duration"
 android:fromYDelta="0%"
 android:toYDelta="-15%"
 android:interpolator="@android:anim/accelerate_interpolator"/>
 </set>

slide-51
SLIDE 51

Don’t use them - ViewPager

slide-52
SLIDE 52

Don’t use them - ViewPager

public class ViewListAdapter extends PagerAdapter {
 
 private ViewGroup [] views;
 
 public CustomPagerAdapter(ViewGroup... views) {
 this.views = views;
 }
 
 @Override
 public Object instantiateItem(ViewGroup collection, int position) {
 ViewGroup layout = views[position];
 collection.addView(layout);
 return layout;
 }
 
 @Override
 public void destroyItem(ViewGroup collection, int position, Object view) {
 collection.removeView((View) view);
 }
 
 @Override
 public int getCount() { return views.length; }
 
 @Override
 public boolean isViewFromObject(View view, Object object) { return view == object; }
 }

slide-53
SLIDE 53

Don’t use them - ViewPager

public class ViewListAdapter extends PagerAdapter {
 
 private ViewGroup [] views;
 
 public CustomPagerAdapter(ViewGroup... views) {
 this.views = views;
 }
 
 @Override
 public Object instantiateItem(ViewGroup collection, int position) {
 ViewGroup layout = views[position];
 collection.addView(layout);
 return layout;
 }
 
 @Override
 public void destroyItem(ViewGroup collection, int position, Object view) {
 collection.removeView((View) view);
 }
 
 @Override
 public int getCount() { return views.length; }
 
 @Override
 public boolean isViewFromObject(View view, Object object) { return view == object; }
 }

slide-54
SLIDE 54

Don’t use them - ViewPager

public class ViewListAdapter extends PagerAdapter {
 
 private ViewGroup [] views;
 
 public CustomPagerAdapter(ViewGroup... views) {
 this.views = views;
 }
 
 @Override
 public Object instantiateItem(ViewGroup collection, int position) {
 ViewGroup layout = views[position];
 collection.addView(layout);
 return layout;
 }
 
 @Override
 public void destroyItem(ViewGroup collection, int position, Object view) {
 collection.removeView((View) view);
 }
 
 @Override
 public int getCount() { return views.length; }
 
 @Override
 public boolean isViewFromObject(View view, Object object) { return view == object; }
 }

slide-55
SLIDE 55

Don’t use them - setRetainInstance()

Luke's a bad dev!


(Well, perhaps not)

Cancel short tasks

slide-56
SLIDE 56

Don’t use them - setRetainInstance()

slide-57
SLIDE 57

Don’t use them - Lifecycle, Navigation

  • What about Managing the back stack? Navigation? Passing data?
  • There are 3rd party libraries and solutions
  • Flow and Mortar From Square
  • https://www.bignerdranch.com/blog/an-investigation-into-flow-

and-mortar/

slide-58
SLIDE 58

Flow - Screens & Navigation

Screen Screen Screen

Activity

RecipeSearch ViewRecipe

flow.set(new ViewRecipeKey(234));

RecipeSearch ViewRecipe

flow.goBack();

slide-59
SLIDE 59

Mortar

Custom View Presenter

// Lifecycle methods
 void onEnterScope(MortarScope scope) void onLoad(Bundle savedInstanceState) void onSave(Bundle outState) void onExitScope() “Mortar provides a simplified, composable overlay for the Android lifecycle”

slide-60
SLIDE 60

Best Practises

Mitigate the risks if you do use them

slide-61
SLIDE 61

What the Fragment? - Google I/O 2016

https://youtu.be/k3IT-IJ0J98

slide-62
SLIDE 62

What is a fragment? (according to google)

  • Roughly equivalent to an activity in terms of level of abstraction
  • Part of the? in MV?
  • Quote: “Seriously, the are not just fancy view groups”, “Don’t use a

fragment when a ViewGroup or <include> will do”

  • Fragments provide glue and coordination of components, driven by

the knowledge of external lifecycle

slide-63
SLIDE 63

Fragment = Component + Lifecycle

slide-64
SLIDE 64

UI Components that have a lifecycle

slide-65
SLIDE 65

Googles suggestions - How to use them

“Make sure that you keep your thinking just scoped to the Fragment.” “Make sure its not trying to take on responsibilities

  • utside of its self”.
slide-66
SLIDE 66

Googles suggestions - How to use them

DO NOT ‘go fishing’ for things when you get attached to an activity - go looking for other fragments, try and pull in various deps, etc

slide-67
SLIDE 67

Googles suggestions - How to use them

Beware of dependencies! You can use onInflate() and fragment args to get data in

Activity List Fragment Detail Fragment

? ? ???

slide-68
SLIDE 68

Google suggestions - don’t worry about lifecycle

static final int INITIALIZING = 0; // Not yet created.
 static final int CREATED = 1; // Created.
 static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
 static final int STOPPED = 3; // Fully created, not started.
 static final int STARTED = 4; // Created and started, not resumed.
 static final int RESUMED = 5; // Created started and resumed.

slide-69
SLIDE 69

Use the support library Fragments!

  • Child FragmentManager state guaranteed after super.onCreate()
  • executePendingTransactions() didn’t do all the pending stuff for
  • children. Now fixed!
  • We now have FragmentTransaction.commitNow()
  • Added Fragment.onAttachFragment () - good time to setup

listeners, etc

slide-70
SLIDE 70

Pro-tip - Test with Do not keep activities

slide-71
SLIDE 71

Summary

slide-72
SLIDE 72

Summary - Problems with Fragments

  • Treat fragments with respect - they

are dangerous

  • Lifecycle, Child fragments and

Async fragment transactions!

  • Lack of clear use case causes

problems - where to put them in your architecture

slide-73
SLIDE 73

Summary - Don't use them

  • You can probably get by with a lot less fragments than you think
  • Don’t need them for normal activities
  • Don’t need them for tablet layouts/responsive UI
  • Don’t need them as composable UI building blocks
  • (Probably) Don’t need them for drawers and viewpagers
slide-74
SLIDE 74

If you have to use them, do this:

  • Don’t misuse them - e.g., they are not ViewGroups!
  • Keep communication to a minimum - “Make sure its not trying to

take on responsibilities outside of its self”

  • Use support library
  • Try and reduce the impact of the lifecycle as much as possible
slide-75
SLIDE 75

Questions?

slide-76
SLIDE 76
slide-77
SLIDE 77
slide-78
SLIDE 78
slide-79
SLIDE 79
slide-80
SLIDE 80
slide-81
SLIDE 81
slide-82
SLIDE 82

Case study - Fragments with Viewpager

  • Viewpager may not construct all its

views at once. Depends on how many pages your caching

  • FragmentPagerAdapter may build a

new fragment using getItem or may re-use an already constructed fragment by looking it up by ID

  • Two different view pager adapters,

which deal with state in a different manner

slide-83
SLIDE 83

Case study - Fragments with Viewpager

  • Often used with nested fragments.

EG, you may have a Fragment which takes up the screen, which contains a view pager inside it, which of course has other fragments

  • No way to get the current fragment.

Or fragments based on position

  • Existing PagerAdapters are awful -

you can’t reliably modify their contents, get fragment at index, etc.

slide-84
SLIDE 84

Case study - Fragments with Viewpager

  • Who knows when any of the lifecycle methods will

be called ?! Often depends on position index, and what page your are selecting.

  • eg. I have code that runs when the page changes

to update some stuff (activity action bar colour). It works fine when I select next page, or two pages

  • down. Dies with :



 java.lang.IllegalStateException: Fragment TimelineListFragment_{b20af32 id=0x7f0c00bb android:switcher: 2131493051:1949793103} not attached to Activity 
 
 When I select something 5 pages across

slide-85
SLIDE 85

S.O.L.I.D principals of OO design

S - Single Responsibility Principal O L I D

slide-86
SLIDE 86

Googles suggestions - Setup is conditional

  • code from 14:30 in presentation.
slide-87
SLIDE 87

Googles suggestions

  • Fragments are great of libraries - don’t need to add stuff into
  • nCreate, onPause, onResume, etc. Instead just add this fragment

and it does it all - e.g., the map fragment

  • can even use <fragment>
slide-88
SLIDE 88

Flow and Morter From Square

  • TODO ***Small example of what they each do*** leave out of GDG

presentation

  • https://www.bignerdranch.com/blog/an-investigation-into-flow-and-

mortar/

  • https://corner.squareup.com/2014/10/advocating-against-android-

fragments.html

  • https://www.reddit.com/r/androiddev/comments/2iodnx/

advocating_against_android_fragments/