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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

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

Q&A

解決済

2回答

179閲覧

SQLiteを使用した保存/取り出しについて

Neev

総合スコア7

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

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

0グッド

1クリップ

投稿2018/04/26 02:20

前提・実現したいこと

Androidの勉強として、SQLiteを使用した簡単なメッセージアプリを作成しています。
ただ、メッセージの保存/取り出しに関して、下記の通り意図しない動作が発生しています。

発生している問題・エラーメッセージ

下記のような順序でメッセージを保存したとき

1. AAAA 2. BBBB 3. CCCC

次回にDBから取り出してListViewで一覧化すると下記のようになっています。

1. CCCC 2. CCCC 3. CCCC

SQLiteを使用したアプリは初めて作成するので、使用方法や呼び出し方などに誤りがあるのではないかと色々なサイトも調べましたが、似たような事象を発見できず行き詰っています。

SQLiteOpenHelper

public class DBHelper extends SQLiteOpenHelper { public DBHelper(Context context) { super(context, Consts.DB_NAME, null, Consts.DB_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("create table " + Consts.TABLE_NAME_MESSAGE + " (" + Consts.COLUMN_NAME_MESSAGE_ID + " integer primary key autoincrement, " + Consts.COLUMN_NAME_ROOM_ID + " integer not null, " + Consts.COLUMN_NAME_MESSAGE + " text not null, " + Consts.COLUMN_NAME_SPEAKER_TYPE + " text not null, " + Consts.COLUMN_NAME_DATE + " text not null);"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("drop table if exists " + Consts.TABLE_NAME_MESSAGE); onCreate(db); } }

DBUtils

public class DBUtils { /** * [概 要] メッセージ取得メソッド。<br> * [詳 細] メッセージを取得するメソッド。<br> * [備 考] <br> */ public static List<MessageBean> queryMessageRecodes(Context context){ DBHelper dbHelper = new DBHelper(context); SQLiteDatabase db = dbHelper.getReadableDatabase(); // SQL文作成 StringBuilder sql = new StringBuilder(); sql.append("SELECT "); sql.append(Consts.COLUMN_NAME_MESSAGE + ", "); sql.append(Consts.COLUMN_NAME_SPEAKER_TYPE + ", "); sql.append(Consts.COLUMN_NAME_DATE + " "); sql.append("FROM " + Consts.TABLE_NAME_MESSAGE + ";"); Log.d(Consts.LOG_TAG, "queryMessageRecodes SQL:" + String.valueOf(sql)); // 取得したレコードをリストに詰める List<MessageBean> messageList = new ArrayList<>(); MessageBean messageBean = new MessageBean(); Cursor cursor = db.rawQuery(sql.toString(), null); while (cursor.moveToNext()) { messageBean.setMessage(cursor.getString(0)); messageBean.setSpeakerType(cursor.getString(1)); messageBean.setDate(cursor.getString(2)); messageList.add(messageBean); } cursor.close(); db.close(); return messageList; } /** * [概 要] メッセージ保存メソッド。<br> * [詳 細] メッセージを保存するメソッド。<br> * [備 考] <br> */ public static void insertMessageRecode(Context context, MessageBean messageBean){ DBHelper dbHelper = new DBHelper(context); SQLiteDatabase db = dbHelper.getWritableDatabase(); // メッセージをDBに格納 ContentValues contentValues = new ContentValues(); contentValues.put(Consts.COLUMN_NAME_ROOM_ID, 0); contentValues.put(Consts.COLUMN_NAME_MESSAGE, messageBean.getMessage()); contentValues.put(Consts.COLUMN_NAME_SPEAKER_TYPE, messageBean.getSpeakerType()); contentValues.put(Consts.COLUMN_NAME_DATE, messageBean.getDate()); db.insert(Consts.TABLE_NAME_MESSAGE, "", contentValues); db.close(); } /** * [概 要] 全メッセージ削除メソッド。<br> * [詳 細] 全てのメッセージを削除するメソッド。<br> * [備 考] <br> */ public static void deleteAllMessageRecodes(Context context){ DBHelper dbHelper = new DBHelper(context); SQLiteDatabase db = dbHelper.getWritableDatabase(); // 全メッセージを削除 db.delete(Consts.TABLE_NAME_MESSAGE, null, null); } }

Fragment

public class ChatFragment extends Fragment { View mRootView; ListView mMessageListView; List<MessageBean> mMessageList = new ArrayList<>(); ChatAdapter mChatAdapter; String mMessageType = Consts.MESSAGE_TYPE_I; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ mRootView = inflater.inflate(R.layout.fragment_chat, container, false); mMessageListView = mRootView.findViewById(R.id.message_list); // メッセージをリストに追加 mMessageList = DBUtils.queryMessageRecodes(getContext()); mChatAdapter = new ChatAdapter(getContext(), mMessageList); mMessageListView.setAdapter(mChatAdapter); // 初期表示時にキーボードを出さない getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); // ボタンのクリックイベントを設定 setClickEvent(); return mRootView; } /** * [概 要] クリックイベント設定メソッド。<br> * [詳 細] フラグメント上の各ボタンのクリックイベントを設定するメソッド。<br> * [備 考] <br> */ public void setClickEvent(){ // 発言者変更ボタン ImageButton changeButton = mRootView.findViewById(R.id.change_button); changeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ImageButton changeButton = mRootView.findViewById(R.id.change_button); if(mMessageType.equals(Consts.MESSAGE_TYPE_I)){ // メッセージタイプを切り替え mMessageType = Consts.MESSAGE_TYPE_YOU; changeButton.setImageResource(R.mipmap.ic_launcher_round); } else{ // メッセージタイプを切り替え mMessageType = Consts.MESSAGE_TYPE_I; changeButton.setImageResource(R.mipmap.ic_launcher_round); } } }); // 送信ボタン ImageButton sendButton = mRootView.findViewById(R.id.send_button); sendButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EditText editMessage = mRootView.findViewById(R.id.edit_message); String sendMessage = editMessage.getText().toString(); if(sendMessage.length() <= 0){ // 何も入力されていなければエラー editMessage.setError(getString(R.string.send_message_empty)); return; } // メッセージをリストに追加 MessageBean messageBean = new MessageBean(); messageBean.setMessage(sendMessage); messageBean.setSpeakerType(mMessageType); messageBean.setDate(""); mMessageList.add(messageBean); // データベースにデータを格納 DBUtils.insertMessageRecode(getContext(), messageBean); // 最新メッセージを表示 mMessageListView.setSelection(mMessageListView.getCount() -1); // メッセージを空に戻す editMessage.setText(""); // キーボードを隠す InputMethodManager inputMethodManager = (InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } }); } }

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

SQLite3は関係無いはずで、DBUtilクラスのメソッド中に問題があるようです。こうではないかと。

Java

1 2//ここではなく MessageBean messageBean = new MessageBean(); 3 Cursor cursor = db.rawQuery(sql.toString(), null); 4 while (cursor.moveToNext()) { 5      // ここでインスタンス生成 6   MessageBean messageBean = new MessageBean(); 7 messageBean.setMessage(cursor.getString(0)); 8 messageBean.setSpeakerType(cursor.getString(1)); 9 messageBean.setDate(cursor.getString(2)); 10 11 messageList.add(messageBean); 12 }

最初のご提示のコードですと、MessageBeanクラスのインスタンスはwhileループ外で1回だけ生成しています。その参照をmessageListに何回もaddしていることになるので、結局最後のcursorの値を参照することになってます。

投稿2018/04/26 02:34

編集2018/04/26 02:37
dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Neev

2018/04/26 02:58

早急なご回答ありがとうございます。 参照型なので、都度 new しないと最後のデータを表示してしまうという事ですね。 SQLiteの方ばかり調査していて、ListViewに正しくデータが格納されているかの確認が疎かになっていました…。
dodox86

2018/04/26 03:03

コメントありがとうございます。 > 参照型なので、都度 new しないと最後のデータを表示してしまうという事ですね。 はい、仰るとおりです。
guest

0

MessageBeanを一度しか作成していないので、messageListに同じオブジェクトが検索件数分追加されているようです。
MessageBeanの作成をwhileループの中に移動すればよいと思います。

java

1 // 取得したレコードをリストに詰める 2 List<MessageBean> messageList = new ArrayList<>(); 3 // MessageBean messageBean = new MessageBean(); // 削除 4 Cursor cursor = db.rawQuery(sql.toString(), null); 5 while (cursor.moveToNext()) { 6 MessageBean messageBean = new MessageBean(); // 追加 7 messageBean.setMessage(cursor.getString(0)); 8 messageBean.setSpeakerType(cursor.getString(1)); 9 messageBean.setDate(cursor.getString(2)); 10 11 messageList.add(messageBean); 12 }

投稿2018/04/26 02:38

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Neev

2018/04/26 02:59

早急なご回答ありがとうございます。 SQLiteの方ばかり調査していて、ListView側の確認が疎かになっていました…。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問