Android: ListView mit CheckBox, bevölkert von SQLite-Datenbank, die nicht ganz funktioniert

Wie bei einigen anderen Beiträgen hier, bin ich versucht, zu erstellen eine ListView enthält eine CheckBox für jede Zeile und verwenden Sie eine SQLite-Datenbank zum speichern der aktuelle Zustand der Auswahl.

Beginnend mit dem Beispiel http://appfulcrum.com/?p=351, die nicht ganz so funktioniert, wie es ist, habe ich eine einfache app, die die Datenbank erstellt, füllt es mit 20 items, und zeigt die Liste an.

Erfolgreich ruft die Staats-und speichert den Zustand der Auswahl.

ABER, ist es nicht richtig anzeigen das Kontrollkästchen Zustand, wenn ich es ändern, navigieren Sie an das andere Ende der Liste, und Blättern Sie zurück. wenn ich z.B. wählen Sie die erste CheckBox, scrollen Sie nach unten, und kommen zurück an die Spitze, die CheckBox wird nicht mehr gesetzt. Diese laufen auf einem Android 2.1 Samsung handset.

Wenn ich zum Hauptbildschirm zurück, kommen Sie zurück in die Liste, die CheckBox ist richtig eingestellt, so dass die Datenbank hat ja auch schon aktualisiert.

Beispiel erstreckt sich SimpleCursorAdapter, und die getView() ruft setChecked() mit true oder false als angemessen, auf der Grundlage der Wert der Auswahl-Spalte in der Tabelle.

Nachfolgend werden alle Quellen.

Ich würde sicherlich zu schätzen wissen, wird gesagt, "Naja, hier ist Ihr problem..."

CustomListViewDB.java

// src/CustomListViewDB.java
package com.appfulcrum.blog.examples.listviewcustomdb;

import android.app.ListActivity;
import android.database.Cursor;
import android.database.SQLException;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

public class CustomListViewDB extends ListActivity {

    private ListView mainListView = null;
    CustomSqlCursorAdapter adapter = null;
    private SqlHelper dbHelper = null;
    private Cursor currentCursor = null;

    private ListView listView = null;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.simple);

        if (this.dbHelper == null) {
            this.dbHelper = new SqlHelper(this);

        }

        listView = getListView();
        listView.setItemsCanFocus(false);
        listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        //listView.setClickable(true);

        Button btnClear = (Button) findViewById(R.id.btnClear);
        btnClear.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                Toast.makeText(getApplicationContext(),
                        " You clicked Clear button", Toast.LENGTH_SHORT).show();
                ClearDBSelections();
            }
        });

        new SelectDataTask().execute();

        this.mainListView = getListView();

        mainListView.setCacheColorHint(0);

    }

    @Override
    protected void onRestart() {
        super.onRestart();
        new SelectDataTask().execute();
    }

    @Override
    protected void onPause() {

        super.onPause();
        this.dbHelper.close();
    }

    protected void ClearDBSelections() {

        this.adapter.ClearSelections();

    }

    private class SelectDataTask extends AsyncTask<Void, Void, String> {

        protected String doInBackground(Void... params) {

            try {

                CustomListViewDB.this.dbHelper.createDatabase(dbHelper.dbSqlite);
                CustomListViewDB.this.dbHelper.openDataBase();

                CustomListViewDB.this.currentCursor = CustomListViewDB.this.dbHelper
                        .getCursor();

            } catch (SQLException sqle) {

                throw sqle;

            }
            return null;
        }

        // can use UI thread here
        protected void onPostExecute(final String result) {

            startManagingCursor(CustomListViewDB.this.currentCursor);
            int[] listFields = new int[] { R.id.txtTitle };
            String[] dbColumns = new String[] { SqlHelper.COLUMN_TITLE };

            CustomListViewDB.this.adapter = new CustomSqlCursorAdapter(
                    CustomListViewDB.this, R.layout.single_item,
                    CustomListViewDB.this.currentCursor, dbColumns, listFields,
                    CustomListViewDB.this.dbHelper);
            setListAdapter(CustomListViewDB.this.adapter);

        }
    }

}

CustomSqlCursorAdapter.java

// src/CustomSqlCursorAdapter.java

package com.appfulcrum.blog.examples.listviewcustomdb;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;

public class CustomSqlCursorAdapter extends SimpleCursorAdapter {
    private Context mContext;

    private SqlHelper mDbHelper;
    private Cursor mCurrentCursor;

    public CustomSqlCursorAdapter(Context context, int layout, Cursor c,
            String[] from, int[] to, SqlHelper dbHelper) {
        super(context, layout, c, from, to);
        this.mCurrentCursor = c;
        this.mContext = context;
        this.mDbHelper = dbHelper;

    }

