15

的每一頁上運行,我有3個選項卡像android development tutorial的AsyncTask的ViewPager

現在我想要做的是非常簡單的我用碎片在每一頁上。我想在每個頁面上顯示來自RSS源的不同內容。

問題是,當我轉到下一個選項卡時,它運行前一個Fragment的AsyncTask(它在onCreateView中)。

因此,您從第1頁開始,它會將內容加載得很好。然後當你去第2頁時再次運行頁面片段的onCreateView。顯然給了一個NullException。關鍵是它不應該在第1頁運行AsyncTask,而是在第2頁。

我不認爲有任何示例代碼需要,如果是這樣告訴我你需要看哪個部分。然後我會編輯我的問題。

的AsyncTask一個ListFragment內:

public class MyAsyncTask extends AsyncTask<List<String>, Void, List<String>> 
{ 
    // List of messages of the rss feed 
    private List<Message> messages; 
    private volatile boolean running = true; 

    @SuppressWarnings("unused") 
    private WeakReference<NieuwsSectionFragment> fragmentWeakRef; 

    private MyAsyncTask(NieuwsSectionFragment fragment) 
    { 
     this.fragmentWeakRef = new WeakReference<NieuwsSectionFragment>(fragment); 
    } 
    @Override 
    protected void onPreExecute() 
    { 
     super.onPreExecute(); 

     mProgress.show(); 
     // progress.setVisibility(View.VISIBLE); //<< set here 
    } 
    @Override 
    protected void onCancelled() 
    { 
     Log.w("onCancelled", "now cancelled"); 
     running = false; 
    } 
    @Override 
    protected List<String> doInBackground(List<String>... urls) 
    { 
     FeedParser parser = FeedParserFactory.getParser(); 
     messages = parser.parse(); 
     List<String> titles = new ArrayList<String>(messages.size()); 
     for (Message msg : messages) 
     { 
      titles.add(msg.getTitle()); 
      // Log.w("doInBackground", msg.getTitle()); 
     } 
     return titles; 
    } 

    @Override 
    protected void onPostExecute(List<String> result) 
    { 
     super.onPostExecute(result);    
     mProgress.dismiss(); 
     if (result != null) 
     { 
      PostData data = null; 
      listData = new PostData[result.size()]; 
      for (int i = 0; i < result.size(); i++) 
      { 
       data = new PostData();     
       data.postTitle = result.get(i); 
       data.postThumbUrl = "http://igo.nl/foto/app_thumb/28991-Taxi-vast-na-poging-tot-nemen-van-sluiproute.jpg";     
       listData[i] = data; 
       Log.w("onPostExecute", "" + listData[i].postTitle); 
      } 
      adapter = new PostItemAdapter (getActivity(), android.R.layout.simple_list_item_1, listData);    
      setListAdapter(adapter); 
      adapter.notifyDataSetChanged(); 
     } 
    } 
} 

這就是所謂的方法內部和ListFragment的onCreateView內部執行的方法:

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
{ 
    startNewAsyncTask(); 
    View rootView = inflater.inflate(R.layout.fragment_section_nieuws, container, false); 
    return rootView; 
} 

@SuppressWarnings("unchecked") 
public void startNewAsyncTask() 
{  
    MyAsyncTask asyncTask = new MyAsyncTask(this); 
    this.asyncTaskWeakRef = new WeakReference<MyAsyncTask>(asyncTask); 
    asyncTask.execute(); 
} 

的logcat的: logcat

+0

請發佈您的代碼和登錄貓! –

+0

我不知道自從加載內容的第一頁起,您想看到哪部分代碼。 logcat在頁面上運行'AsyncTask'時只會給出'NullPointerException',因爲它不應該運行它,這是邏輯的。 – Shishi

+0

發佈您的異步任務和一段代碼,其中調用from ..Along與您的日誌貓錯誤.Error必須指出空行指針發生的行。該部分還 –

回答

2

移動您的

startNewAsyncTask(); 

到onActivityCreated()

+0

同樣的事情發生時,轉到下一個選項卡它運行'AsyncTask'。 – Shishi

0

棘手的點這裏是事實,你去下一個片段(Fragment 2)後,AsyncTaskFragment 1仍在運行。你可能會想:「好吧,在這種情況下,我會阻止我的AsyncTaskonDestroyView,例如」,但另一個棘手的事實是,在撥打.cancel方法後,AsyncTask不會立即停止。因此,問題是:在onPostExecute上,您引用了切換到Fragment 2後不存在的資源。讓我們在ArrayAdapter:310一看:

mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 

很顯然,這是contextnull。讓我們更深入地看看getActivity方法 - 它只是返回mActivity字段的值。

