使用AsyncTaskLoader的片段会影响附加到活动的其他片段

时间:2012-02-10 18:41:33

标签: android android-fragments android-asynctask android-cursorloader asynctaskloader

我使用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扩展了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
    
    }
    
  4. 我真的不知道为什么会这样。

    P.S。我在评论中制作代码块时遇到了一些问题,我发现它有一个bug,很抱歉。

    提前谢谢,Elad。

1 个答案:

答案 0 :(得分:2)

简短的回答是,在收到适当的生命周期回调信号之前,你永远不应该假设某个片段处于任何特定状态。

您所看到的是在ViewPager利用的ICS期间添加的优化。 FragmentPagerAdapter通过调用setUserVisibleHint特别标记屏幕外片段,因为用户不可见。 FragmentManager使用它来优先处理加载器的执行方式,以便用户首先看到完全加载的可见页面,加载侧页不会减慢加载可见页面的过程。具体来说,它会延迟将片段移动到“已启动”状态,也就是当加载器开始运行时。

如果用户在此过程中滚动到另一个页面,FragmentManager会将片段移动到启动状态并立即开始运行其加载器作为FragmentPagerAdapter#setPrimaryItem()的一部分,因为此方法将当前页面标记为现在用户可见。