1. 程式人生 > >Android 重寫 getViewTypeCount()陣列越界異常

Android 重寫 getViewTypeCount()陣列越界異常

由於自定義listview和多種item佈局的需求,我一如既往的在我的介面卡中重寫了

getViewTypeCount()、getItemViewType(int position)、getView()等方法
在getView()中通過對不同型別值的item進行不同的佈局處理,程式碼片段如下:
@Override
public int getViewTypeCount() {
    return 3;
}

@Override
public int getItemViewType(int position) {
    return adapterDataList.get(position).getType();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
... ...
... ...
switch (type) {case 21://小圖視訊
convertView = LayoutInflater.from(context).inflate(R.layout.layout_simple_item_type1, null);
        holder.titleType1 = (TextView) convertView.findViewById(R.id.tvItemType1);
        holder.imageType1 
= (ImageView) convertView.findViewById(R.id.imageItemType1); holder.assist1 = (TextView) convertView.findViewById(R.id.nice1); holder.pubTime1 = (TextView) convertView.findViewById(R.id.putTime1); ViewGroup.LayoutParams paramsImg = holder.imageType1.getLayoutParams(); paramsImg.width
= imgWidth1Of3; paramsImg.height = (int) (imgWidth1Of3 * DisplayUtils.goldenRatio + 0.5f); holder.imageType1.setLayoutParams(paramsImg); ViewGroup.LayoutParams paramsText = holder.titleType1.getLayoutParams(); paramsText.width = DisplayUtils.calcMultipleWidth(getContext(), width, 3, 2, 5, 15); holder.titleType1.setLayoutParams(paramsText); convertView.setTag(holder); holder.titleType1.setText(title); setTitleColor(holder.titleType1, title, true); imageLoader.displayImage(imgPaths[0], holder.imageType1, options); holder.assist1.setText(count666); holder.pubTime1.setText(pubTime); break;case 22://大圖視訊 convertView = LayoutInflater.from(context).inflate(R.layout.layout_simple_item_type2, null); holder.titleType2 = (TextView) convertView.findViewById(R.id.tvItemType2); holder.imageType2 = (ImageView) convertView.findViewById(R.id.imageItemType2); holder.assist2 = (TextView) convertView.findViewById(R.id.nice2); holder.pubTime2 = (TextView) convertView.findViewById(R.id.putTime2); holder.viewType2 = convertView.findViewById(R.id.playButton); TextView picsCountBg = (TextView) convertView.findViewById(R.id.picsCountBg); TextView picsCountOrTime = (TextView) convertView.findViewById(R.id.picsCount); if (type == 22) { holder.viewType2.setVisibility(View.VISIBLE); String dueTime = VideoInfoHelper.formatLongToTimeStr(dataItem.getDueTime()); picsCountBg.setText(dueTime); picsCountOrTime.setText(dueTime); } else { picsCountBg.setText(dataItem.getImageNum()+""); picsCountOrTime.setText(dataItem.getImageNum()+""); } int imgWidth1Of1 = DisplayUtils.calcMultipleWidth(getContext(), width, 1, 1, 5, 15); ViewGroup.LayoutParams paramsImgType2 = holder.imageType2.getLayoutParams(); paramsImgType2.width = imgWidth1Of1; paramsImgType2.height = (int) (imgWidth1Of1 * DisplayUtils.goldenRatio + 0.5f); holder.imageType2.setLayoutParams(paramsImgType2); convertView.setTag(holder); holder.titleType2.setText(title); setTitleColor(holder.titleType2, title, true); imageLoader.displayImage(imgPaths[0], holder.imageType2, options); holder.assist2.setText(count666); holder.pubTime2.setText(pubTime); break;
    case 23: ... ...
... ...
... ...
}
於是就發生了讓人頭疼的陣列越界異常:
 java.lang.ArrayIndexOutOfBoundsException: length=3; index=12
                                                       at android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:7113)
                                                       at android.widget.ListView.measureHeightOfChildren(ListView.java:1262)
                                                       at android.widget.ListView.onMeasure(ListView.java:1162)
                                                       at android.view.View.measure(View.java:15481)
                                                       at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5107)
                                                       at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
                                                       at android.view.View.measure(View.java:15481)
                                                       at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5107)
                                                       at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1396)
                                                       at android.widget.LinearLayout.measureVertical(LinearLayout.java:681)
... ...
... ...
一開始急趕程式碼給人看效果沒來得及仔細檢視異常發生在具體哪個引用類中(當然,是沒有出現自己專案下的類呼叫錯誤行提示,只有API中的)於是就上網搜了一下異常
(機智的加上Android關鍵字在前再搜尋~ 純Java的陣列越界就不在這裡討論了~) 由於異常資訊及其相似~害的自己走了不少彎路, 不過也瞭解了另外一個問題就是textview單行顯示不加singleLine屬性的BUG ,彎路就不繼續描述了,那個問題可見https://code.google.com/p/android/issues/detail?id=33868
後來下班經過debug除錯後,問題解決了,但是感覺這個設計有些蠢~   如果沒看懂我吐槽了半天要講什麼,沒關係,結論來了:
getViewTypeCount()  顧名思義就是我們一共需要多少種item的佈局 
getItemViewType() 的返回值(int)是區分不同型別的數字  那麼問題來了,我現在需要3種佈局,於是前者返回3  後者當然是利用postion返回3種不同的型別值 
問題就出在這3種不同的型別值的限制上,目的是區分,正常的邏輯是,只要這3個值不同即可,比如  1、2、3、   100、200、300、
但是越界異常就出現在這裡 因為 getItemViewType()返回的值規定必須小於getViewTypeCount()  也就是說如果有3種,那型別必須是0、1、2、 那個找了半天找不到的越界的陣列就是型別值和型別數"繫結"的陣列  ,將型別返回值寫成0、1、2 不報錯了, 我再但是~ 這個型別值是我從WEB後臺獲取資料物件後get到的,如果後臺程式碼不能改或者不方便改的情況下怎麼辦? 於是我嘗試了下將型別數量返回值改成了24 (最大的型別值是23,規定要小於count) 乍一看~ 有歧義,會以為有24種類型呢,但是執行並不會有任何問題~ 問題也可以解決
最後總覺得這樣不好,雖然執行時並沒有問題,但程式碼很不友好,於是我再稍加改進,乾脆將後臺的型別值和getItemViewType()的返回值做一個數據字典的對應轉換:
@Override
public int getItemViewType(int position) {
    int type = adapterDataList.get(position).getType();
    if (type == 21) {
        return 0;
    } else if (type == 22) {
        return 1;
    } else if (type == 23) {
        return 2;
    }
    return 0;//default
}

這樣同時避免不產生歧義也不需要重構WEB後臺程式碼的情況下解決了問題。