如何避免每次通过切换片段来创建Fragment对象?

问题描述:

我只有一个活动的应用程序与4个片段切换底部选项卡菜单。所以它一次只能在屏幕上显示4个片段之一。看起来很简单,但我问自己为什么通过切换片段,每次都必须重新创建新的Fragment对象?这是从Android文档:如何避免每次通过切换片段来创建Fragment对象?

FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); 
// Replace the contents of the container with the new fragment 
ft.replace(R.id.your_placeholder, new FooFragment()); 
// or ft.add(R.id.your_placeholder, new FooFragment()); 
// Complete the changes added above 
ft.commit(); 

我可以尝试存储由我自己片段的引用,每次挑现成的对象,但我发现这样的片段使用风格的建筑,所以它可能是错的?

+0

看到我更新的答案 –

您可以在ViewPager中设置片段,并切换ViewPager页面。

试试这个:

viewPager = (ViewPager) findViewById(R.id.viewpager); 
    FragmentAdapter adapter = new FragmentAdapter(getSupportFragmentManager()); 
    adapter.addFragment(new ExplorerFragment(), "Fragment1", false); 
    adapter.addFragment(new NotificationFragment(), "Fragment2", false); 
    adapter.addFragment(new HistoryFragment(), "Fragment3", false); 
    adapter.addFragment(new AccountFragment(), "Fragment4", false); 
    viewPager.setAdapter(adapter); 

    bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() { 
     @Override 
     public boolean onNavigationItemSelected(@NonNull MenuItem item) { 
      int id = item.getItemId(); 
      switch (id){ 
       case R.id.action_explorer: 
        viewPager.setCurrentItem(0); 
        final Menu bottomMenu = bottomNavigationView.getMenu(); 
        final MenuItem targetMenuItem = bottomMenu.getItem(0); 
        targetMenuItem.setChecked(true); 
        break; 
       case R.id.action_notification: 
        viewPager.setCurrentItem(1); 
        final Menu bottomMenu1 = bottomNavigationView.getMenu(); 
        final MenuItem targetMenuItem1 = bottomMenu1.getItem(1); 
        targetMenuItem1.setChecked(true); 
        break; 
       case R.id.action_history: 
        viewPager.setCurrentItem(2); 
        final Menu bottomMenu2 = bottomNavigationView.getMenu(); 
        final MenuItem targetMenuItem2 = bottomMenu2.getItem(2); 
        targetMenuItem2.setChecked(true); 
        break; 
       case R.id.action_account: 
        viewPager.setCurrentItem(3); 
        final Menu bottomMenu4 = bottomNavigationView.getMenu(); 
        final MenuItem targetMenuItem4 = bottomMenu4.getItem(3); 
        targetMenuItem4.setChecked(true); 
        break; 
       case R.id.action_search: 
        break; 
      } 
      return true; 
     } 
    }); 

EDIT1:如何创建NonSwipeableViewPager:

public class NonSwipeableViewPager extends ViewPager { 

    public NonSwipeableViewPager(Context context) { 
     super(context); 
     setMyScroller(); 
    } 

    public NonSwipeableViewPager(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     setMyScroller(); 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent event) { 
     // Never allow swiping to switch between pages 
     return false; 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     // Never allow swiping to switch between pages 
     return false; 
    } 

    //down one is added for smooth scrolling 

    private void setMyScroller() { 
     try { 
      Class<?> viewpager = ViewPager.class; 
      Field scroller = viewpager.getDeclaredField("mScroller"); 
      scroller.setAccessible(true); 
      scroller.set(this, new MyScroller(getContext())); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public class MyScroller extends Scroller { 
     public MyScroller(Context context) { 
      super(context, new DecelerateInterpolator()); 
     } 

     @Override 
     public void startScroll(int startX, int startY, int dx, int dy, int duration) { 
      super.startScroll(startX, startY, dx, dy, 350 /*1 secs*/); 
     } 
    } 
} 

,然后在你的XML:

<com.project.Components.NonSwipeableViewPager 
    android:id="@+id/viewpager" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:layout_above="@id/bottom_navigation"/> 
+0

我知道ViewPager只有通过实现滑动浏览的网页。你知道是否有可能禁用任何类型的动画和轻扫手势,只是使其立即替换碎片? –

+0

另外我见过ViewPager一次只保留有限数量的片段。所以如果它只有3的缓存,那么我的情况下,位于边缘的碎片将不断重新创建。 –

+1

是的。您只需创建一个自定义的ViewPager组件。我将使用代码@ArnieSchwarzvogel编辑我的文章 –

创建的所有片段一次,并用它或者使你的片段对象成为一个单例来实现它。

辛格尔顿例子:

class MyFragment extends Fragment{ 
    private static MyFragment instance; 

    public static MyFragment getInstance(){ 
    if(instance == null) 
     instance = new MyFragment(); 

    return instance; 
    } 
} 

使用MyFragment.getInstance();

现在,它不会产生新的对象,每次创建对象片段。

您可以将TAG添加到您的片段,同时更换,然后再使用FragmentManagerfindFragmentByTag检索:

FragmentManager fm = getSupportFragmentManager(); 
FragmentTransaction ft = fm.beginTransaction(); 
// Replace the contents of the container with the new fragment 
Fragment fooFrag = fm.findFragmentByTag("foo-frag-tag"); 

if(fooFrag == null) { 
    fooFrag = new FooFrag(); 
} 

ft.replace(R.id.your_placeholder, fooFrag, "foo-frag-tag"); 
// or ft.add(R.id.your_placeholder, new FooFragment()); 
// Complete the changes added above 
ft.commit(); 
+0

好主意。 –

+0

不幸的是,这不起作用--FragmentManager不会简单地缓存片段,它仅与putFragment()结合使用,这是一个完全不同的故事 –