ViewPager с FragmentStatePagerAdapter проблемы, которые проявляются только на Android 8.0+ Oreo - PullRequest
0 голосов
/ 27 сентября 2018

У меня есть приложение для Android, которое существует довольно давно, и все работает как надо, кроме Android Oreo.Существует ViewPager с множеством разных типов фрагментов различной сложности каждый.Он ведет себя правильно (смахивание влево / вправо), значения также автоматически сохраняются при наборе текста, захвате изображения или выборе элементов из списка и т. Д. На Android O, когда я делаю горизонтальную фотографию (он воссоздает действие вместе со всем внутри)отображается правильно, и когда я проведу пальцем влево / вправо для нескольких фрагментов, они начинают казаться полностью пустыми, если я вернусь на исходную страницу (где я сделал фотографию), она также будет пустой и все фрагменты рядом с ней.

Я перепробовал все, но ничего не работает.Я проверил время жизни каждого типа фрагмента, и они правильно приостановлены / уничтожены / воссозданы / возобновлены, но они абсолютно пустые.

Один из моих фрагментов содержит поле подписи, которое требует ViewPager для предотвращения перемещения страниц во время рисования подписипоэтому я использую следующий пользовательский ViewPager:

public class LockableViewPager extends ViewPager {
    private boolean mPagingEnabled;

    public LockableViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mPagingEnabled = true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return this.mPagingEnabled && super.onTouchEvent(event);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return this.mPagingEnabled && super.onInterceptTouchEvent(event);
    }

    public void setPagingEnabled(boolean enabled) {
        this.mPagingEnabled = enabled;
    }
}

Этот LockableViewPager затем помещается в файл макета активности:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <my.somedomain.someapp.ui.LockableViewPager
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/parametersPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/view_pager_indicator"/>

    <my.somedomain.someapp.ui.CustomViewPagerIndicator
        android:id = "@+id/view_pager_indicator"
        android:layout_width = "wrap_content"
        android:layout_height = "wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="2dp"
        app:delimiterSize = "8dp"
        app:itemSize="10dp" />
</RelativeLayout>

Активность, которая обрабатывает ViewPagerвыглядит следующим образом:

public class EditParametersActivity extends FragmentActivity
        implements ParameterInteractionEvents, TouchEventsListenerInterface {
    private static final String TAG                            = "EditParametersActivity";
    private static final String CLASS_NAME                     = EditParametersActivity.class.getName();
    //...

    private static ArrayList<RouteStructureParamListItem> mParamItems                  = new ArrayList<>();
    private static ArrayList<VibValueInstancesItem>       mParameterValueInstanceItems = new ArrayList<>();
    //...
    private FrameLayout            mMainLayout;
    private LockableViewPager      mViewPager;

    private ParametersPagerAdapter mPagerAdapter;
    private CustomViewPagerIndicator     mPageIndicator;
    private int mCurrentPage = 0;

    //...

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

        mToolbar = findViewById(R.id.toolbar);
        setActionBar(mToolbar);

        if (getActionBar() != null) {
            getActionBar().setDisplayHomeAsUpEnabled(true);
            getActionBar().setDisplayShowHomeEnabled(true);
        }

        mRlLoading = findViewById(R.id.rlLoading);
        mMainLayout = findViewById(R.id.main_layout);

        mViewPager = findViewById(R.id.parametersPager);
        mViewPager.setOffscreenPageLimit(3);

        mPageIndicator = findViewById(R.id.view_pager_indicator);

        Bundle args = savedInstanceState != null ? savedInstanceState : getIntent().getExtras();

        mCurrentUser = args.getParcelable(ARG_CURRENT_USER);
        mItem = args.getParcelable(ARG_ROUTE_DETAILS_ITEM);
        mRouteListItem = args.getParcelable(ARG_ROUTE_LIST_ITEM);

        if (args.containsKey(ARG_LIST_ITEM_POSITION)) {
            mCurrentPage = args.getInt(ARG_LIST_ITEM_POSITION);
        }

        if (mRouteListItem != null && mRouteListItem.getRouteDesc() != null) {
            setTitle(mRouteListItem.getRouteDesc());
        }

        mRlLoading.setVisibility(View.VISIBLE);

        mToolbar.setSubtitle(mItem.getNodeDescription());

        mDrawerLayout = findViewById(R.id.drawer_layout);
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);

        //...

        mBtnToggleParametersDrawer = findViewById(R.id.btnToggleParametersDrawer);
        mBtnToggleParametersDrawer.setOnClickListener(view -> mDrawerLayout.openDrawer(Gravity.END));

        mRvNavDrawerParameters = findViewById(R.id.rvNavDrawerParameters);
        mRvNavDrawerParameters.setLayoutManager(new LinearLayoutManager(this));
        mRvNavDrawerParameters.setNestedScrollingEnabled(false);

        if (savedInstanceState != null) {
            mParamItems = args.getParcelableArrayList(ARG_ROUTE_STRUCTURE_PARAM_LIST);
            displayParameters();
            mRlLoading.setVisibility(View.GONE);
        } else {
            // Load parameters from database
            GetViewPagerDataTask routesTask = new GetViewPagerDataTask(this,
                    mCurrentUser, mRouteListItem.getAssignedInspectionID(),
                    mItem.getRouteStructureTaskID());

            routesTask.getTask().continueWith(task -> {
                if (task.isFaulted()) {
                    mRlLoading.setVisibility(View.GONE);
                    showSnackBar(mMainLayout, "Error loading structure parameters", true, Snackbar.LENGTH_SHORT);
                } else {
                    mParamItems = task.getResult().mData;

                    displayParameters();

                    mRlLoading.setVisibility(View.GONE);
                    updateToolbarAndNavDrawer();
                }

                return null;
            }, Task.UI_THREAD_EXECUTOR);

        }

        //...

        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                mCurrentPage = position;

                updateToolbarAndNavDrawer();

                Tools.hideSoftKeyboard(EditParametersActivity.this);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        //...
        outState.putInt(ARG_LIST_ITEM_POSITION, mCurrentPage);
        outState.putParcelableArrayList(ARG_ROUTE_STRUCTURE_PARAM_LIST, mParamItems);
    }

    //...

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            // Respond to the action bar's Up/Home button
            case android.R.id.home:
                finish();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private void displayParameters() {
        mPagerAdapter = new ParametersPagerAdapter(
                getSupportFragmentManager(), mParamItems, mCurrentUser, mToolbar.getTitle().toString(),
                mToolbar.getSubtitle().toString());
        mViewPager.setAdapter(mPagerAdapter);

        mPageIndicator.setViewPager(mViewPager);

        mViewPager.setCurrentItem(mCurrentPage, true);

        //...
    }


    @Override
    public void onShowSnackBar(String message, boolean isError, int duration) {
        showSnackBar(mMainLayout, message, isError, duration);
    }

    @Override
    public void onRequestViewPagerLock(boolean lock) {
        mViewPager.setPagingEnabled(!lock);

        if (lock && mDrawerLayout.isDrawerOpen(Gravity.END)) {
            mDrawerLayout.closeDrawer(Gravity.END);
        }

        mBtnToggleParametersDrawer.setEnabled(!lock);

        mSpnVibParamInstances.setEnabled(!lock);
    }

    @Override
    public void setScrollEnabled(boolean enabled) {
        mViewPager.setPagingEnabled(enabled);
    }

    @Override
    public void onNavDrawerParameterItemClick(int position) {
        mViewPager.setCurrentItem(position, true);
        mDrawerLayout.closeDrawer(Gravity.END);

        mCurrentPage = position;

        //...
    }

    @Override
    public void onBackPressed() {
        if (mDrawerLayout.isDrawerOpen(Gravity.END)) {
            mDrawerLayout.closeDrawer(Gravity.END);
        } else {
            super.onBackPressed();
        }
    }
}

