我正在尝试将类别字段包含到我的自定义 ListView 中。在我开始快速滚动之前它工作正常。当滚动非常慢时,不会发生此错误。这真的让我很困惑。有人可以帮忙吗?我的代码:
package com.mamlambo.tutorial.tutlist;
import java.util.ArrayList;
import java.util.TreeSet;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.ImageView;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
public class TutListActivity extends Activity {
private DatabaseManager mHelper;
private SQLiteDatabase mDatenbank;
private ArrayList<String> devicesList;
private TreeSet<Object> mSeparatorsSet;
ListView listView;
EfficientAdapter objectAdapter;
private class EfficientAdapter extends BaseAdapter {
private LayoutInflater mInflater;
private Bitmap mIcon1;
private Bitmap mIcon2;
private static final int TYPE_ITEM = 0;
private static final int TYPE_SEPARATOR = 1;
private static final int TYPE_MAX_COUNT = TYPE_SEPARATOR + 1;
public EfficientAdapter(Context context) {
// Cache the LayoutInflate to avoid asking for a new one each time.
mInflater = LayoutInflater.from(context);
// Icons bound to the rows.
mIcon1 = BitmapFactory.decodeResource(context.getResources(), R.drawable.icon);
mIcon2 = BitmapFactory.decodeResource(context.getResources(), R.drawable.icon);
}
/**
* The number of items in the list is determined by the number of speeches
* in our array.
*
* @see android.widget.ListAdapter#getCount()
*/
public int getCount() {
return devicesList.size();
}
public void addItem(final String item) {
devicesList.add(item);
notifyDataSetChanged();
}
/**
* Since the data comes from an array, just returning the index is
* sufficent to get at the data. If we were using a more complex data
* structure, we would return whatever object represents one row in the
* list.
*
* @see android.widget.ListAdapter#getItem(int)
*/
public Object getItem(int position) {
return position;
}
/**
* Use the array index as a unique id.
*
* @see android.widget.ListAdapter#getItemId(int)
*/
public long getItemId(int position) {
return position;
}
@Override
public void notifyDataSetChanged() // Create this function in your adapter class
{
super.notifyDataSetChanged();
}
public void addSeparatorItem(final String item) {
devicesList.add(item);
// save separator position
mSeparatorsSet.add(devicesList.size() - 1);
notifyDataSetChanged();
}
@Override
public int getItemViewType(int position) {
return mSeparatorsSet.contains(position) ? TYPE_SEPARATOR : TYPE_ITEM;
}
public View getView(int position, View convertView, ViewGroup parent) {
// A ViewHolder keeps references to children views to avoid unneccessary calls
// to findViewById() on each row.
ViewHolder holder;
// When convertView is not null, we can reuse it directly, there is no need
// to reinflate it. We only inflate a new View when the convertView supplied
// by ListView is null.
int type = getItemViewType(position);
if (convertView == null) {
holder = new ViewHolder();
switch (type) {
case TYPE_ITEM:
convertView = mInflater.inflate(R.layout.list_item, null);
holder.text = (TextView) convertView.findViewById(R.id.Title_List_Item);
holder.icon = (ImageView) convertView.findViewById(R.id.Delete_List_Item);
convertView.findViewById(R.id.Title_List_Item).setTag(devicesList.get(position));
convertView.findViewById(R.id.Delete_List_Item).setTag(devicesList.get(position));
holder.text.setText(devicesList.get(position));
holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2);
holder.text.setOnClickListener(mOnTitleClickListener);
holder.icon.setOnClickListener(mOnIconClickListener);
break;
case TYPE_SEPARATOR:
convertView = mInflater.inflate(R.layout.seperator_item, null);
holder.text = (TextView)convertView.findViewById(R.id.Text_Seperator_Item);
holder.text.setText(devicesList.get(position));
break;
}
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
return convertView;
}
private OnClickListener mOnTitleClickListener = new OnClickListener() {
public void onClick(View v) {
if(v.getTag().toString() == "ADD DEVICE"){
Intent addDevice = new Intent(getApplicationContext(), addDevice.class);
startActivity(addDevice);
}else{
Intent showRemote = new Intent(TutListActivity.this, Remote.class);
showRemote.putExtra("selectedDevice", v.getTag().toString());
startActivity(showRemote);
}
}
};
private OnClickListener mOnIconClickListener = new OnClickListener() {
public void onClick(View v) {
String NameOfDevice[] = new String[2];
NameOfDevice = v.getTag().toString().split(",");
mDatenbank.execSQL("DELETE FROM addedDevices WHERE name = '"+NameOfDevice[0]+"'");
ladeDevices();
objectAdapter.notifyDataSetChanged();
}
};
class ViewHolder {
TextView text;
ImageView icon;
}
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mainlayout);
mHelper = new DatabaseManager(this);
mDatenbank = mHelper.getReadableDatabase();
listView = (ListView) findViewById(R.id.list);
objectAdapter = new EfficientAdapter(this);
ladeDevices();
}
/*
@Override
protected void onPause() {
super.onPause();
mDatenbank.close();
dataloaded = false;
}
@Override
protected void onResume() {
super.onResume();
mDatenbank = mHelper.getReadableDatabase();
ladeDevices();
}
*/
private void ladeDevices() {
devicesList = new ArrayList<String>();
mSeparatorsSet = new TreeSet<Object>();
Cursor devicesCursor = mDatenbank.query("addedDevices", new String[] {"name", "hersteller"}, null, null, null, null, null);
startManagingCursor(devicesCursor);
devicesCursor.moveToFirst();
for (int i=0;i<devicesCursor.getCount();i++){
String addingElement = new String(devicesCursor.getString(0)+", "+devicesCursor.getString(1));
objectAdapter.addItem(addingElement);
devicesCursor.moveToNext();
if (i % 4 == 0) {
objectAdapter.addSeparatorItem("separator " + i);
}
}
objectAdapter.addItem("ADD DEVICE");
listView.setAdapter(objectAdapter);
}
}
谢谢!
编辑:LogCat 输出:
11-19 15:01:44.898: E/AndroidRuntime(957): FATAL EXCEPTION: main
11-19 15:01:44.898: E/AndroidRuntime(957): java.lang.NullPointerException
11-19 15:01:44.898: E/AndroidRuntime(957): at com.mamlambo.tutorial.tutlist.TutListActivity$EfficientAdapter.getView(TutListActivity.java:150)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.widget.AbsListView.obtainView(AbsListView.java:2012)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.widget.ListView.makeAndAddView(ListView.java:1772)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.widget.ListView.fillUp(ListView.java:705)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.widget.ListView.correctTooHigh(ListView.java:1395)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.widget.ListView.fillGap(ListView.java:637)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.widget.AbsListView.trackMotionScroll(AbsListView.java:4546)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.widget.AbsListView.scrollIfNeeded(AbsListView.java:2852)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.widget.AbsListView.onTouchEvent(AbsListView.java:3106)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.view.View.dispatchTouchEvent(View.java:5486)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1953)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1714)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1959)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1728)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1959)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1728)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1959)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1728)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1959)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1728)
11-19 15:01:44.898: E/AndroidRuntime(957): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1892)
11-19 15:01:44.898: E/AndroidRuntime(957): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1371)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.app.Activity.dispatchTouchEvent(Activity.java:2364)
11-19 15:01:44.898: E/AndroidRuntime(957): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1840)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.view.View.dispatchPointerEvent(View.java:5662)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:2863)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2442)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.os.Handler.dispatchMessage(Handler.java:99)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.os.Looper.loop(Looper.java:137)
11-19 15:01:44.898: E/AndroidRuntime(957): at android.app.ActivityThread.main(ActivityThread.java:4340)
11-19 15:01:44.898: E/AndroidRuntime(957): at java.lang.reflect.Method.invokeNative(Native Method)
11-19 15:01:44.898: E/AndroidRuntime(957): at java.lang.reflect.Method.invoke(Method.java:511)
11-19 15:01:44.898: E/AndroidRuntime(957): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
11-19 15:01:44.898: E/AndroidRuntime(957): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
11-19 15:01:44.898: E/AndroidRuntime(957): at dalvik.system.NativeStart.main(Native Method)
编辑:我添加了一个新版本。我把 listView.setAdapter(objectAdapter); 在从数据库加载列表条目并将它们放入 ArrayList 的方法中。这样,每次发生变化(条目被删除)时,适配器都会被设置为新的。这样做可以让我将 setTag() 和 onClickListener() 调用放入 if (convertView == null) {...} 中,以便仅在某些情况发生变化时调用它们,而不是每次调用 getView() 时调用。我相信这一定是最大的错误,尽管我不确定我的解决方案是否是一个非常好的解决方案。