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