質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.47%

  • Android

    6628questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

[Android]ListViewでonItemLongClickからのDBデータ削除の手順について

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 1,237

yoshiky

score 95

お世話になっております。
Androidアプリで、
  1 ローカルDBからデータ取得
  2 ListViewに一覧表示
  3 list長押しでActionBarの部分に削除ボタン表示
  4  OkでDBから削除、画面再描画で対象データが非表示に、
というアプリを作ろうとしています(Gmailアプリみたいな動作です)。

ここで今、4番の削除後の画面再描画のところで詰まっています。
「ListView 更新」などで調べるとnotifyDataSetChangedがよくヒットするので試してみても、変わりません。
削除後、別画面に遷移して戻ってもう一度Listを構築すれば、削除したデータは一覧に出ませんが、
Gmailアプリみたいに削除したらすぐに一覧から消えるようにするには、どうしたらいいのでしょうか。

稚拙ですが、主だった部分のコードを載せます(メソッドの中身はところどころ省略)。
SQliteはActiveAndroidで操作しています。

Adapterを操作せずに直接DeleteしているからnotifyDataSetChangedが効かないと思うのですが、
ActiveAndroidを使うと下記のような書き方しか思いつかず。。

# モデル定義
@Table(name="Members")
public class Members extends Model{
    @Column(name="Name")
    public String Name;
}
public class MyListItem{
    ...
    public Long getId() { return id; }
    public String getName() { return name; }
    ...
}
public class MySampleList extends AppCompatActivity {

    protected MyListItem myListItem;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        final List<MyListItem> lists = new ArrayList<>();
        List<Members> members = new Select().from(Members.class).orderBy("id DESC").execute();
        for(Members member : members){
            myListItem = new MyListItem(
                member.getId(),
                member.Name
            );
            lists.add(myListItem);
        }

        MyBaseAdaptor mba = new MyBaseAdaptor(this, lists);
        ListView mlist = (ListView) this.findViewById(R.id.mListView);
        mlist.setAdaptor(mba);

        mlist.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {

                final ActionBar actionBar = getSupportActionBar(); 
                startActionMode(new ActionMode.Callback() {        //List長押しでActionMode
                    ...
                    @Override
                    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                        switch (item.getItemId()){ 
                            case R.id.icon_discard: // 削除アイコンを押した場合
                                Long member_id = lists.get(position).getId();
                                new Delete().from(Members.class).where("id = ?", member_id).execute();
                                //このあたりで notifyDataSetChanged ?
                                return true;
                        }
                        return false;
                    }
                }
            }
        });
    }

    public class MyBaseAdaptor extends BaseAdapter{
       private Context context;
       private List<MyListItem> members;

       public MyBaseAdaptor(Context context, List<MyListItem> members) {
           this.context = context;
           this.members = members;
       }
       @Override
       public int getCount() { }

       @Override
       public Object getItem(int position) {}

       @Override
       public long getItemId(int position) {}

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

}

アドバイスいただけると幸いです。「ここ見ろ」などサイトの紹介でも結構です。
よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

ListViewにセットされているAdapterからデータを削除してからListView#notifyDataSetChangedを呼ぶ必要があります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/03 19:52

    ご回答ありがとうございます。
    よく分かってなく恐縮ですが、Adapterからデータを削除すると、同時にDBからも消えるのか、DBから消す処理が別途必要なのかが、分かりません。。

    mlist.setAdaptor(mba);

    でsetしたmbaからremoveすると思っているのですが、removeメソッドが使えずAndroidStudioに怒られます。。

    キャンセル

  • 2016/04/03 20:19

    Adapterはデータを保持し、データを元にViewをつくり、ViewGroupに渡す役割しかありません。
    DBとは切り離されているため、Adapterからデータを削除してもDBには影響がありません。

    ArrayListAdapterを継承した方が楽そうですね。

    キャンセル

  • 2016/04/03 23:05

    アドバイスありがとうございます。
    色々試行錯誤しましたが、最終的に下記のようにしたら動きました()。

    1) BaseAdapterを継承したMyBaseAdaptorにremoveItem(position)というメソッド追加。
    2) removeItem内でnew Delete.from ~ でActiveAndroid経由でDBレコード削除。かつmembers.remove(potision)でMyBaseAdaptorが保持するデータからも対象を削除。
    3) startActoinMode#onActionItemClicked にて、myBaseAdaptor#removeItemを呼び出す。

    myBaseAdapter#removeItemを呼び出す際、myBaseAdapter(のインスタンス)を定義した箇所が悪いのか、finalをつけないとエラーになるのが気持ち悪いですが。


    >ArrayListAdapterを継承した方が楽そうですね。

    こちらはちなみに、ArrayAdapterでしょうか?
    http://developer.android.com/intl/ja/reference/android/widget/ArrayAdapter.html
    こういうDBのデータを使う場合はArrayAdapterかBaseAdapterで独自に作る方がいいのか、分からないのですが。。

    キャンセル

  • 2016/04/03 23:32

    finalをつけないといけないのはmyBaseAdapterがローカル変数なため、押したタイミングでは到達できないインスタンスになるからですよ。

    DBの更新処理をAdapterの中に入れてしまうのはあまりお勧めできません。
    せっかく分離した、データと見た目を再結合してしまうからです。

    誤記でした、ArrayAdapterですね。
    今回のように配列からAdapterを作るときは追加、挿入、削除ができるからです。

    キャンセル

  • 2016/04/06 12:03

    返事が遅くなって申し訳ありませんでした(回答コメントってメール通知ないのかな。。)

    > finalをつけないといけないのはmyBaseAdapterがローカル変数なため、押したタイミングでは到達できないインスタンスになるからですよ。
    なるほどです。
    finalだらけになりそうで気持ち悪かったのですが、この場合は仕方ないですかね。。

    > DBの更新処理をAdapterの中に入れてしまうのはあまりお勧めできません。
    > せっかく分離した、データと見た目を再結合してしまうからです。
    なるほど、おっしゃる通りですね。。
    Adapter内でDBの処理はしないで、分離してみます!

    キャンセル

関連した質問

同じタグがついた質問を見る

  • Android

    6628questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。