    public View getView(int pos, View inView, ViewGroup parent) {
        View v = inView;
        if (v == null) {
            LayoutInflater inflater = (LayoutInflater) mContext
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = inflater.inflate(R.layout.single_item, null);
        }

        if (!this.mCurrentCursor.moveToPosition(pos)) {
            throw new SQLException("CustomSqlCursorAdapter.getView: Unable to move to position: "+pos);
        }

        CheckBox cBox = (CheckBox) v.findViewById(R.id.bcheck);

        // save the row's _id value in the checkbox's tag for retrieval later
        cBox.setTag(Integer.valueOf(this.mCurrentCursor.getInt(0)));

        if (this.mCurrentCursor.getInt(SqlHelper.COLUMN_SELECTED_idx) != 0) {
            cBox.setChecked(true);
            Log.w("SqlHelper", "CheckBox true for pos "+pos+", id="+this.mCurrentCursor.getInt(0));
        } else {
            cBox.setChecked(false);
            Log.w("SqlHelper", "CheckBox false for pos "+pos+", id="+this.mCurrentCursor.getInt(0));
        }
        //cBox.setOnClickListener(this);
        cBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

                Log.w("SqlHelper", "Selected a CheckBox and in onCheckedChanged: "+isChecked);

                Integer _id = (Integer) buttonView.getTag();
                ContentValues values = new ContentValues();
                values.put(SqlHelper.COLUMN_SELECTED, 
                        isChecked ? Integer.valueOf(1) : Integer.valueOf(0));
                mDbHelper.dbSqlite.beginTransaction();
                try {
                    if (mDbHelper.dbSqlite.update(SqlHelper.TABLE_NAME, values, "_id=?",
                            new String[] { Integer.toString(_id) }) != 1) {
                        throw new SQLException("onCheckedChanged failed to update _id="+_id);
                    }
                    mDbHelper.dbSqlite.setTransactionSuccessful();
                } finally {
                    mDbHelper.dbSqlite.endTransaction();
                }

                Log.w("SqlHelper", "-- _id="+_id+", isChecked="+isChecked);
            }
        });

        TextView txtTitle = (TextView) v.findViewById(R.id.txtTitle);
        txtTitle.setText(this.mCurrentCursor.getString(this.mCurrentCursor
                .getColumnIndex(SqlHelper.COLUMN_TITLE)));

        return (v);
    }

    public void ClearSelections() {
        this.mDbHelper.clearSelections();
        this.mCurrentCursor.requery();

    }
}

ListViewWithDBActivity.java

package com.appfulcrum.blog.examples.listviewcustomdb;

import android.app.Activity;
import android.os.Bundle;

public class ListViewWithDBActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

SqlHelper

// SqlHelper.java

package com.appfulcrum.blog.examples.listviewcustomdb;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.database.sqlite.SQLiteStatement;
import android.util.Log;

public class SqlHelper extends SQLiteOpenHelper {
    private static final String DATABASE_PATH = "/data/data/com.appfulcrum.blog.examples.listviewcustomdb/databases/";

    public static final String DATABASE_NAME = "TODOList";

    public static final String TABLE_NAME = "ToDoItems";
    public static final int ToDoItems_VERSION = 1;

    public static final String COLUMN_ID = "_id";               // 0
    public static final String COLUMN_TITLE = "title";          // 1
    public static final String COLUMN_NAME_DESC = "description";// 2
    public static final String COLUMN_SELECTED = "selected";    // 3
    public static final int    COLUMN_SELECTED_idx = 3;

    public SQLiteDatabase dbSqlite;
    private Context mContext;

    public SqlHelper(Context context) {
        super(context, DATABASE_NAME, null, 1);
        mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        createDB(db);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.w("SqlHelper", "Upgrading database from version " + oldVersion
                + " to " + newVersion + ", which will destroy all old data");

        db.execSQL("DROP TABLE IF EXISTS ToDoItems;");

        createDB(db);
    }

    public void createDatabase(SQLiteDatabase db) {
        createDB(db);
    }

    private void createDB(SQLiteDatabase db) {
        if (db == null) {
            db = mContext.openOrCreateDatabase(DATABASE_NAME, 0, null);
        }

        db.execSQL("CREATE TABLE IF NOT EXISTS ToDoItems (_id INTEGER PRIMARY KEY, title TEXT, "
                +" description TEXT, selected INTEGER);");
        db.setVersion(ToDoItems_VERSION);

        //
        // Generate a few rows for an example
        //
        // find out how many rows already exist, and make sure there's some minimum
        SQLiteStatement s = db.compileStatement("select count(*) from ToDoItems;");

        long count = s.simpleQueryForLong();
        for (int i = 0; i < 20-count; i++) {
            db.execSQL("INSERT INTO ToDoItems VALUES(NULL,'Task #"+i+"','Description #"+i+"',0);");
        }
    }

    public void openDataBase() throws SQLException {
        String myPath = DATABASE_PATH + DATABASE_NAME;

        dbSqlite = SQLiteDatabase.openDatabase(myPath, null,
                SQLiteDatabase.OPEN_READWRITE);
    }

    @Override
    public synchronized void close() {
        if (dbSqlite != null)
            dbSqlite.close();

        super.close();
    }

