Фрагмент не раздувается после приостановки и возобновления действия - PullRequest
0 голосов
/ 14 июля 2020

Здравствуйте, товарищи программисты!

Наблюдаю странное поведение на android 9 устройствах. Следующий код отлично работает на Android 5.1.1

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

private void openHistoryFragment(boolean withSelfHealing) {
    try {
        FragmentManager fragmentManager = getSupportFragmentManager();
        HistoryFragment mPreviousHistoryInstance = null;
        if (historyFragment != null && historyFragment.isVisible())
            mPreviousHistoryInstance = historyFragment;
        historyFragment = new HistoryFragment();
        historyFragment.setSettingsCallback(this);
        if (withSelfHealing)
            historyFragment.addFixingRunnable(() -> {
                Timber.w("Self healing view behaviour");
                openLoginDialog(LoginDialog.LoginMode.TEXT_ENTER, false);
                hideLoginDialog();
                Timber.w("Self healing view behaviour --- END");
            });
        FragmentTransaction transaction = fragmentManager.beginTransaction();
    
        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        
        if (mPreviousHistoryInstance != null)
            transaction.remove(mPreviousHistoryInstance);
        transaction.add(R.id.fragment_holder, historyFragment, "historyFragment");
        //transaction.setReorderingAllowed(true);
        transaction.commit();
    } catch (Exception e) {
        Timber.e(e, "Failed to display HistoryFragment ! ");
    }

Это отлично работает, когда мой Activity ( Действие A) загружено. Однако, если я запустил другое действие B, затем вернусь к действию A. Фрагмент больше не отображается при вызове этой функции.

Вот код для фрагмента:

public class HistoryFragment extends ErgoDialogFragment implements 
LoaderManager.LoaderCallbacks<Cursor>, 
View.OnClickListener, AdapterView.OnItemClickListener,
WorkoutDetailFragment.OnFragmentInteractionListener 
{
private static final int USER_LOADER = 2;
private static final int WORKOUT_LOADER = 1;

private ProgressBar spinner;

private OldSettingsFragmentCallback settings;

//private View view;

private CursorAdapter cursorAdapter;
private ListView listView;

private WeekStatsView weeklyView;
private TextView emptyView;
private Switcher switcher;
private LoaderManager mLoaderManager;


public HistoryFragment() {

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    super.onCreateView(inflater, container, savedInstanceState);
    View view;
    
    view = inflater.inflate(R.layout.history_fragment, container, false);

    RelativeLayout background = view.findViewById(R.id.background_layout);

    try {
        //background.setBackgroundResource(R.drawable.background_blue_gauss2);
        Drawable backgroundDrawable = ErgoApplication.getBackgroundDrawableBlurred();
        if (backgroundDrawable != null) {
            background.setBackground(backgroundDrawable);
        }
    } catch (Exception e) {
        LogCatcher.write(e);
    }
    DialogHeader header = view.findViewById(R.id.dialogHeader1);
    header.setTitle(getString(R.string.history_title));
    header.setCloseBtnOnClickListener(new ErgoOnClickListener() {
        @Override
        public void onClickEvent(View view) {
            dismiss();
        }
    });


    listView = view.findViewById(R.id.backgroundListView);
    weeklyView = view.findViewById(R.id.weekly_view);

    cursorAdapter = new WorkoutCursorAdapter(getContext(), null, true);
    listView.setAdapter(cursorAdapter);
    listView.setOnItemClickListener(this);
    emptyView = view.findViewById(R.id.emptyView);
    listView.setEmptyView(emptyView);

    switcher = view.findViewById(R.id.mode_switcher);
    switcher.setTextLeft(getString(R.string.history_switcher_personal));
    switcher.setTextRight(getString(R.string.history_switcher_all));

    spinner = view.findViewById(R.id.spinner);

    mLoaderManager = LoaderManager.getInstance(this);

    if (ErgoApplication.getUserManager() != null 
&& ErgoApplication.getUserManager().getIfisUser() != null) {
        switchToUserLoader();
        switcher.setActiveSide(Switcher.SwitcherSide.SWITCHER_LEFT);
        switcher.show();
    } else {
        switchToGeneralLoader();
        switcher.hide();
        switcher.setActiveSide(Switcher.SwitcherSide.SWITCHER_RIGHT);
    }
    switcher.setLeftOnClickListener(new ErgoOnClickListener() {
        @Override
        public void onClickEvent(View view) {
            switchToUserLoader();
            switcher.setActiveSide(Switcher.SwitcherSide.SWITCHER_LEFT);
        }
    });
    switcher.setRightOnClickListener(new ErgoOnClickListener() {
        @Override
        public void onClickEvent(View view) {
            switchToGeneralLoader();
            switcher.setActiveSide(Switcher.SwitcherSide.SWITCHER_RIGHT);
        }
    });
    return view;
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    view.postDelayed(this::hideKeyboard, 500);
}

private void switchToGeneralLoader() {
    if (mLoaderManager == null)
        return;
    mLoaderManager.destroyLoader(USER_LOADER);
    mLoaderManager.initLoader(WORKOUT_LOADER, null, this);
}

public void switchToUserLoader() {
    Timber.w("Using USER specific loader ! ");
    if (mLoaderManager == null)
        return;
    mLoaderManager.destroyLoader(WORKOUT_LOADER);
    mLoaderManager.initLoader(USER_LOADER, null, this);
}

/*public View getView() {
    return view;
}*/

public void stopSpinning() {
    if (spinner != null)
        spinner.setVisibility(View.INVISIBLE);
}

/**
 * Shows a spinner to show that work is in progress
 */
public void showLoadingLayout() {
    weeklyView.fetchData(null);
    emptyView.setVisibility(View.INVISIBLE);
    if (spinner != null)
        spinner.setVisibility(View.VISIBLE);
}


public void setSettingsCallback(OldSettingsFragmentCallback settings) {
    this.settings = settings;
}

public void doNothing(View v) {

}

@Override
public void onClick(View v) {
    LogCatcher.dropBreadCrump("close-history-fragment");
    settings.onCloseClick(getTag());
}

/**
 * Hides the keyboard
 */
public void hideKeyboard() {
    try {
        InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (listView != null)
            imm.hideSoftInputFromWindow(listView.getWindowToken(), 0);

        getActivity().getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
    } catch (Exception e) {

    }
}

@Override
public void onResume() {
    super.onResume();

    if (getContext() != null)
        FirebaseAnalytics.getInstance(getContext()).setCurrentScreen(getActivity(),
"HistoryFragment", null);
    
    EventLogger.logView(getActivity(), getClass().getSimpleName());
    Timber.i("onResume()");
    if (switcher != null) {
        switcher.postDelayed(this::hideKeyboard, 500);
        if (switcher.getActiveSide() != null) {
            if (switcher.getActiveSide() == Switcher.SwitcherSide.SWITCHER_LEFT) {
                //user mode
                String user = ErgoApplication.getUserManager().getIfisUser();
                Timber.i("onResume() -- user is %s", (user != null ? user : "undefined"));
                weeklyView.fetchData(user);
            } else {
                //other side
                Timber.i("onResume() -- switcher is in right position");
            }
        } else {
            Timber.i("onResume() -- no active side");
        }
    } else
        Timber.i("onResume() -- no switcher found");
}

@NonNull
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    switch (id) {
        case WORKOUT_LOADER:
            showLoadingLayout();
            return new CursorLoader(getActivity(), MyContentProvider.WORKOUT_URI, 
null, null, null, WorkoutSummaryTable.COLUMN_ID + " DESC");
        case USER_LOADER:
            //TODO hier geht es weiter
            String currentUser = ErgoApplication.getUserManager().getIfisUser();
            if (currentUser != null) {
                showLoadingLayout();
                String selectString = WorkoutSummaryTable.COLUMN_STAGING + "=?";
                return new CursorLoader(getActivity(), MyContentProvider.WORKOUT_URI,
 null, selectString, new String[]{currentUser}, WorkoutSummaryTable.COLUMN_ID + " DESC");
            } else {
                stopSpinning();
            }
        default:
            return new CursorLoader(getActivity(), MyContentProvider.WORKOUT_URI,
 null, null, null, WorkoutSummaryTable.COLUMN_ID + " DESC");
    }
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    try {
        stopSpinning();
        cursorAdapter.changeCursor(data);
        if (weeklyView != null) {
            String user = null;
            if (ErgoApplication.getUserManager() != null)
                user = ErgoApplication.getUserManager().getIfisUser();
            if (loader.getId() == WORKOUT_LOADER)
                user = null;
            weeklyView.fetchData(user);
        }
        Timber.e("Cursor returned %d entries ", data.getCount());
    } catch (Exception e) {

    }
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
    if (cursorAdapter != null)
        cursorAdapter.changeCursor(null);
}

@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
    Timber.d("Openening details of #%d", l);
    if (settings == null) {
        Timber.w("No - not openening .... activity is gone");
        return;
    }
    LogCatcher.dropBreadCrump("history-detail @" + l);
    HistoryDetailFragment mFragment = HistoryDetailFragment.newInstance(l);
    mFragment.setInteractionListener(this);
    mFragment.setSettingsCallback(settings);
    settings.onOpenSubFragmentRequest(mFragment);
}

