Подтвердить что ты не робот

Обновление представления внутри фрагмента

Я искал многочисленные вопросы, которые похожи на этот, но не нашел ответа ни в одном из них.

У меня есть активность, которая имеет 3 вкладки, доступные через панель действий. Я достиг этого, добавив 3 фрагмента, которые раздувают пользовательский вид, который я сделал, расширяя класс представления.

В настоящий момент база данных изменяется, я пытаюсь обновить представление на моей вкладке, вызывая invalidate()/postinvalidate(), но это не работает. То же самое верно для вызова onCreateView фрагмента так же, как и многие другие варианты, которые я рассматривал.

Когда я перехожу на другую вкладку и вернусь, это изменение было внесено, и мое представление обновлено, как и должно быть.

Как смоделировать то же самое, что происходит при переходе на другую вкладку? Что происходит. Я попытался посмотреть жизненный цикл Fragment (попробовал вызвать onCreateView()), чтобы понять это, но он просто не хочет обновлять/перерисовывать, как и должно быть.

Данные загружаются правильно, так как данные меняются при переходе на другую вкладку.

Я удалил часть кода, поскольку он больше не подходит. Я применил Cursorloaders вместо своего собственного шаблона Observer, чтобы уведомить об изменении. Это моя основная деятельность прямо сейчас.

Вопрос в том, что мне теперь делать, если я хочу перерисовать представление внутри этих фрагментов. Если я применил функцию fragmentObject.getView(). Invalidate(), это не сработает. У меня такая же проблема, как раньше, но теперь мой Observer уведомляет об изменениях в базе данных, правильно реализован с загрузчиками.

public class ArchitectureActivity extends Activity implements LoaderManager.LoaderCallbacks<Cursor> {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);     
    setContentView(R.layout.main);

    ActionBar actionbar = getActionBar();
    actionbar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    ActionBar.Tab EditTab = actionbar.newTab().setText("Edit");
    ActionBar.Tab VisualizeTab = actionbar.newTab().setText("Visualize");
    ActionBar.Tab AnalyseTab = actionbar.newTab().setText("Analyse");

    Fragment editFragment = new EditFragment();
    Fragment visualizeFragment = new VisualizeFragment();
    Fragment analyseFragment = new AnalyseFragment();

    EditTab.setTabListener(new MyTabsListener(editFragment));
    VisualizeTab.setTabListener(new MyTabsListener(visualizeFragment));
    AnalyseTab.setTabListener(new MyTabsListener(analyseFragment));

    actionbar.addTab(EditTab);
    actionbar.addTab(VisualizeTab);
    actionbar.addTab(AnalyseTab);

    ArchitectureApplication architectureApplication = (ArchitectureApplication)getApplicationContext();
    architectureApplication.initialize();

    getLoaderManager().initLoader(0, null, this);
    getLoaderManager().initLoader(1, null, this);
}

public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    if (id == 0){
        return new CursorLoader(this, GraphProvider.NODE_URI , null, null, null, null);
    } else if (id == 1){
        return new CursorLoader(this, GraphProvider.ARC_URI , null, null, null, null);
    }
    return null;
}

public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    // Reloading of data, actually happens because when switching to another tab the new data shows up fine
    Log.e("Data", "loaded");
}

public void onLoaderReset(Loader<Cursor> loader) {
}
}
4b9b3361

Ответ 1

Я нашел обходное решение для обновления представления внутри моего фрагмента. Я обновлял (новый CustomView) просмотр каждый раз, когда база данных обновлялась. После этого я вызываю setContentView (представление CustomView). Это больше похоже на взлом, но он работает, и ничего другого, что я пробовал, делает.

Хотя моя проблема не была фактически решена, я отдал награду Алексу Локвуду. Его совет по Loaders сделал мое приложение лучше, и это заставило меня продолжать искать решение, которое я в конце концов нашел.

Ответ 2

  • Не пытайтесь вызвать onCreateView() самостоятельно... это метод жизненного цикла и должен быть вызван только каркасом.

  • Fragment являются повторно используемыми компонентами пользовательского интерфейса. Они имеют собственный жизненный цикл, отображают собственное представление и определяют свое поведение. Обычно вам не нужно иметь беспорядок вокруг Activity с внутренними работами Fragment, так как поведение Fragment должно быть самодостаточным и не зависит от какого-либо конкретного Activity.

    Тем не менее, я считаю, что лучшим решением является использование каждого из Fragment интерфейса LoaderManager.LoaderCallbacks<D>. Каждый Fragment инициализирует Loader (т.е. A CursorLoader, если вы используете ContentProvider, поддерживаемый базой данных SQLite), и что Loader будет отвечать за (1) загрузку данных на фоне поток и (2) прослушивание изменений содержимого, которые сделаны в источнике данных, и доставка новых данных в onLoadFinished() всякий раз, когда происходит изменение содержимого.

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

  • Если вы ленивы и хотите получить быстрое решение, вы можете уйти с обновлением представления в вашем методе Fragment onResume().

Ответ 3

У меня была аналогичная (хотя и не идентичная) проблема, которую я мог решить следующим образом:

В фрагменте я добавил

public void invalidate() {
    myView.post(new Runnable() {
        @Override
        public void run() {
            myView.invalidate();
        }
    });
}

и я вызвал этот метод из активности, когда захотел обновить представление myView фрагмента. Использование post() гарантирует, что представление будет только отменено, когда оно будет готово к рисованию.

Ответ 4

У меня была такая же проблема. Мое решение было отделить фрагмент и снова прикрепить его.

        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        Fragment f = getFragment(action);
        if(forceUpdate)
        {
            fragmentTransaction.detach(f);
            fragmentTransaction.attach(f);
        }
        fragmentTransaction.replace(R.id.mainFragment, f);
        fragmentTransaction.commit();
        currentAction = action;

Ответ 5

Самое быстрое решение для меня:

 @Override
    public void onPause() {
        super.onPause();
        if (isRemoving() && fragmentView != null) {
            ((ViewGroup) fragmentView).removeAllViews();
        }
    }