在這種情況下,爲什麼它null?因爲一旦Fragment已被刪除,FragmentManager電話initState,其中刪除鏈接到Activity對象明確

void initState() { 
    ... 
    mActivity = null; 
    ... 
} 

如何從NPE保護?總是檢查getActivity的結果onPostExecutenull

0

由於您太早打電話給getActivity(),您會收到該例外情況。您應該在onActivityCreated()(請參閱this diagram

在後臺執行onCreateView()罰款,實際上是默認行爲。問題是,ViewPager已經過優化,可以在後臺加載鄰居不可見頁面的內容以提高UX。您可以這樣做: mViewPager.setOffscreenPageLimit(2);(默認值爲1)一次加載所有3個頁面(1加載爲當前可見,其他2加載爲優化)。或者將其設置爲0以禁用此行爲,但這不是最好的主意。

通常情況下,您應該爲已加載的數據提供現金,並且不要通過儘量減少片段的生命週期方法來加載它。 2的頁面限制對於3頁是好的,但是如果你有例如10頁,則限制9太多。

0

如果我明白你的問題吧,我想你需要與每個片斷正確的獨特的內容?

嘗試使用execute方法的變量參數。例如:

yourTask.execute(<some-unique-URL>, parameter, one-more-parameter); 

通過這種方式,你可以通過每個片段形式獨特的URL,你可以讓你的內容。 我覺得你已經擁有了這個。 doInBackground方法具有URL列表。你只需要在execute方法中傳遞這些信息並在doInBackground中使用它。

希望這會有所幫助!

0

這是正常的,它運行從相鄰FragmentsAsyncTask,因爲ViewPager + PagerAdapter組合,作品加載當前,過去和未來Fragment

您應該關注問題,不要停止AsyncTask運行,而是讓它運行而不會拋出NullPointerException

下應該叫內onCreateView()

adapter = new PostItemAdapter (getActivity(), android.R.layout.simple_list_item_1, myList);    
setListAdapter(adapter); 

然後,onPostExecute()

myList.clear(); 
myList.addAll(listData); 
adapter.notifyDataSetChanged(); 
1

我假設你使用FragmentPagerAdapterViewPager

要啓用流暢的動畫,ViewPager默認保持當前片段和兩個鄰居處於恢復狀態。所以onCreateView不是開始AsyncTask的最佳地點。

相反,您需要創建一個自定義偵聽器接口。 ViewPager中的fragments應該實現它,並從ViewPager'sOnPageChangeListener調用新的接口。

查看我的回答this question或者您可以閱讀整個教程here

0

ViewPager將爲相鄰頁面中的片段創建視圖並銷燬與當前頁面不相鄰的片段的視圖。因此,如果您從page1-> page2-> page3-> page2進行導航,則頁面1的onCreateView將會被調用。通過使用ViewPager.setOffscreenPageLimit,您可以讓viewpager在內存中保留更多頁面。

fragmentPagerAdapter保留片段對象。只有意見被破壞。因此,當viewpage重新創建page1的視圖時,fragment對象是相同的。因此,片段中的所有字段將被保留。 與大多數沒有實時數據的應用程序一樣,每次創建片段視圖時不需要加載數據,您可以在加載後將數據存儲在片段對象中。然後,在啓動onCreateView/onActivityCreated中的AsyncTask之前,檢查數據是否已經先前加載過。

class PageFragment { 

private List<String> mData; 

... 
void onActivityCreated() { 
    if (data == null) { // OR if the data is expired 
     startAsyncTask(); 
    } else { 
     updateViews(); 
    } 
} 

void updateViews() { 
    // Display mData in views 
} 

class LoadDataTask extends AsyncTask<List<String>, ..., ...> { 

    ... 
    void onPostExecute(List<String> result) { 
     PageFragment.this.mData = result; 
     PageFragment.this.updateViews(); 
    } 
} 

我建議您使用加載器來加載片段的數據。出於您的目的,您可以配置加載程序以僅加載一次數據。 這是一個關於裝載機的好教程。 http://www.androiddesignpatterns.com/2012/07/loaders-and-loadermanager-background.html

在本教程中,加載程序配置爲立即返回以前的數據(如果可用),然後在後臺獲取數據並在獲取完成後返回數據。因此,新的數據下載後UI將會更新,但同時它會在下載發生時顯示最初的數據。

0

您可以使用其他活動 - 此活動將運行asynctask,然後移至片段相關活動。通過這種方式,它只應該調用一次。

如果您需要使用此AsyncTask更新Fragment UI,請使用靜態方法通過AsyncTask進行調用。

相關問題