網上很多listview加載不同的佈局 採用getItemViewType 方式行不通 也不知道他們怎麼寫的blog.能先自己用一下在發表嗎 複製粘貼的東西 不自己分析對錯,就這麼用嗎?
採用所有類型整合到一個item中控制佈局顯示隱藏的方式,雖然維護不方便,但至少不會出錯。
我爲了測試,使用了pulltorefreshlistview ,我的blog有講。
錯誤源代碼:
public class MainActivity extends AppCompatActivity {
PullToRefreshListView listView;
ImageView imageView;
MyAdapter mAdapter;
List<MDTO> list = new ArrayList<>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView) findViewById(R.id.iv);
imageView.setImageResource(R.drawable.proxyimg);
//控件
listView = (PullToRefreshListView) findViewById(R.id.listview);
for (int i = 0; i < 50; i++) {
MDTO mdto = new MDTO();
mdto.setId(R.drawable.ic_launcher);
mdto.setText("text" + i);
mdto.setType(i % 3);
list.add(mdto);
}
mAdapter = new MyAdapter(list);
listView.setAdapter(mAdapter);
//控件模式
listView.setMode(PullToRefreshBase.Mode.PULL_FROM_START);
//控件滾動行爲
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView absListView, int i) {
}
@Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
}
});
//控件刷新行爲
listView.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener<ListView>() {
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView) {
}
});
}
class MyAdapter extends BaseAdapter {
List<MDTO> mList = new ArrayList<>();
MyAdapter(List<MDTO> mdtoList) {
mList.clear();
this.mList.addAll(mdtoList);
for (int i = 0; i < mList.size(); i++) {
Log.i("id", mList.get(i).getId() + "");
Log.i("type", mList.get(i).getType() + "");
}
notifyDataSetChanged();
}
@Override
public int getCount() {
return mList.size();
}
@Override
public Object getItem(int i) {
return mList.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
int type = mList.get(i).getType();
ViewHolder_One viewHolder_one;
if (view == null) {
view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_one, null);
viewHolder_one = new ViewHolder_One();
viewHolder_one.iv = (ImageView) view.findViewById(R.id.one_iv);
viewHolder_one.tv = (TextView) view.findViewById(R.id.one_tv);
} else {
viewHolder_one = (ViewHolder_One) view.getTag();
}
if (type == 0) {
viewHolder_one.iv.setVisibility(View.VISIBLE);
viewHolder_one.tv.setVisibility(View.VISIBLE);
viewHolder_one.iv.setImageResource(mList.get(i).getId());
viewHolder_one.tv.setText(mList.get(i).getText());
view.setBackgroundColor(Color.RED);
} else if (type == 1) {
viewHolder_one.tv.setVisibility(View.VISIBLE);
viewHolder_one.iv.setVisibility(View.GONE);
viewHolder_one.tv.setText(mList.get(i).getText());
view.setBackgroundColor(Color.BLUE);
} else {
viewHolder_one.iv.setVisibility(View.VISIBLE);
viewHolder_one.tv.setVisibility(View.GONE);
viewHolder_one.iv.setImageResource(mList.get(i).getId());
view.setBackgroundColor(Color.WHITE);
}
return view;
}
class ViewHolder_One {
TextView tv;
ImageView iv;
}
}
}
當然 熟悉的同學一眼就看出問題所在,如果你忘了那麼辦呢?
報錯處
java.lang.NullPointerException: Attempt to read from field 'android.widget.TextView com.lcldream.www.MainActivity$MyAdapter$ViewHolder_One.tv' on a null object reference
at com.lcldream.www.MainActivity$MyAdapter.getView(MainActivity.java:141)
at android.widget.HeaderViewListAdapter.getView(HeaderViewListAdapter.java:220)
at android.widget.AbsListView.obtainView(AbsListView.java:2575)
at android.widget.ListView.makeAndAddView(ListView.java:1956)
at android.widget.ListView.fillDown(ListView.java:757)
at android.widget.ListView.fillGap(ListView.java:721)
at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5733)
at android.widget.AbsListView.scrollIfNeeded(AbsListView.java:3780)
at android.widget.AbsListView.onTouchMove(AbsListView.java:4277)
at android.widget.AbsListView.onTouchEvent(AbsListView.java:4052)
at android.widget.ListView.onTouchEvent(ListView.java:4287)
at android.view.View.dispatchTouchEvent(View.java:8677)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2517)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2161)
at com.handmark.pulltorefresh.library.PullToRefreshListView$InternalListView.dispatchTouchEvent(PullToRefreshListView.java:312)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2523)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2175)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2523)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2175)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2523)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2175)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2523)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2175)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2523)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2175)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2523)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2175)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2523)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2175)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2523)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2175)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2539)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1807)
at android.app.Activity.dispatchTouchEvent(Activity.java:2823)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:71)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2496)
at android.view.View.dispatchPointerEvent(View.java:8883)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4779)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4611)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4087)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4140)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4106)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4243)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4114)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4300)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4087)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4140)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4106)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4114)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4087)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6598)
at a
我們一看 空指針 果斷debug,debug是遇到任何問題都首先想到的。
進入了else{
viewHolder_one = (ViewHolder_One) view.getTag();
}
然後執行
對應type
報的空指針
那麼至此問題定位就明確了
viewHolder_one 出問題了
我們在看viewholder代碼發現沒有setTag.添上再運行 很流暢。
那麼沒有tag爲什麼會報錯呢 第一屏爲什麼沒有報錯呢?
涉及到listview複用機制
listview 爲了達到優化目的 使用了複用機制 其實第一屏都是 執行view == null 判斷 都是重新加載佈局 第二屏開始慢慢移除舊的 此時 view不再爲空 所以會重用tag中的內容,類似於日曆表 可以上下滑動 但是 中間顯示就一個 也就是容量有限 不用的就回收。