Исключение нулевого указателя с использованием BaseAdapter и ViewHolder - PullRequest
0 голосов
/ 28 декабря 2018

Я получаю исключение NullPointerException в строке:

viewHolder.list_item_TextView = convertView.findViewById(R.id.listItem_TextView);

То же приложение работает без проблем, если viewholder не реализовано.Я добавляю viewHolder, как я делал раньше в других приложениях, и они работают.Не могу найти ошибку.

public class lv_cb_db_ea_Adapter extends BaseAdapter {

final private Context context;
private Cursor cursor;
private SQLiteDatabase database;


lv_cb_db_ea_Adapter(Context context, Cursor cursor, SQLiteDatabase database) {
    super();
    this.context = context;
    this.cursor = cursor;
    this.database = database;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {

    ViewHolder viewHolder;

    if (convertView == null) {

        LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = layoutInflater.inflate(R.layout.list_item, parent, false);

        viewHolder = (ViewHolder) convertView.getTag();

// ########  here comes the NPE  #########
        viewHolder.list_item_TextView = convertView.findViewById(R.id.listItem_TextView);
        viewHolder.list_item_Checkbox = convertView.findViewById(R.id.listItem_CheckBox);

    } else {
        viewHolder = (ViewHolder) convertView.getTag();
    }

    cursor.moveToPosition(position);

    viewHolder.list_item_TextView.setText("Some Text");
    viewHolder.list_item_Checkbox.setChecked(cursor.getInt(cursor.getColumnIndex("selected")) != 0);

    return convertView;
}

public int getCount() {
    return cursor.getCount();
}

public Object getItem(int position) {
    return position;
}

public long getItemId(int position) {
    return position;
}

private static class ViewHolder {
    CheckBox list_item_Checkbox;
    TextView list_item_TextView;
}
}

вот xml-файл

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">

<CheckBox
    android:id="@+id/listItem_CheckBox"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:focusable="false"
    android:focusableInTouchMode="false" />

<TextView
    android:id="@+id/listItem_TextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_toRightOf="@+id/listItem_CheckBox" />

</RelativeLayout>

вот логкат:

java.lang.NullPointerException: Attempt to write to field 'android.widget.TextView ws.rtin.android.listviewexample.lv_cb_db_ea_Adapter$ViewHolder.list_item_TextView' on a null object reference

--- добавлен database.javaи listview.java ----

Поскольку есть некоторые ответы (спасибо за это), которые не решают проблему, я выкладываю все свое приложение (только три небольших java-файла и xml).«lv_cb_db_ea» - это основной файл в манифесте.

Вот моя база данных.java

public class database extends SQLiteOpenHelper {

database(Context context) {
    super(context, "database", null, 1);
}

@Override
public void onCreate(SQLiteDatabase db) {

    db.execSQL("CREATE TABLE country(" +
            "_id integer primary key autoincrement, " +
            "code varchar(3) not null," +
            "name varchar(30) not null," +
            "selected integer not null)"
    );

    db.execSQL("INSERT INTO country VALUES('0','DK','Dänemark',0)");
    db.execSQL("INSERT INTO country VALUES('1','F','Frankreich',1)");
    db.execSQL("INSERT INTO country VALUES('2','B','Belgien',0)");
    db.execSQL("INSERT INTO country VALUES('3','NL','Niederlande',1)");
    db.execSQL("INSERT INTO country VALUES('4','D','Deutschland',0)");
    db.execSQL("INSERT INTO country VALUES('6','TR','Türkei',0)");
    db.execSQL("INSERT INTO country VALUES('8','S','Schweden',0)");
    db.execSQL("INSERT INTO country VALUES('10','FN','Finnland',0)");
    db.execSQL("INSERT INTO country VALUES('11','GR','Griechenland',0)");
    db.execSQL("INSERT INTO country VALUES('12','A','Östereich',0)");
    db.execSQL("INSERT INTO country VALUES('13','LIT','Litauen',0)");
    db.execSQL("INSERT INTO country VALUES('14','PL','Polen',0)");
    db.execSQL("INSERT INTO country VALUES('15','P','Portugal',0)");
    db.execSQL("INSERT INTO country VALUES('16','I','Italien',0)");
    db.execSQL("INSERT INTO country VALUES('17','GB','Groß Britannien',0)");
    db.execSQL("INSERT INTO country VALUES('18','IRL','Irland',0)");
    db.execSQL("INSERT INTO country VALUES('19','L','Luxemburg',0)");
    db.execSQL("INSERT INTO country VALUES('20','E','Spanien',0)");
    db.execSQL("INSERT INTO country VALUES('21','CH','Schweiz',0)");
    db.execSQL("INSERT INTO country VALUES('22','CZ','Tschechien',0)");
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}

, а вот listView («MainActivity»)

public class lv_cb_db_ea extends Activity {

private static SQLiteDatabase sqLiteDatabase;
private Cursor cursor;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // connect to database
    SQLiteOpenHelper database = new database(this);
    sqLiteDatabase = database.getWritableDatabase();
    cursor = getDBContent();

    //create an ArrayAdapter by given database-cursor
    lv_cb_db_ea_Adapter itemAdapter = new lv_cb_db_ea_Adapter(this, cursor, sqLiteDatabase);
    ListView listView = findViewById(R.id.main_ListView);
    listView.setAdapter(itemAdapter);

    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
            String sToast = ((TextView) view.findViewById(R.id.listItem_TextView)).getText().toString();
            Toast.makeText(lv_cb_db_ea.this,
                    "Clicked on Row: " + sToast,
                    Toast.LENGTH_SHORT).show();
        }
    });
}

public void findSelected(View v) {
    StringBuilder sToast = new StringBuilder();
    sToast.append("You've selected...\n");
    cursor = sqLiteDatabase.rawQuery("SELECT * FROM country WHERE selected", null);
    while (cursor.moveToNext()) {
        sToast.append("\n").append(cursor.getString(cursor.getColumnIndex("name")));
    }
    Toast.makeText(getApplicationContext(), sToast, Toast.LENGTH_LONG).show();
    cursor.close();
}

// outsourcing query (for more complex queries (i.e. multiple tables))
public static Cursor getDBContent(){
    return sqLiteDatabase.rawQuery("SELECT * FROM country", null);
}

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

viewHolder = (ViewHolder) convertView.getTag();

должно быть

viewHolder = new ViewHolder();

в части if.

0 голосов
/ 28 декабря 2018

Ошибка говорит о том, что переменная viewHolder равна нулю.Взгляните на эту часть вашего кода:

LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.list_item, parent, false);

viewHolder = (ViewHolder) convertView.getTag();

Проблема в том, что «тег» представления - это место для хранения пользовательских данных.Это будет иметь значение, только если вы позвоните setTag().Поскольку вы только что надули новый макет, getTag() возвращает null, потому что вы его не установили.Вместо этого вам нужно создать новый ViewHolder и установить его в качестве тега представления:

LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.list_item, parent, false);
viewHolder = new ViewHolder();
convertView.setTag(viewHolder);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...