2011-02-16 73 views
4

我有一個問題,我一直無法弄清楚,它只發生在設備運行< 2.1。它在Android 2.2上正常工作。我有一個ansync任務,它在加載所有選項卡時顯示一個加載對話框。下面是TabActivity代碼:Android 2.1 NullPointerException與TabWidgets

public class OppTabsView extends TabActivity { 
Dialog dialog; 
String errorText; 
boolean save; 
final int OPP_SAVE = 0; 
public static boolean edited; 

public void onCreate(Bundle icicle) { 

    try { 
     super.onCreate(icicle); 
     new DoInBackground().execute(); 

    } catch (Exception e) { 
     Toast.makeText(this, "Error occured. Please try again later.", 
       Toast.LENGTH_SHORT).show(); 

    } 

} 

@Override 
protected void onResume() { 
    super.onResume(); 
} 

@Override 
protected void onStop() { 
    super.onStop(); 

} 

@Override 
protected void onPause() { 
    super.onPause(); 

} 

public boolean onCreateOptionsMenu(Menu menu) { 
    menu.add(0, OPP_SAVE, 0, "Test"); 
    return true; 
} 

public boolean onOptionsItemSelected(MenuItem item) { 

    switch (item.getItemId()) { 

    case OPP_SAVE: 
     save = true; 
     new DoInBackground().execute(); 

     return true; 

    } 

    return false; 

} 

public void LoadOpp() { 
    handler.sendEmptyMessage(0); 
} 

public void SaveOpp() { 
    DoStuff(); 

} 

public void LoadLayout() { 
    setContentView(R.layout.view_opptabs); 

    /* TabHost will have Tabs */ 
    TabHost tabHost = (TabHost) findViewById(android.R.id.tabhost); 

    /* 
    * TabSpec used to create a new tab. By using TabSpec only we can able 
    * to setContent to the tab. By using TabSpec setIndicator() we can set 
    * name to tab. 
    */ 

    /* tid1 is firstTabSpec Id. Its used to access outside. */ 
    TabSpec firstTabSpec = tabHost.newTabSpec("tid1"); 
    TabSpec secondTabSpec = tabHost.newTabSpec("tid1"); 
    TabSpec thirdTabSpec = tabHost.newTabSpec("tid1"); 

    /* TabSpec setIndicator() is used to set name for the tab. */ 
    /* TabSpec setContent() is used to set content for a particular tab. */ 

    firstTabSpec.setIndicator("General", 
      getResources().getDrawable(R.drawable.tab_moneybag)) 
      .setContent(new Intent(this, OppTabGeneral.class)); 
    secondTabSpec.setIndicator("Details", 
      getResources().getDrawable(R.drawable.tab_papers)).setContent(
      new Intent(this, OppTabDetails.class)); 
    thirdTabSpec.setIndicator("Contact", 
      getResources().getDrawable(R.drawable.tab_contact)).setContent(
      new Intent(this, OppTabContact.class)); 

    /* Add tabSpec to the TabHost to display. */ 
    tabHost.addTab(firstTabSpec); 
    tabHost.addTab(secondTabSpec); 
    tabHost.addTab(thirdTabSpec); 

} 

private void do_update() { 
    if (save) { 
     SaveOpp(); 
    } else { 
     LoadOpp(); 
    } 
} 

Handler handler = new Handler() { 
    public void handleMessage(Message msg) { 
     LoadLayout(); 
    } 
}; 

private class DoInBackground extends AsyncTask<Void, Void, Void> implements 
     DialogInterface.OnCancelListener { 

    protected void onPreExecute() { 

     String verb = "Connecting"; 
     if (save) { 
      verb = "Saving"; 
     } 
     dialog = ProgressDialog.show(OppTabsView.this, "", verb 
       + ". Please Wait...", true, true, this); 
    } 

    protected Void doInBackground(Void... v) { 
     do_update(); 
     return null; 
    } 

    protected void onPostExecute(Void v) { 
     dialog.dismiss(); 


    } 

    public void onCancel(DialogInterface dialog) { 
     cancel(true); 
     dialog.dismiss(); 
     finish(); 
    } 
} 
} 

下面是錯誤的堆棧跟蹤:

