【问题标题】:Viewpager extremely slow when swiping滑动时Viewpager非常慢
【发布时间】:2016-04-21 10:59:05
【问题描述】:

我有一个ViewPager,其中包含我生成的几个Fragments,并为其提供了独特的布局。这些Fragments 只是用户不应该与之交互的静态布局的占位符。 (类似于预览页面)。

这是包含FragmentsViewPager 的活动:

public class KidPreviewActivity extends FragmentActivity implements IKidPreviewView, PreviewFragment.OnFragmentInteractionListener {

private KidPreviewPresenter mPresenter;
private ViewPager mPager;
private PreviewSlidePagerAdapter mPagerAdapter;
private static final int NUM_PAGES = 6;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_kid_preview);

    // hide navigation bar
    View decorView = getWindow().getDecorView();
    int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_FULLSCREEN;
    decorView.setSystemUiVisibility(uiOptions);


    Button returnToLauncherBtn = (Button) findViewById(R.id.kidPreviewReturnToLauncherBtn);
    EditText emailET = (EditText) findViewById(R.id.kidPreviewParentEmail);

    mPresenter = new KidPreviewPresenter(getApplicationContext());
    mPresenter.attachView(this);

    returnToLauncherBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mPresenter.backToLauncher();
        }
    });
    mPager = (ViewPager) findViewById(R.id.previewPager);
    mPagerAdapter = new PreviewSlidePagerAdapter(getSupportFragmentManager());
    mPager.setAdapter(mPagerAdapter);
    CircleIndicator indicator = (CircleIndicator) findViewById(R.id.cIndicator);
    indicator.setViewPager(mPager);

} //-onCreate

@Override
protected void onDestroy() {
    super.onDestroy();
    if (isFinishing()) {
        mPresenter.destroy();
    }
}


@Override
public void onError(Message msg) {
    Utils.DisplayError(this, msg);
}

@Override
public void onDisconnected() {
    ActivityHelper.handleDisconnected(this);
}


@Override
public void backToLauncher() {
    finish();
}

@Override
public void notifyParents() {

}

@Override
public void onFragmentInteraction(Uri uri) {

}

private class PreviewSlidePagerAdapter extends FragmentStatePagerAdapter {
    public PreviewSlidePagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        PreviewFragment currentFrag = PreviewFragment.newInstance(R.layout.kid_preview_flipper_one);
        switch (position) {
            case 0:
                currentFrag = PreviewFragment.newInstance(R.layout.kid_preview_flipper_one);
                break;
            case 1:
                currentFrag = PreviewFragment.newInstance(R.layout.kid_preview_flipper_two);
                break;
            case 2:
                currentFrag = PreviewFragment.newInstance(R.layout.kid_preview_flipper_three);
                break;
            case 3:
                currentFrag = PreviewFragment.newInstance(R.layout.kid_preview_flipper_four);
                break;
            case 4:
                currentFrag = PreviewFragment.newInstance(R.layout.kid_preview_flipper_five);
                break;
            case 5:
                currentFrag = PreviewFragment.newInstance(R.layout.kid_preview_flipper_six);
                break;
        }
        return currentFrag;
    }

    @Override
    public int getCount() {
        return NUM_PAGES;
    }
}

但是,在加载此活动时,我在滑动/滑动 viewpager 项目时变得非常缓慢。

带有如下消息:

 04-21 06:56:13.238 1897-1897/com.myApp.myAppDev I/Choreographer: Skipped 97 frames!  The application may be doing too much work on its main thread.
04-21 06:56:14.933 1897-2281/com.myApp.myAppDev E/OpenGLRenderer: GL error:  Out of memory!

有什么方法可以解决这个问题/优化这个问题使其不会锁定活动?

我不确定为什么它在主线程上做“太多工作”,据我所知我没有在主线程上做太多工作?

Fragment newInstance:

   public static PreviewFragment newInstance(int layoutSelected){
        PreviewFragment fragment = new PreviewFragment();
        Bundle args = new Bundle();
        args.putInt(ARG_LAYOUT, layoutSelected);
        fragment.setArguments(args);
        return fragment;
    }

其他PreviewFragment方法:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        layoutSelected = getArguments().getInt(ARG_LAYOUT);
    }
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    return inflater.inflate(layoutSelected, container, false);


}

// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
    if (mListener != null) {
        mListener.onFragmentInteraction(uri);
    }
}

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    if (context instanceof OnFragmentInteractionListener) {
        mListener = (OnFragmentInteractionListener) context;
    } else {
        throw new RuntimeException(context.toString()
                + " must implement OnFragmentInteractionListener");
    }
}

【问题讨论】:

  • @user3505534 正如您从我的代码中看到的那样,我已经遵循了本指南。可悲的是,这无济于事。
  • 可能是附加片段代码?构造函数、onCreate 等?

标签: android android-fragments android-viewpager


【解决方案1】:

您似乎每次都在创建片段(在getItem 函数中)。 相反,您希望使用片段列表创建适配器,将它们存储在适配器中,然后更改 getItem 以从该列表中返回片段。

private class PreviewSlidePagerAdapter extends FragmentStatePagerAdapter {
  private List<Fragment>  mFragments;
  public PreviewSlidePagerAdapter(FragmentManager fm, List<Fragment> fragments) {
    super(fm);
    mFragments = fragments;
  }

  @Override
  public Fragment getItem(int position) {
    if (mFragments == null) {
      return (null);
    }
    return mFragments.get(position);
  }
}

并从您的 MainActivity 创建适配器:

List<Fragment> fragmentsList = new ArrayList<>();
fragmentsList.add(PreviewFragment.newInstance(R.layout.kid_preview_flipper_one));
            fragmentsList.add(PreviewFragment.newInstance(R.layout.kid_preview_flipper_two));
            fragmentsList.add(PreviewFragment.newInstance(R.layout.kid_preview_flipper_three));
            fragmentsList.add(PreviewFragment.newInstance(R.layout.kid_preview_flipper_four));
            fragmentsList.add(PreviewFragment.newInstance(R.layout.kid_preview_flipper_five));
            fragmentsList.add(PreviewFragment.newInstance(R.layout.kid_preview_flipper_six));
mPagerAdapter = new PreviewSlidePagerAdapter(getSupportFragmentManager(), fragmentsList);
mPager.setAdapter(mPagerAdapter);

【讨论】:

  • ViewPager 在内存中存储三个片段:当前、左、右。将它们全部保存在内存中 - 坏主意,因为主题启动器现在内存有问题
  • 哦,那么每次从头开始重新创建片段会更好吗?
  • 没错!更好
【解决方案2】:

尝试像这样更改您的适配器,它将节省一次调用 newInstance

    @Override
    public Fragment getItem(int position) {

        PreviewFragment currentFrag = null;
        switch (position) {
            case 1:
                currentFrag = PreviewFragment.newInstance(R.layout.kid_preview_flipper_two);
                break;
            case 2:
                currentFrag = PreviewFragment.newInstance(R.layout.kid_preview_flipper_three);
                break;
            case 3:
                currentFrag = PreviewFragment.newInstance(R.layout.kid_preview_flipper_four);
                break;
            case 4:
                currentFrag = PreviewFragment.newInstance(R.layout.kid_preview_flipper_five);
                break;
            case 5:
                currentFrag = PreviewFragment.newInstance(R.layout.kid_preview_flipper_six);
                break;
            default:
               currentFrag = PreviewFragment.newInstance(R.layout.kid_preview_flipper_one);
        }
        return currentFrag;
    }

如果您发布您的 newInstance 方法代码,那么它将很有用。我认为他们在 UI 线程中做了很多工作

更新

正如@user3505534 所说,尝试将父类从FragmentStatePagerAdapter 更改为FragmentPagerAdapter

【讨论】:

  • 添加了新实例。
  • 这仍然不能解决应用程序的滞后问题
  • @Tukajo 这是一个小小的改进 =) 我确实用新的细节更新了我的答案,我希望它会有用
  • 据我所知,无论好坏都没有太大变化。似乎仍然跳过了 60 多帧。
  • 我发现了这个问题,它与ViewPagerFragments 完全无关。我在布局中使用的其中一张图片非常庞大。它被缩小会导致问题。很抱歉浪费您的时间!感谢您的细微改进:)
猜你喜欢
  • 1970-01-01
  • 2018-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多