Фрагмент с AsyncTaskLoader влияет на прикрепление других фрагментов к активности - PullRequest
0 голосов
/ 10 февраля 2012

Я использовал AsyncTaskLoader для загрузки курсора из запроса к базе данных.Я следовал примеру Android Developers: http://developer.android.com/reference/android/content/AsyncTaskLoader.html

Но почему-то фрагменты, которые добавляются в адаптер страницы после этого фрагмента (который использует загрузчик), не привязываются к действию и когда он пытается использовать методыкоторому нужно действие (например, getString ()), генерируется исключение, которое говорит, что этот фрагмент не привязан ни к какому действию.

Вот некоторый код:

  1. Добавление фрагментов в адаптер страницы.

    mAdapter = new PlaceFragmentPagerAdapter(getSupportFragmentManager());
    
    
    NewFragment newFrag = new NewFragment();
    mAdapter.addFragment(newShiftFrag);
    
    ListFragment listFrag = new ListFragment();
    mAdapter.addFragment(listFrag);
    
    SettingsFragment settingsFrag = new SettingsFragment();
    mAdapter.addFragment(settingsFrag);
    
    mPager = (ViewPager)findViewById(R.id.pager);
    mPager.setAdapter(mAdapter);
    
  2. Реализация AsyncTaskLoader:

    абстрактный открытый класс AbstractCursorLoader extends AsyncTaskLoader {

        abstract protected Cursor buildCursor();
        Cursor lastCursor=null;
    
        public AbstractCursorLoader(Context context) {
            super(context);
        }
    
        /** 
         * Runs on a worker thread, loading in our data. Delegates
         * the real work to concrete subclass' buildCursor() method. 
         */
        @Override
        public Cursor loadInBackground() {
            Cursor cursor=buildCursor();
    
            if (cursor!=null) {
                // Ensure the cursor window is filled
                cursor.getCount();
            }
    
            return(cursor);
        }
    
        /**
         * Runs on the UI thread, routing the results from the
         * background thread to whatever is using the Cursor
         * (e.g., a CursorAdapter).
         */
        @Override
        public void deliverResult(Cursor cursor) {
            if (isReset()) {
                // An async query came in while the loader is stopped
                if (cursor!=null) {
                    cursor.close();
                }
    
                return;
            }
    
            Cursor oldCursor=lastCursor;
            lastCursor=cursor;
    
            if (isStarted()) {
                super.deliverResult(cursor);
            }
    
            if (oldCursor!=null && oldCursor!=cursor && !oldCursor.isClosed()) {
                oldCursor.close();
            }
        }
    
        /**
         * Starts an asynchronous load of the list data.
         * When the result is ready the callbacks will be called
         * on the UI thread. If a previous load has been completed
         * and is still valid the result may be passed to the
         * callbacks immediately.
         * 
         * Must be called from the UI thread.
         */
        @Override
        protected void onStartLoading() {
            if (lastCursor!=null) {
                deliverResult(lastCursor);
            }
            if (takeContentChanged() || lastCursor==null) {
                forceLoad();
            }
        }
    
        /**
         * Must be called from the UI thread, triggered by a
         * call to stopLoading().
         */
        @Override
        protected void onStopLoading() {
            // Attempt to cancel the current load task if possible.
            cancelLoad();
        }
    
        /**
         * Must be called from the UI thread, triggered by a
         * call to cancel(). Here, we make sure our Cursor
         * is closed, if it still exists and is not already closed.
         */
        @Override
        public void onCanceled(Cursor cursor) {
            if (cursor!=null && !cursor.isClosed()) {
                cursor.close();
            }
        }
    
        /**
         * Must be called from the UI thread, triggered by a
         * call to reset(). Here, we make sure our Cursor
         * is closed, if it still exists and is not already closed.
         */
        @Override
        protected void onReset() {
            super.onReset();
    
            // Ensure the loader is stopped
            onStopLoading();
    
            if (lastCursor!=null && !lastCursor.isClosed()) {
                lastCursor.close();
            }
    
            lastCursor=null;
        }
    }
    
        private static class ListLoader extends AbstractCursorLoader {
            private String mName;
    
            public ShiftsListLoader(Context context, String name) {
                super(context);
                mName = name;
            }
    
            @Override
            protected Cursor buildCursor() {
                PlacesHandler wph = new PlacesHandler(this.getContext());
                return wph.GetShifts(mName);
            }
        }
    
  3. Инициализация загрузчика:

        @Override 
        public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    
        // Give some text to display if there is no data.  In a real
        // application this would come from a resource.
        // TODO change to resource and back
        setEmptyText("Nothing here..");
    
        // Start out with a progress indicator.
        setListShown(false);
    
    
    
        // Prepare the loader.  Either re-connect with an existing one,
        // or start a new one.
        getLoaderManager().initLoader(0, null, this);
    

    }

        @Override
        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
            return new ListLoader(getActivity(), mWorkPlaceName);
        }
        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
            // Create an empty adapter we will use to display the loaded data.
        mAdapter = new ListCursorAdapter(getActivity(), data, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
        setListAdapter(mAdapter);
    
        }
    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        // TODO Auto-generated method stub
    
    }
    

Я действительно понятия не имею, почему это происходит.

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

Заранее спасибо, Elad.

1 Ответ

2 голосов
/ 10 февраля 2012

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

То, что вы видите, это добавленная оптимизация во время ICS, которой ViewPager пользуетсяиз.FragmentPagerAdapter специально помечает фрагменты за пределами экрана как невидимые для пользователя, вызывая setUserVisibleHint .FragmentManager использует это для определения приоритетов выполнения загрузчиков, чтобы пользователь сначала увидел полностью загруженную видимую страницу, а загрузка боковых страниц не замедляет процесс загрузки видимой страницы.В частности, он задерживает перемещение фрагмента в состояние «запущено», что также происходит, когда запускаются загрузчики.

Если пользователь прокручивает страницу на другую страницу во время процесса, FragmentManager переместит фрагмент в запущенныйи немедленно запустите его загрузчики как часть FragmentPagerAdapter # setPrimaryItem (), поскольку этот метод помечает текущую страницу как видимую для пользователя.

...