ruruchan_nanodesu
@ruruchan_nanodesu (RU RU)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

チェックリストの削除イベントについて

android studioでjavaのtodoリストアプリを作っています。データベースから読みだしたテキストとチェックボックスを一行ずつ表示していくアプリで、データベースのテーブルには、ID(Integer)、text(string)とカテゴリ分けして表示するためのgenre(Integer)の3つのカラムがあります。リスト表示まではできたのですが、削除イベントが書けなくて困っています。
1.チェックボックスをチェックする(複数でも可)
2.ボタンをクリック
3.データベースからチェックした項目を削除
という削除イベントを起こしたいのですが、どうすればいいかわかりません。助けてください

発生している問題

削除イベントの書き方がわからない

実際のコード

ListActivity

package com.example.todoapp;

import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.SimpleAdapter;

import androidx.appcompat.app.AppCompatActivity;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ListActivity extends AppCompatActivity {

    /**MapのKey**/
    private final String[] FROM = {"memo", "check"};

    /**リソースのコントロールID**/
    private final int[] TO = {R.id.textView, R.id.checkbox};

    private ListView mylistView;
    private DBAdapter dbAdapter;
    private List<Map<String, Object>> list;
    private Button deleteB;

    /**カスタムアダプター**/
    private class MyAdapter extends SimpleAdapter{
        public Map<Integer, Boolean> checkList = new HashMap<>();

        public MyAdapter(Context context, List<? extends Map<String, ?>> data, int resourse, String[] from, int[] to){
            super(context, data, resourse, from, to);

            //初期値を設定する
            for(int i = 0; i < data.size(); i++){
                Map map = (Map)data.get(i);
                checkList.put(i,(Boolean)map.get("check"));
            }
        }
        @Override
        public View getView(final int position, View convertView, ViewGroup parent){
            View view = super.getView(position, convertView, parent);
            CheckBox ch = view.findViewById(R.id.checkbox);
            return view;
        }
    }

    /**ListActivity**/
    @Override
    protected void onCreate(Bundle savedInstanced){
        super.onCreate(savedInstanced);
        setContentView(R.layout.activity_list);

        /**main画面で選ばれたgenreを受け取る**/
        Intent i = getIntent();
        int genre = i.getIntExtra("CHOOSED", 100);

        /**DBAdapterインスタンス化**/
        dbAdapter = new DBAdapter(this);
        /**DBOpen**/
        dbAdapter.openDB();

        findViews();

        items = new ArrayList<>();

        /**DBのデータを取得**/
        String[] columns = {DBAdapter.COL_TEXT};

        if(genre == 0){
            Cursor c = dbAdapter.getDB(columns);
            if(c.moveToFirst()){
                do{
                    Map<String, Object> map = new HashMap<>();
                    map.put("memo", c.getString(0));
                    map.put("check", false);
                    list.add(map);
                }while (c.moveToNext());
            }
            c.close();
            dbAdapter.closeDB();
        }else {
            Cursor c = dbAdapter.selectDB(columns, Integer.toString(genre));
            if(c.moveToFirst()){
                do{
                    Map<String, Object> map = new HashMap<>();
                    map.put("memo", c.getString(1));
                    map.put("check", false);
                    list.add(map);
                }while (c.moveToNext());
            }
            c.close();
            dbAdapter.closeDB();
        }

        /**データをリスト表示**/
        MyAdapter adapter = new MyAdapter(ListActivity.this, list, R.layout.item_list, FROM, TO);
        mylistView.setAdapter(adapter);
  }

    private void findViews(){

        mylistView = findViewById(R.id.list_view);
        deleteB = findViewById(R.id.deleteB);

    }
}

DB関連のクラス

package com.example.todoapp;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteCursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import java.util.ArrayList;
import java.util.List;

public class DBAdapter {
    public final static String DB_NAME = "TODOData.db";
    public final static String DB_TABLE = "mySheet";
    public final static int DB_VERSION = 3;

    public final static String COL_ID = "_id";
    public final static String COL_TEXT = "text";
    public final static String COL_GENRE = "genre";

    private SQLiteDatabase db = null;
    private DBHelper helper = null;
    protected Context context;

    public DBAdapter(Context context){
        this.context = context;
        helper = new DBHelper(this.context);
    }

    public DBAdapter openDB(){
        db = helper.getWritableDatabase();
        return this;
    }

    public DBAdapter readDB(){
        db = helper.getReadableDatabase();
        return this;
    }

    public void closeDB(){
        db.close();
        db = null;
    }

    public void saveDB(String memo, int genre){
        //トランザクション開始
        db.beginTransaction();
        try {
            ContentValues values = new ContentValues();
            values.put(COL_TEXT, memo);
            values.put(COL_GENRE, genre);

            db.insert(DB_TABLE, null, values);
            //トランザクションにコミット
            db.setTransactionSuccessful();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            db.endTransaction();
        }
    }

    //DBのデータを取得
    public Cursor getDB(String[] columns){
        return db.query(DB_TABLE, columns, null, null, null, null, null);
    }

    /**select文で抽出**/
    public Cursor selectDB(String[] columns, String choosedG){
        return db.query(DB_TABLE, null, COL_GENRE + " = ?", new String[] {choosedG}, null, null, null);
    }

    //DBの検索したデータを取得
    public Cursor searchDB(String[] columns, String column, String[] name){
        return db.query(DB_TABLE, columns, column + " like ?", name, null, null, null);
    }

