2013-05-13 67 views
1

我有一個應用程序使用NumberPicker s。由於該應用支持較舊版本的Android,但尚未提供NumberPicker小部件,因此我必須使用external library爲什麼將net.simonvt.numberpicker.NumberPicker強制轉換爲android.widget.NumberPicker?

在我的XML佈局numberpicker_dialog.xml,我定義了NumberPicker這樣的:

<net.simonvt.numberpicker.NumberPicker 
    android:id="@+id/interval_picker_1" 
    ... /> 

然後在我的活動的代碼,我有:

import net.simonvt.numberpicker.NumberPicker; 

private View intervalPickerDialogBody; 
private NumberPicker intervalPicker1; 
private android.widget.NumberPicker api11_intervalPicker1; 

protected void onCreate(Bundle savedInstanceState) { 

    intervalPickerDialogBody = getLayoutInflater() 
      .inflate(R.layout.numberpicker_dialog, null); 

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 
     // the casting in question happens here 
     api11_intervalPicker1 = (android.widget.NumberPicker) 
       intervalPickerDialogBody.findViewById(R.id.interval_picker_1); 
    } else { 
     intervalPicker1 = (NumberPicker) 
       intervalPickerDialogBody.findViewById(R.id.interval_picker_1); 
    } 

} 

它的工作原理,真正的蜂窩並較新版本,使用android.widget.NumberPicker,在舊版本中使用net.simonvt.numberpicker.NumberPicker

但現在,我正在寫有關使用此應用的論文,我在想:

  1. 爲什麼從XML佈局鑄造net.simonvt.numberpicker.NumberPicker當他們在現實中是不同類android.widget.NumberPicker工作?
  2. 爲什麼只有這種鑄造使設備在Honeycomb上使用android.widget.NumberPicker而在XML佈局中的NumberPicker實際上是來自exetrnal庫的設備時更新?什麼時候創建android.widget.NumberPicker的實例?

android.widget.NumberPicker用在蜂窩和更新是由事實forecoming代碼片段的第二行我4.0.3手機等於true支持的事實。

View tmp = intervalPickerDialogBody.findViewById(R.id.interval_picker_1); 
tmp instanceof android.widget.NumberPicker // pseudocode 

(謝謝你,朱爾斯,這比刪除線用一個箭頭一個更好的證明。:))

如果有人想知道我是怎麼知道的 android.widget.NumberPicker實際上是在Honeycomb和較新的使用,這是因爲 net.simonvt.numberpicker.NumberPicker不顯示箭頭上方和下方的箭頭,因爲它已從4.2中移除,箭頭已被刪除。當我在運行4.0.3的設備上嘗試它時,即使它應該顯示 net.simonvt.numberpicker.NumberPicker,它們也不會顯示,但箭頭仍然存在。

我希望這個問題是可以理解的。感謝您對這個主題的闡述。

回答

1

有趣的問題。這似乎是因爲我認爲是LayoutInflater中的一個錯誤。下面是用來決定什麼View類是用於特定的XML標記代碼:

public final View createView(String name, String prefix, AttributeSet attrs) 
     throws ClassNotFoundException, InflateException { 
    Constructor constructor = sConstructorMap.get(name); 
    Class clazz = null; 

    try { 
     if (constructor == null) { 
      // Class not found in the cache, see if it's real, and try to add it 
      clazz = mContext.getClassLoader().loadClass(
        prefix != null ? (prefix + name) : name); 

      if (mFilter != null && clazz != null) { 
       boolean allowed = mFilter.onLoadClass(clazz); 
       if (!allowed) { 
        failNotAllowed(name, prefix, attrs); 
       } 
      } 
      constructor = clazz.getConstructor(mConstructorSignature); 
      sConstructorMap.put(name, constructor); 
     } 
     ... 

在此之前被調用,前綴(即一切直至幷包括在標籤名稱的最後一個點)被分離出來,投入前綴參數,所以對於你的XML,電話是:

createView ("NumberPicker", "net.simonvt.numberpicker.", ...); 

這意味着,當在高速緩存中先前使用的構造函數CreateView的方法檢查,只要NumberPicker之前已使用它將返回系統NumberPicker。

作爲我相信這是一個錯誤的必然結果,我會修改上面的代碼以防止Android的未來變體通過測試哪些類型的對象由findViewById使用instanceof返回來修復錯誤的可能性運營商,而不是你的當前版本號測試,即:

View tmp = intervalPickerDialogBody.findViewById(R.id.interval_picker_1); 
if (tmp instanceof android.widget.NumberPicker) { // Note 1 below 
    api11_intervalPicker1 = (android.widget.NumberPicker) 
      intervalPickerDialogBody.findViewById(R.id.interval_picker_1); 
} else { 
    intervalPicker1 = (NumberPicker) 
      intervalPickerDialogBody.findViewById(R.id.interval_picker_1); 
} 

注1就是我正在做的假設,instanceof檢查將在運行時不崩潰,如果你檢查,對沒有按」類不存在。如果是這樣,你必須改變檢查順序。

+0

謝謝你的闡述。我猜你是對的。問題是即使使用你的代碼,如果'LayoutInflater'的錯誤得到解決,應用程序很可能會崩潰,因爲我的應用程序後來指望'api11_intervalPicker1'在蜂窩或更新版本上運行時被初始化......我想我會只需要一種更好的方式來在不同的Android版本中使用具有相同名稱的不同類。我現在就會這樣離開它,因爲它是一個無人使用的應用程序。 – zbr 2013-05-13 15:25:20

相關問題