У меня TabLayout настроен с помощью viewpager. Viewpager настроен с адаптером. К адаптеру добавлено 11 фрагментов, и каждый фрагмент имеет обзор переработчика. Когда я запускаю приложение, пролистывание между фрагментами идет медленно. Может кто-нибудь сказать мне причину этой проблемы?

Моя MainActivity:

    myTabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);


    mainViewPager = (ViewPager) findViewById(R.id.mainViewPager);
    tabLayoutAdapter = new TabLayoutAdapter(getSupportFragmentManager());
    tabLayoutAdapter.addFragment(new HomeFragment());
    tabLayoutAdapter.addFragment(new ClipFragment());
    tabLayoutAdapter.addFragment(new MovieFragment());
    tabLayoutAdapter.addFragment(new SerialFragment());
    tabLayoutAdapter.addFragment(new MusicFragment());
    tabLayoutAdapter.addFragment(new BookFragment());
    tabLayoutAdapter.addFragment(new PixFragment());
    tabLayoutAdapter.addFragment(new GameFragment());
    tabLayoutAdapter.addFragment(new NewsFragment());
    tabLayoutAdapter.addFragment(new LiveFragment());
    tabLayoutAdapter.addFragment(new AdvancedSearchFragment());
    mainViewPager.setAdapter(tabLayoutAdapter);
    myTabLayout.setupWithViewPager(mainViewPager);

Мой адаптер:

public class TabLayoutAdapter extends FragmentStatePagerAdapter {
List<Fragment> tabPages = new ArrayList<>();

public TabLayoutAdapter(FragmentManager fm) {
    super(fm);
}

@Override
public Fragment getItem(int position) {
    return tabPages.get(position);
}

@Override
public int getCount() {
    return tabPages.size();
}

public void addFragment(Fragment page){
    tabPages.add(page);
}

}

Фрагмент образца:

public class MovieFragment extends Fragment {
RecyclerView movieRecyclerView;
List<Movie> movieList;
MovieAdapter movieAdapter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d("Fragment", "thread = " + Thread.currentThread().getName());
    Log.i("Fragment", "thread = " + Thread.currentThread().getName());
}


@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {


    View movieView = inflater.inflate(R.layout.tab_movie, container, false);
    return movieView;
}


@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    movieRecyclerView = (RecyclerView) view.findViewById(R.id.movieRecyclerView);
    movieList = new ArrayList<Movie>();
    movieAdapter = new MovieAdapter(view.getContext(), movieList);

    RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(view.getContext(), 2);
    movieRecyclerView.setLayoutManager(mLayoutManager);
    movieRecyclerView.addItemDecoration(new GridSpacingItemDecoration(2, dpToPx(10), false));
    movieRecyclerView.setItemAnimator(new DefaultItemAnimator());
    movieRecyclerView.setAdapter(movieAdapter);

    prepareMovies();



}

public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {

    private int spanCount;
    private int spacing;
    private boolean includeEdge;

    public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
        this.spanCount = spanCount;
        this.spacing = spacing;
        this.includeEdge = includeEdge;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view); // item position
        int column = position % spanCount; // item column

        if (includeEdge) {
            outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
            outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)

            if (position < spanCount) { // top edge
                outRect.top = spacing;
            }
            outRect.bottom = spacing; // item bottom
        } else {
            outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
            outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f /    spanCount) * spacing)
            if (position >= spanCount) {
                outRect.top = spacing; // item top
            }
        }
    }
}



private void prepareMovies() {
    int[] covers = new int[]{
            R.drawable.bossbaby,
            R.drawable.abeautifulmind,
            R.drawable.despicableme,
            R.drawable.harrypotter,
            R.drawable.thegodfather,
            R.drawable.piratesofcaribbean,
            };

    Movie movie = new Movie("Boss Baby",10000,4.5,20000,16000, covers[0]);
    movieList.add(movie);
    movie = new Movie("A Beautiful mind",35100,4.9,40000,39000, covers[1]);
    movieList.add(movie);
    movie = new Movie("Despicable me",20000,4.7,33000,31000, covers[2]);
    movieList.add(movie);
    movie = new Movie("Harry Potter",90000,5.0,110000,105000, covers[3]);
    movieList.add(movie);
    movie = new Movie("The God Father",70000,4.9,90000,86700, covers[4]);
    movieList.add(movie);
    movie = new Movie("Pirates of caribbean",50000,4.6,70000,64000, covers[5]);
    movieList.add(movie);



    movieAdapter.notifyDataSetChanged();
}

private int dpToPx(int dp) {
    Resources r = getResources();
    return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()));
}

}

3
Samin Heydarian 21 Авг 2018 в 09:33

3 ответа

Лучший ответ

Если у вас много фрагментов и вы хотите оптимизировать анимацию и взаимодействие, вы можете использовать viewpager.setOffscreenPageLimit(int numberOfPages);

setOffscreenPageLimit() будет иметь значение по умолчанию 1, т. Е. Viewpager будет загружать только одну страницу (фрагмент) с обеих сторон, а другие страницы будут воссозданы из адаптера при прокрутке и, следовательно, будут отставать в зависимости от операций, которые будет выполнять страница , Таким образом, когда вы знаете количество страниц, тогда использование этого метода поможет в плавности анимации подкачки и взаимодействия.

Из документа setOffscreenPageLimit ()

Установите количество страниц, которые должны быть сохранены по обе стороны от текущей страницы в иерархии представления в состоянии ожидания. Страницы за пределами этот предел будет воссоздан из адаптера при необходимости.

Это предлагается в качестве оптимизации. Если вы заранее знаете количество страниц, которые вам нужно будет поддерживать, или используете на своих страницах механизмы отложенной загрузки, то настройка этого параметра может иметь преимущества в воспринимаемой плавности анимации подкачки и взаимодействия. Если у вас есть небольшое количество страниц (3-4), которые вы можете поддерживать активными все сразу, меньше времени будет потрачено на макет для вновь созданных представлений поддеревьев, поскольку пользовательские страницы перемещаются назад и вперед.

8
Mohammed Farhan 21 Авг 2018 в 07:16

Наряду с ответом @Khemraj, попробуйте следующее также, потому что, когда мы возвращаемся к тому же классу recyclerview, то есть вероятность проблем с адаптером viewpager

tabLayoutAdapter = new TabLayoutAdapter(getChildFragmentManager());

Вместо того

tabLayoutAdapter = new TabLayoutAdapter(getSupportFragmentManager());
0
Uma Achanta 21 Авг 2018 в 07:43

Попробуйте сделать следующее, чтобы сделать навигацию более плавной:

1) в каждом фрагменте перемещайте код из onViewCreated в onActivityCreated, потому что это методы вызываются, когда фрагмент появляется полностью:

 @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        // put code of setting data to views etc.
    }

2) реализовать следующие методы в классе FragmentStateAdapter:

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
//        super.destroyItem(container, position, object);
    }

    // Force a refresh of the page when a different fragment is displayed
    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

3) Используйте несколько изображений с низким разрешением в вашем фрагменте (если вы используете их из папки ресурсов). Не используйте большое разрешение, как - 1024 * 960, попробуйте сжать их, а затем добавить.

4) Избегайте использования wrap_content в файлах разметки фрагментов. потому что тогда для вычисления высоты ширины требуется время. Если вы можете указать match_parent или любое другое конкретное значение в dp, оно будет работать намного быстрее.

Попробуйте эти пункты, может быть, они помогут вам.

0
NehaK 27 Авг 2018 в 07:15
51942878