【问题标题】:Fragment with AsyncTaskLoader influence other fragments' attaching to the activity带有 AsyncTaskLoader 的 Fragment 影响其他 Fragment 附加到 Activity
【发布时间】:2012-02-10 18:41:33
【问题描述】:

我使用 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
    
    }
    

我真的不知道为什么会这样。

附:我在评论中制作代码块时遇到了一些问题,我认为它有错误,很抱歉。

提前致谢,埃拉德。

【问题讨论】:

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


    【解决方案1】:

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

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

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

    【讨论】:

    • 我理解你,我想我理解我的问题。我的应用程序中的每个片段都从我正在使用的 TitlePageIndicator 的资源中返回其名称(来自 sherlock 操作栏的创建者的非常好的库),当我有 3 个片段时,第三个片段还没有附加到活动,所以它可以'不要使用使用活动资源的 getString()。谢谢,我会用其他方式来做!
    • 您可能对支持库的 PagerTitleStrip 感兴趣;它从 PagerAdapter 中检索标题字符串,您可能会在其中有一个 Activity 引用,您可以使用它来获取这些字符串。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-14
    • 2012-10-23
    • 2019-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多