    public Cursor getCursor() {
        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();

        queryBuilder.setTables(TABLE_NAME);

        String[] asColumnsToReturn = new String[] { COLUMN_ID, COLUMN_TITLE,
                COLUMN_NAME_DESC, COLUMN_SELECTED };

        Cursor mCursor = queryBuilder.query(dbSqlite, asColumnsToReturn, null,
                null, null, null, COLUMN_ID+" ASC");

        return mCursor;
    }

    public void clearSelections() {
        ContentValues values = new ContentValues();
        values.put(COLUMN_SELECTED, 0);
        this.dbSqlite.update(SqlHelper.TABLE_NAME, values, null, null);
    }
}

Start.java

//src/Start.java
package com.appfulcrum.blog.examples.listviewcustomdb;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class Start extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button btnSimple = (Button) findViewById(R.id.btnSimple);
        btnSimple.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {

                Toast.makeText(getApplicationContext(),
                        " You clicked ListView From DB button", Toast.LENGTH_SHORT).show();

                Intent intent = new Intent(v.getContext(), CustomListViewDB.class);
                startActivityForResult(intent, 0);
            }
        });

    }
}

layout/main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/buttonlayout" android:orientation="vertical"
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    android:gravity="left|top" android:paddingTop="2dp"
    android:paddingBottom="2dp">

    <TextView android:id="@+id/txtTest" android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:textStyle="bold"
        android:text="@string/app_name" android:textSize="15sp"
        android:textColor="#FF0000" android:gravity="center_vertical"
        android:paddingLeft="5dp">
    </TextView>

    <Button android:id="@+id/btnSimple" 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" 
        android:textSize="15sp"
        android:text="Listview from DB"
        android:textColor="#000000"
        >
    </Button>

</LinearLayout>

layout/simple.xml

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

    <LinearLayout android:id="@+id/buttonlayout"
        android:orientation="horizontal" android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:height="32dp"
        android:gravity="left|top" android:paddingTop="2dp"
        android:paddingBottom="2dp">

        <LinearLayout android:id="@+id/buttonlayout2"
            android:orientation="horizontal" android:layout_height="wrap_content"
            android:gravity="left|center_vertical" android:layout_width="wrap_content"
            android:layout_gravity="left|center_vertical">

            <TextView android:id="@+id/txtTest"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent" android:textStyle="bold"
                android:text="@string/list_header" android:textSize="15sp"
                android:gravity="center_vertical" android:paddingLeft="5dp">
            </TextView>

            <Button android:id="@+id/btnClear"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" android:text="Clear"
                android:textSize="15sp" android:layout_marginLeft="10px"
                android:layout_marginRight="10px"
                android:layout_marginBottom="2px"
                android:layout_marginTop="2px" android:height="15dp"
                android:width="70dp"></Button>
        </LinearLayout>
    </LinearLayout>

    <TableLayout android:id="@+id/TableLayout01"
        android:layout_width="fill_parent" android:layout_height="fill_parent"
        android:stretchColumns="*">
        <TableRow>
            <ListView android:id="@android:id/list"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"></ListView>
        </TableRow>

    </TableLayout>

</LinearLayout>

layout/single_item.xml

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

    <CheckBox android:id="@+id/bcheck"
              android:layout_width="wrap_content"
              android:layout_height="fill_parent" />

        <TextView android:id="@+id/txtTitle"
            android:layout_width="wrap_content" android:gravity="left|center_vertical"
            android:layout_height="?android:attr/listPreferredItemHeight"
            android:layout_alignParentLeft="true" 
            android:textSize="20sp" android:text="Test"
            android:textStyle="bold" android:paddingLeft="5dp"
            android:paddingRight="2dp" android:focusable="false"
            android:focusableInTouchMode="false"></TextView>
        <LinearLayout android:layout_width="fill_parent"
            android:layout_height="wrap_content" android:orientation="horizontal"
            android:gravity="right|center_vertical">
        </LinearLayout>

</LinearLayout>

values/strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, ListViewWithDBActivity!</string>
    <string name="app_name">ListViewWithDB</string>
    <string name="list_header">List Headers</string>
</resources>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="1" android:versionName="1.0"    
    package="com.appfulcrum.blog.examples.listviewcustomdb">

    <application android:icon="@drawable/icon"
        android:label="@string/app_name" 
        android:theme="@android:style/Theme.NoTitleBar">
        >
        <activity android:name=".Start" android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".CustomListViewDB"></activity>
    </application>

    <uses-sdk android:minSdkVersion="7" /> <!-- android 1.6 -->
</manifest>

Wenn Sie bauen wollen, werfen Sie einige beliebige Symbol.png in drawable.

Vielen Dank im Voraus.

  • TL;DR... Wirklich, versuchen Sie, um präziser.
  • Andere Fragen wie diese waren kurz, aber immer noch Leute verwirrt. Ich wollte so viele Informationen wie nötig. Wie bereits in meiner weiteren Antwort, einen anderen Standort eine Lösung für das genaue Problem. Cheers.
InformationsquelleAutor user877139 | 2011-08-29
Schreibe einen Kommentar