java.lang.NullPointerException 
at android.widget.TabWidget.dispatchDraw(TabWidget.java:206) 
at android.view.ViewGroup.drawChild(ViewGroup.java:1529) 
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258) 
at android.view.ViewGroup.drawChild(ViewGroup.java:1529) 
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258) 
at android.view.ViewGroup.drawChild(ViewGroup.java:1529) 
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258) 
at android.view.View.draw(View.java:6538) 
at android.widget.FrameLayout.draw(FrameLayout.java:352) 
at android.view.ViewGroup.drawChild(ViewGroup.java:1531) 
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258) 
at android.view.ViewGroup.drawChild(ViewGroup.java:1529) 
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258) 
at android.view.View.draw(View.java:6538) 
at android.widget.FrameLayout.draw(FrameLayout.java:352) 
at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1830) 
at android.view.ViewRoot.draw(ViewRoot.java:1349) 
at android.view.ViewRoot.performTraversals(ViewRoot.java:1114) 
at android.view.ViewRoot.handleMessage(ViewRoot.java:1633) 
at android.os.Handler.dispatchMessage(Handler.java:99) 
at android.os.Looper.loop(Looper.java:123) 
at android.app.ActivityThread.main(ActivityThread.java:4363) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:521) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) 
at dalvik.system.NativeStart.main(Native Method) 

我試圖通過它加強,但錯誤似乎出來沒有在那裏,不一條特定的路線。任何幫助是極大的讚賞。

+0

哪一行代碼做這點:`顯示java.lang.NullPointerException在android.widget.TabWidget.dispatchDraw(TabWidget.java:206)` – 2011-02-16 23:22:04

+0

線206對do_update功能 – ninjasense 2011-02-16 23:24:28

+0

我一直在拉大括號此代碼分開,看起來像,因爲其他選項卡依賴於TabActivity拉動的信息,TabActivity必須在加載選項卡之前完成。在android 2.2中,數據是異步加載的,在2.1中它不會導致錯誤。唯一的方法,我知道如何通過處理程序來做到這一點,似乎並沒有在工作2.1 – ninjasense 2011-02-17 19:44:10

回答

1
TabSpec firstTabSpec = tabHost.newTabSpec("tid1"); 
TabSpec secondTabSpec = tabHost.newTabSpec("tid1"); 
TabSpec thirdTabSpec = tabHost.newTabSpec("tid1"); 

您是否允許爲多個TabSpec使用相同的「標籤」?我會嘗試設置正確的,看看它是否修復它。

編輯:好吧,所以我的建議並沒有解決它,但無論如何它有獨特的標籤是有道理的。

試試這個看看是否有幫助。添加選項可以設置當前選擇的標籤在你LoadLayout()方法,像這樣結束(見最後一行)...

/* Add tabSpec to the TabHost to display. */ 
tabHost.addTab(firstTabSpec); 
tabHost.addTab(secondTabSpec); 
tabHost.addTab(thirdTabSpec); 

tabHost.setCurrentTab(0); // <== Add this 

EDIT2:我發現TabWidget.java源和線206(其中NullPointerException異常發生時)是...

mBottomLeftStrip.setState(selectedChild.getDrawableState());

...有,我可以看到異常的三種可能的原因。

  1. mBottonLeftStrip爲空(可能性很小)
  2. selectedCHild爲空(TabWidget應該默認爲孩子0和使用tabHost.setCurrentTab()將執行的是反正)
  3. selectedChild.getDrawableState()結果是空

最後似乎是可能的原因,但我不知道什麼可能導致它返回null。

試試谷歌的'TabWidget.java源' - 第二個結果指向grepcode.com,它有行號,你可以看到它在異常點上試圖做什麼。

1

與從1.6和2.1上的AsyncTask填充的選項卡有相同的問題。看起來像早期版本不喜歡沒有任何標籤的TabHost。爲了解決這個問題,我不使用TabActivity並在AsyncTask的onPostExecute函數中手動創建TabHost及其所有層次結構。

1

一個簡單的解決方案是將tabWidget可見性設置爲在佈局

<TabWidget 
    android:id="@android:id/tabs" 
    android:orientation="horizontal" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_weight="0" 
    android:visibility="gone" /> 

然後,一旦你定義了你的標籤內容,你可以把它再次可見:

// Add tab content (here a fragment class) 
tabHost.addTab(
    tabHost.newTabSpec("tag1").setIndicator("Title"), 
    contentFragment.class, 
    null); 

// Set tabWidget visible again 
tabWidget.setVisibility(View.VISIBLE); 
0

受相關TabHost答案之一的啓發:

public class FixedTabHost extends FragmentTabHost 
{ 
    public FixedTabHost(Context context, AttributeSet attrs) 
    { 
     super(context, attrs); 
    } 

    @Override 
    protected void dispatchDraw(Canvas canvas) 
    { 
     try { super.dispatchDraw(canvas); } 
     catch (Exception ignored) {} 
    } 
} 

爲我工作。