私は自分のいとこ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()が呼び出されるたびにではなく、何かが変更されたときにのみ呼び出されるようにすることができます。私の解決策が非常に良いものであるかどうかはわかりませんが、これが大きな間違いだったに違いないと思います。