0

我使用AsyncTaskLoader从数据库查询加载游标。 我跟着Android开发者样本: http://developer.android.com/reference/android/content/AsyncTaskLoader.html带AsyncTaskLoader的片段影响其他片段附加到活动

但不知何故,正在添加到页面适配器该片段后(使用加载器)的碎片不会得到重视的活动,它会尝试当使用需要方法一个活动(如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. Initializng装载机:

    @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 
    
    } 
    

我真的不知道为什么会发生这种情况。

P.S.我在评论中遇到了一些问题,我觉得它有一个bug,所以很抱歉。

在此先感谢,Elad。

回答

2

简短的回答是,你永远不应该假设一个片段处于任何特定的状态,直到它收到相应的生命周期回调信号为止。

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

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

+0

我了解你,我想我理解我的问题。我的应用程序中的每个片段都从我使用的TitlePageIndicator的资源中返回它的名称(来自sherlock操作栏创建者的非常好的库),并且当我有3个片段时,第三个片段不会附加到活动,因此它可以不使用getString(),它使用活动的resorces。谢谢我会以其他方式做到这一点! – Elad92 2012-02-10 19:13:39

+0

您可能会对支持库的PagerTitleStrip有兴趣作为替代;它从PagerAdapter中检索标题字符串,你可能会有一个Activity引用可以用来获取这些字符串。 – adamp 2012-02-10 19:36:57