@Override
public void onFragmentInteraction(Uri uri) {
    //getChildFragmentManager().popBackStack();
    Timber.d("Clicked onFragmentInteraction");
    FragmentManager mRef = getFragmentManager();
    if (mRef != null)
        mRef.popBackStack(); //remove the detail fragment
}

@Override
public void onDismiss(DialogInterface dialog) {
    super.onDismiss(dialog);
}

@Override
public void onDestroyView() {
    try {
        /**
         * Clear refs here since this view will be gone after this function returns
         */
        if (mLoaderManager != null) {
            mLoaderManager.destroyLoader(USER_LOADER);
            mLoaderManager.destroyLoader(WORKOUT_LOADER);
            mLoaderManager = null;
        }
        spinner = null;
        settings = null;
        //view = null;
        cursorAdapter = null;
        listView = null;
        weeklyView = null;
        emptyView = null;
        switcher = null;
    } catch (Exception err) {
        Timber.e(err, "failed to destroy view release");
    }
    super.onDestroyView();

}

}

Используя инспектор логов и макетов, я решил, что фрагмент раздувается с нулевой высотой и нулевым размером. HistoryFragment.onCreateView в этом случае никогда не вызывается.

В качестве обходного пути я заставил фрагмент «самовосстанавливаться», расширив этот базовый (DialogFragment) класс:

public class ErgoDialogFragment extends DialogFragment {
boolean hasInflatedProper = false;
private Runnable selfFix;
private Handler healHandler;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setStyle(STYLE_NO_FRAME, android.R.style.Theme_Holo_Light_NoActionBar_Fullscreen);
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    if (ErgoApplication.isAndroid9())
        view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, 
int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                Timber.d("Inflated history fragment has left = %d, 
top=%d, right =%d, bottom=%d", left, top, right, bottom);
                if (bottom != 800 && right != 1280) {
                    for (int i = 0; i < 10; i++)
                        Timber.e("HistoryFragment inflated, but not shown ! ");
                } else
                    hasInflatedProper = true;
                v.removeOnLayoutChangeListener(this);
            }
        });
}

@Override
public void onResume() {
    super.onResume();
    if (selfFix != null) {
        if (ErgoApplication.isAndroid9()) {
            //To be executed only for new tablets.....
            if (healHandler == null) {
                healHandler = new Handler();
                DefaultExecutorSupplier.getInstance().registerHandler("history_healing", healHandler);
            }
            healHandler.postDelayed(() -> {
                if (!hasInflatedProper) {
                    try {
                        if (selfFix != null)
                            selfFix.run();
                    } catch (Exception e) {
                        Timber.w(e, "Failed to self heal view.....");
                    }
                }
            }, 500);
        }
    }
}

public void addFixingRunnable(Runnable runner) {
    this.selfFix = runner;
}

@Override
public void onPause() {
    if (healHandler != null)
        healHandler.removeCallbacksAndMessages(null);
    super.onPause();
}

}

Если фрагмент не отображается должным образом - я открываю другой DialogFragment (см. AddFixingRunnable) и закрываю его через мгновение - в результате отображается желаемый фрагмент.

Кто-нибудь замечает, что я делаю не так ? Я хочу реализовать это правильно ....

Обозначьте: я ничего не делаю с фрагментами / supportFragmentManager в хостинге FragmentActivitys onPause / onResume

Для справки, это макет HistoryFragment:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/background_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/solid_white_transparency"
android:orientation="vertical"
tools:showIn="@layout/startmenu"
android:onClick="doNothing">

<de.ergo.frontend.custumviews.DialogHeader
    android:id="@+id/dialogHeader1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true">

</de.ergo.frontend.custumviews.DialogHeader>

<de.ergo.frontend.custumviews.Switcher
    android:id="@+id/mode_switcher"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignTop="@+id/dialogHeader1"
    android:layout_alignEnd="@+id/dialogHeader1"
    android:padding="15dp" />

<de.ergo.frontend.custumviews.WeekStatsView
    android:id="@+id/weekly_view"
    android:layout_width="match_parent"
    android:visibility="visible"
    android:layout_below="@id/dialogHeader1"
    android:layout_height="wrap_content">

</de.ergo.frontend.custumviews.WeekStatsView>
<ListView
    android:id="@+id/backgroundListView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clickable="false"
    android:divider="@color/invisible"
    android:layout_below="@id/weekly_view"
    android:dividerHeight="20dp"
    android:headerDividersEnabled="true"
    android:listSelector="@android:color/transparent"
    android:scrollbars="vertical"
    tools:listitem="@layout/item_workout_rowing"
    tools:visibility="invisible">

</ListView>

<ProgressBar
    android:id="@+id/spinner"
    style="?android:attr/progressBarStyleLarge"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    android:gravity="center"
    android:indeterminate="true" />
<TextView
    android:id="@+id/emptyView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginBottom="128dp"
    android:text="@string/history_empty_text"
    android:layout_below="@id/spinner"
    android:layout_centerHorizontal="true"
    android:gravity="center"
    android:textColor="@color/white"
    android:textSize="40sp" />

</RelativeLayout>

Я попытался переключиться обратно на обычный фрагмент без диалога. Также принудительное переопределение параметров макета жестко заданными значениями по-прежнему не работает. Я изменил цель фрагментов, например, на определенный держатель xml или с помощью android .R.id.content - все равно безуспешно.

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

Просвети меня, пожалуйста!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...