FragmentStatePagerAdapter немного изменен для повышения производительности и может предоставить текущий активный фрагмент:

public abstract class MyFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
    private SparseArray<Fragment> mRegisteredFragments = new SparseArray<>();

    public MyFragmentStatePagerAdapter(FragmentManager fragmentManager) {
        super(fragmentManager);
    }

    @NonNull
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        mRegisteredFragments.put(position, fragment);
        return fragment;
    }

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

    public Fragment getRegisteredFragment(int position) {
        return mRegisteredFragments.get(position);
    }
}

И, наконец,Фактический адаптер пейджера:

public class ParametersPagerAdapter extends MyFragmentStatePagerAdapter {
    private static final String TAG = "ParametersPagerAdapter";
    private static ArrayList<RouteStructureParamListItem> mItems;
    private AccountsModel mCurrentUser;
    private String mToolbarTitle, mToolbarSubtitle;

    public ParametersPagerAdapter(FragmentManager fm, ArrayList<RouteStructureParamListItem> items,
                                  AccountsModel user, String toolbarTitle, String toolbarSubtitle) {
        super(fm);

        mItems = items;
        mCurrentUser = user;
        mToolbarTitle = toolbarTitle;
        mToolbarSubtitle = toolbarSubtitle;
    }

    @Override
    public Fragment getItem(int position) {
        RouteStructureParamListItem item = mItems.get(position);

        switch (item.getParameterType()) {
            case ParameterTypes.Text:
                return TextParameterFragment.newInstance(item, mCurrentUser, position);
            case ParameterTypes.Image:
                return ImageParameterFragment.newInstance(item, mCurrentUser, position);
            case ParameterTypes.GPS:
                return GPSParameterFragment.newInstance(item, mCurrentUser, position);
            case ParameterTypes.Vibration:
                return VibParameterFragment.newInstance(item, mCurrentUser, position,
                        mToolbarTitle, mToolbarSubtitle);
            case ParameterTypes.Signature:
                return SignatureParameterFragment.newInstance(item, mCurrentUser, position);
            case ParameterTypes.Date:
                return DateTimeParameterFragment.newInstance(item, mCurrentUser, position);
            case ParameterTypes.Number:
                return NumericParameterFragment.newInstance(item, mCurrentUser, position);
            case ParameterTypes.Response:
                return ResponseParameterFragment.newInstance(item, mCurrentUser, position);
            default:
                Log.w(TAG, "WARNING: Parameter with type '" + item.getParameterType() + "' is not supported!");
                return ParameterFragment.newInstance(item, mCurrentUser, position);
        }
    }

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

Я бьюсь уже несколько дней, чтобы понять, что не так.Любая помощь приветствуется.

Спасибо!

...