    //DBのレコードを単一削除
    public void selectDelete(String position) {

        db.beginTransaction();
        try {
            db.delete(DB_TABLE, COL_ID + "=?=", new String[]{position});
            //トランザクション開始
            db.setTransactionSuccessful();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            db.endTransaction();
        }
    }



    private static class DBHelper extends SQLiteOpenHelper {
        public DBHelper(Context context){
            super(context, DB_NAME, null, DB_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db){
            String createTable = "CREATE TABLE " + DB_TABLE + " (" +
                    COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
                    COL_TEXT + " TEXT NOT NULL," +
                    COL_GENRE + " INTEGER NOT NULL" +
                    ");";

            db.execSQL(createTable);
        }

        /**DBアップグレード時に呼ばれる**/
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
            //DBからテーブル削除
            db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);
            onCreate(db);
        }

    }
}


activity_list.xml


<ListView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/list_view"/>

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="表示"
    android:id="@+id/deleteB"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.45"/>

item_list.xml


<?xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:descendantFocusability="blocksDescendants">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="6dp"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="6dp"
        android:id="@+id/checkbox"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="6dp"
        android:layout_weight="1"
        android:id="@+id/textView"/>

</LinearLayout>

自分で試したこと

for文でarraylistのチェックされたチェックボックスを探そうとしましたが、リストの中のcheckboxのxml上のidがどうなっているのかわからず躓いています。

0

1Answer

大きく分けて2つ対応しないといけないと思います。

1つめは、アダプタ MyAdaptergetView メソッドで、チェックボックスのコールバックを定義する必要があります。そのコールバックではチェックされた(あるいはチェックをはずされた)ら、その状態(何番目のチェックボタンをチェックされたか、あるいは外されたか)を覚える必要があります。
なので、どこかに何番目のチェックボックスが選ばれているか、という情報を保持しておくようにしてください。

2つめは、アクティビティの onCreate メソッドあたりで、削除ボタンにコールバックを定義する必要があります。こちらのコールバックでは、上記の(1つめの)コールバックで覚えている、チェックされた番号をもとに、該当のデータを削除すればよいと思います。

注意すべき内容としては、DBの削除は一般的に時間のかかる処理なので、普通はメインスレッド(UIスレッド)ではなく、別のスレッドで実施する方が良いと思います。

1Like

Comments

  1. 回答してくださりありがとうございます!
    private int numch = 0;を作り、MyAdapterのgetViewメソッドを

    public View getView(final int position, View convertView, ViewGroup parent){
    View view = super.getView(position, convertView, parent);
    CheckBox ch = view.findViewById(R.id.checkbox);

    ch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    checkList.put(position,isChecked);
    if(isChecked == true){
    numch = position;
    }
    }
    });
    return view;
    }
    と変更し、mylistviewにadapterをsetした後に、

    deleteB.setOnClickListener(v -> {
    dbAdapter.selectDelete(String.valueOf(numch));
    loadMyList();
    });

    と書いたのですが、うまくいきません…loadMyListの内容は
    private void loadMyList(){
    list.clear();
    dbAdapter.openDB();

    if(genre == 0){
    Cursor c = dbAdapter.getDB(columns);
    if(c.moveToFirst()){
    do{
    Map<String, Object> map = new HashMap<>();
    map.put("memo", c.getString(1));
    map.put("check", false);
    list.add(map);
    }while (c.moveToNext());
    }
    c.close();
    dbAdapter.closeDB();
    }else {
    Cursor c = dbAdapter.selectDB(columns, Integer.toString(genre));
    if(c.moveToFirst()){
    do{
    Map<String, Object> map = new HashMap<>();
    map.put("memo", c.getString(1));
    map.put("check", false);
    list.add(map);
    }while (c.moveToNext());
    }
    c.close();
    dbAdapter.closeDB();
    }
    MyAdapter adapter = new MyAdapter(ListActivity.this, list, R.layout.item_list, FROM, TO);
    mylistView.setAdapter(adapter);
    adapter.notifyDataSetChanged();
    }

    です。ボタンを押すと、チェックしたチェックリストのチェックが外れているので、このloadMyList関数自体は動いているようなのですが、項目が削除されていません。これは、おっしゃるようにDB削除に時間がかかっているだけなのでしょうか?それとも他の処理がうまくいっていないのでしょうか。何度もすみません…
  2. ソースコードは返信に書かれると、コードブロックが使えなくて見にくいので、ソースコードについては本文に追記の形でコードブロックを使って書いてもらった方がわかりやすいです。

    また、選択した複数の物を削除したいのであれば、numch ではなく checkList が true の物を削除したほうが良いと思いますが、それは理解したうえで、とりあえず1つだけ削除したいということですよね。

    気になるのは、削除ロジックのところの "=?=" は、 "=?" の間違いだと思います。
    おそらく例外が発生して e.printStackTrace(); でトレースが出ているのではないかと思います。
    実機で動かしているときに e.printStackTrace(); では詳細が見れないのではないかと思うので、Log クラスを使って logcat に出すようにした方が良いと思います。

    実際に動かして試してはいないので、本当に上記が動かない原因なのかはわかりません。
    デバッガーでステップごとに確認するか、Log.d() などでログを出力するようにするなどして、動作を確認しながら動かしてみると、どこでうまくいっていないのかがわかると思います。

Your answer might help someone💌

Login to continue?

Login or Sign up with social account

Login or Sign up with your email address