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

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

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

SQLiteはリレーショナルデータベース管理システムの1つで、サーバーではなくライブラリとして使用されている。

Java

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

Android

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

Q&A

解決済

1回答

2971閲覧

SQLite 本体のデータ削除後に開けなくなった

rinchu_17

総合スコア24

SQLite

SQLiteはリレーショナルデータベース管理システムの1つで、サーバーではなくライブラリとして使用されている。

Java

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

Android

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

0グッド

0クリップ

投稿2017/10/21 22:34

編集2017/10/22 11:21

閲覧ありがとうございます。
専門の知識が乏しいため読みづらかったり、用語の使い方が間違っていたりすると思いますが、何卒よろしくお願いします。

SQLiteを用いてデータ保存をするAndroidアプリの開発中、実機に繋いでインストールし実行していました。
今までデータの読み書きともに正常に行えていたのですが、一旦本体の設定からアプリのデータ削除をしたところ、途端に読み書きともに行えなくなってしまいました。(SQLiteDatabaseオブジェクトをヘルパーからgetReadableDatabase/getWritableDatabaseで開く処理だけtry文に入れるとSQLiteExceptionをcatchしました)

自分では経験・知識ともに浅く、また調べても同じようなケースが見当たらないため、原因や解決方法を教えて頂きたいです。よろしくお願いします。

(ソースコードですが、どの部分を載せるべきか判断しかねましたので、ご指摘いただいてから記載したいと思います)
追記(10/22/20:10):ご指摘いただきましたのでソースコードを追記いたしました。
乱雑で読みづらいコードで申し訳ありません。必要ないと思われる箇所は適宜省略しましたが、いかんせんどこを載せたらよいのかわからず、無駄な部分が多いと思いますがご容赦ください。

また、ご要望頂いておりますエラーログですが、LogCatの調子が悪く全く出力されなくなっているため、自分も把握できていない状況です。申し訳ありません。

###該当のソースコード

java

1public class MainActicity extends FragmentActivity { 2 //扱うitemを管理 3 ArrayList<Item> items = new ArrayList<Item>(); 4 5 //各種数値 6 private int[] values; 7 /* 8 * valuesはアクティビティ全体として保持すべき数値のうち、 9 * データベースに保存すべきもの。 10 * SALES_AMOUNT = 総売り上げ額 11 */ 12 private final int SALES_AMOUNT = 0; 13 14 @Override 15 protected void onCreate(Bundle savedInstanceState) { 16 super.onCreate(savedInstanceState); 17 setContentView(R.layout.activity_main); 18 19 //各ViewをfindViewByIdしたりOnClickを実装したりしていますが省略 20 21 //データロード 22 values = DataUtils.load(this,items); 23 } 24 25  @Override 26 protected void onPause() { 27 DataUtils.store(this,values); 28 super.onPause(); 29 } 30} 31 32public class Item { 33 //商品名 34 public String name; 35 36 //設定価格 37 public int price; 38 39 //売上個数 40 private int sales; 41 42 43 //コンストラクタ 44 public Item(String name, int price, int sales) { 45 this.name = name; 46 this.price = price; 47 this.sales = sales; 48 } 49 50 //セッター 51 public void setName(String name) { 52 this.name = name; 53 } 54 public void setPrice(int price) { 55 this.price = price; 56 } 57 58 //ゲッター 59 public String getName(){ 60 return this.name; 61 } 62 public int getPrice(){ 63 return this.price; 64 } 65 public int getSales(){ 66 return this.sales; 67 } 68 69} 70 71public class MySQLiteOpenHelper extends SQLiteOpenHelper { 72 //データベース・テーブル・カラム・レコード作成用の値はすべてDataUtilsクラスで管理 73 static final String DB_NAME = DataUtils.DB_NAME; 74 static final int DB_VERSION = DataUtils.DB_VERSION; 75 static final String TABLE_NAME_ITEM = DataUtils.TABLE_NAME_ITEM; 76 static final String TABLE_NAME_INTEGER = DataUtils.TABLE_NAME_INTEGER; 77 static final String COLUMN_NAME_ID = DataUtils.COLUMN_NAME_ID; 78 static final String COLUMN_NAME_ITEM_NAME = DataUtils.COLUMN_NAME_ITEM_NAME; 79 static final String COLUMN_NAME_ITEM_PRICE = DataUtils.COLUMN_NAME_ITEM_PRICE; 80 static final String COLUMN_NAME_ITEM_SALES = DataUtils.COLUMN_NAME_ITEM_SALES; 81 static final String COLUMN_NAME_INTEGER_NOMINAL = DataUtils.COLUMN_NAME_INTEGER_NOMINAL; 82 static final String COLUMN_NAME_INTEGER_VALUE = DataUtils.COLUMN_NAME_INTEGER_VALUE; 83 static final String RECORD_NAME_SALESAMOUNT = DataUtils.RECORD_NAME_SALESAMOUNT; 84 85 //コンストラクタ 86 public MySQLiteOpenHelper(Context context) { 87 super(context, DB_NAME, null, DB_VERSION); 88 } 89 90 /** 91 * 初回作成時に呼ばれる 92 * テーブルを作成する 93 */ 94 @Override 95 public void onCreate(SQLiteDatabase db) { 96 //Item用テーブル作成 97 db.execSQL("CREATE TABLE " + TABLE_NAME_ITEM + " (" 98 + COLUMN_NAME_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," 99 + COLUMN_NAME_ITEM_NAME + " TEXT NOT NULL," 100 + COLUMN_NAME_ITEM_PRICE + " INTEGER NOT NULL," 101 + COLUMN_NAME_ITEM_SALES + " INTEGER NOT NULL)"); 102 //整数用テーブル作成 103 db.execSQL("CREATE TABLE " + TABLE_NAME_INTEGER + " (" 104 + COLUMN_NAME_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," 105 + COLUMN_NAME_INTEGER_NOMINAL + "TEXT PRIMARY KEY NOT NULL" 106 + COLUMN_NAME_INTEGER_VALUE + " INTEGER)"); 107 db.execSQL("INSERT INTO " + TABLE_NAME_INTEGER + " VALUES(" 108 + RECORD_NAME_SALESAMOUNT + ",0)"); 109 } 110 111 /** 112 * データベースの更新が必要な時に呼ばれる 113 * テーブルを作り直す 114 */ 115 @Override 116 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 117 118 } 119 120} 121 122public class DataUtils { 123 124 //データベース 125 private static MySQLiteOpenHelper mySQLiteOpenHelper; 126 private static SQLiteDatabase DB; 127 //データベース名 128 static final String DB_NAME = "myregister.db"; 129 //データベースバージョン 130 static final int DB_VERSION = 1; 131 //テーブル名 132 static final String TABLE_NAME_ITEM = "item_table"; 133 static final String TABLE_NAME_INTEGER = "integer_table"; 134 //カラム名 135 static final String COLUMN_NAME_ID = "_id"; 136 static final String COLUMN_NAME_ITEM_NAME = "name"; 137 static final String COLUMN_NAME_ITEM_PRICE = "price"; 138 static final String COLUMN_NAME_ITEM_SALES = "sales"; 139 static final String COLUMN_NAME_INTEGER_NOMINAL = "nominal"; 140 static final String COLUMN_NAME_INTEGER_VALUE = "value"; 141 //INTEGERテーブルのレコード名 142 static final String RECORD_NAME_SALESAMOUNT = "salesAmount"; 143 144 protected static int[] load(Activity activity, ArrayList<Item> items) { 145 mySQLiteOpenHelper = new MySQLiteOpenHelper(activity.getApplicationContext()); 146 147 try{ 148 //データベースを読み取り専用で開く 149 DB = mySQLiteOpenHelper.getReadableDatabase(); 150 }catch(SQLiteException e) { 151 //異常終了 152 //ここで引っかかってしまう(トーストが出る)******************************** 153 Toast.makeText(activity, "データベースを開けません", Toast.LENGTH_SHORT).show(); 154 return null; 155 } 156 try{ 157 //itemテーブルからデータを取得 158 Cursor c; 159 c = DB.rawQuery("SELECT * " 160 + "FROM " + TABLE_NAME_ITEM + " " 161 + "ORDER BY " + COLUMN_NAME_ID + " ASC" 162 , null); 163 164 //取得したデータからitemsを復元 165 if(c.moveToFirst()){ 166 //レコードが存在する場合、ID順にitemsにItemオブジェクトを作成 167 do{ 168 items.add(new Item (c.getString (c.getColumnIndex(COLUMN_NAME_ITEM_NAME)), 169 c.getInt (c.getColumnIndex(COLUMN_NAME_ITEM_PRICE)), 170 c.getInt(c.getColumnIndex(COLUMN_NAME_ITEM_SALES)) ) ); 171 }while(c.moveToNext()); 172 }else{ 173 //レコードが存在しない場合の処理 174 } 175 176 177 //integerテーブルからデータ取得 178 int[] values = new int[1]; 179 c = DB.rawQuery("SELECT * " 180 + "FROM " + TABLE_NAME_INTEGER + " " 181 + "ORDER BY " + COLUMN_NAME_ID + " ASC" 182 , null); 183 184 int n = 0; 185 if(c.moveToFirst()){ 186 do{ 187 values[n] = c.getInt(c.getColumnIndex(COLUMN_NAME_INTEGER_VALUE)); 188 n++; 189 }while(c.moveToNext()); 190 }else{ 191 //レコードが存在しない場合の処理 192 } 193 194 195 DB.close(); 196 197 return values; 198 }catch(SQLiteException e){ 199 //異常終了 200 Toast.makeText(activity, "データ取得に失敗しました", Toast.LENGTH_SHORT).show(); 201 return null; 202 } 203 204 } 205 206 /** 207 * データベースへデータを保存 208 */ 209 protected static void store(Activity activity, int[] values){ 210 mySQLiteOpenHelper = new MySQLiteOpenHelper(activity.getApplicationContext()); 211 try{ 212 //データベースを書き込み可能で開く 213 DB = mySQLiteOpenHelper.getWritableDatabase(); 214 215 //INTEGERテーブルに値を保存 216 for(int i=0;i<values.length;i++){ 217 DB.execSQL("UPDATE " + TABLE_NAME_INTEGER + " " 218 + "SET " + COLUMN_NAME_INTEGER_VALUE + "=" + values[i] + " " 219 + "WHERE " + COLUMN_NAME_ID + "=" + String.valueOf(i+1)); 220 } 221 222 DB.close(); 223 }catch(SQLiteException e) { 224 //異常終了 225 //ここも引っかかる(トーストが出る)******************** 226 Toast.makeText(activity, "保存に失敗しました", Toast.LENGTH_SHORT).show(); 227 return; 228 } 229 } 230}

###試したこと
一度データ削除をしたことで、データベース自体かもしくはテーブルが無くなり、ヘルパーのonCreateが上手く作動してないのかと思い、データベースの中身を見ようと試行錯誤しましたがそもそも見つからずじまいでした。

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

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

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

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

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

yona

2017/10/22 01:38

エラーログを質問に追記してください。
guest

回答1

0

ベストアンサー

こんにちは。
開けなくなるのが正常な動作ですので大丈夫です。SQLiteのデータベースを作ると、データベースのファイルは自アプリで読み書きできるディレクトリ下に作成されます。

例えば自アプリが「Sample」で、パッケージが「products.examples」、データベースファイル名が「sample.db」であれば、ファイルは
/data/data/examples.products.sample/databases/sample.db
として作成されます。これを本体の「設定」でアプリデータの消去をするとdatabases/sample.dbが削除されてしまうので、開けなくなります。
(ファイルの位置はAndroid Device Monitorや、場合にもよりますがadb shellでシェル上で確認することもできます)

アプリで適切にデータベースの作成をするコードがあるのであれば、本体を再起動させればまた正常に開けるようになるはずです。

「本体を再起動させれば」と書いたのは念の為で、データベースを作るコードがどこにあるか、ActivityのonCreateにある場合やonResumeなど、Activityのライフサイクルに関わるメソッドで変わってくるからです。onCreate上にあると、操作の流れによって呼び出されないことがあります。このあたりは「Android Activity ライフサイクル」などで検索して確認してみてください。


追記
ご提示いただいたコードを確認させてもらいました。このコードが全部ではないと言うことでしたが、少なくとも2点、問題を見つけましたので追記します。MySQLiteOpenHelper 内で生成しているSQLに問題があります。

1つ目、2つのカラムにプライマリキー指定がされているので、CREATE文の実行でエラー(Exception)になります。

Java

1//整数用テーブル作成 2 db.execSQL("CREATE TABLE " + TABLE_NAME_INTEGER + " (" 3 + COLUMN_NAME_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," 4 + COLUMN_NAME_INTEGER_NOMINAL + "TEXT PRIMARY KEY NOT NULL" 5 + COLUMN_NAME_INTEGER_VALUE + " INTEGER)");
# Exceptionの内容 android.database.sqlite.SQLiteException: table "integer_table" has more than one primary key (code 1): , while compiling: CREATE TABLE integer_table (_id INTEGER PRIMARY KEY AUTOINCREMENT,nominalTEXT PRIMARY KEY NOT NULLvalue INTEGER)

2つ目、INSERT文のSQLにも問題があり、正しくカラム名が指定できてません。

Java

1 db.execSQL("INSERT INTO " + TABLE_NAME_INTEGER + " VALUES(" 2 + RECORD_NAME_SALESAMOUNT + ",0)");
# Exceptionの内容 android.database.sqlite.SQLiteException: no such column: salesAmount (code 1): , while compiling: INSERT INTO integer_table VALUES(salesAmount,0)

ひとつの例ですが、以下のようなSQLにしてカラムを指定し、完成させる必要があるかと思います。

SQL

1INSERT INTO integer_table(nominal,value) VALUES ('salesAmount',0)

ご提示のコードでは上記のように途中でExceptionが発生し、完了しないのでテーブルが完成していません。
ただ、上の指摘はSQLの問題なので、データベースファイル自体はgetReadableDatabaseを呼び出した時点で作成されるはずです。その後、SQLiteOpenHelper.onCreateが呼ばれるはずですので、ブレークポイントを張って確認してみてください。尚、既にファイルがあればSQLiteOpenHelper.onCreateは呼ばれません。

ファイルはadb shellで確認できるのですが、実機を使っているとユーザーのパーミッションの関係で実行が失敗するかもしれません。以下はmacOS上のAndroidエミュレーターを相手として実行した結果です。myregister.dbファイルがあることが分かります。

Bash

1bash-3.2$ adb shell ls -l /data/data/examples.products.test27/databases/ 2-rw-rw---- u0_a57 u0_a57 24576 2017-10-23 04:23 myregister.db 3-rw------- u0_a57 u0_a57 8720 2017-10-23 04:23 myregister.db-journal

Test27と言うアプリ名、packageが examples.products で確認用アプリを作ったのでこのようなPATHになっています。

投稿2017/10/22 02:35

編集2017/10/22 19:52
dodox86

総合スコア9183

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

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

rinchu_17

2017/10/22 03:08

こんにちは。丁寧な解説ありがとうございます。 ファイルが作成される場所、データベース自体が消えてしまうことなど、勉強になりました。 ご指摘通りに本体を再起動してみましたが、依然変わらず・・・おそらく仰る通り、データベースを作成するコードの位置に問題があるのだと思いました。 ただ、ライフサイクルについても調べてみましたが、どのタイミングでデータベースを作成するのがベストなのかイマイチ理解出来ませんでしたので、恐縮ですが教えていただけますでしょうか。 (現在はonCreate内でSQLiteHelperを継承したクラスのインスタンスを作成しています)
dodox86

2017/10/22 04:03

あれ、ダメでしたか。確かに、回答した後に考えてみて確認中に何回かアプリを再インストールしていたかもしれないと思い、違う原因かもしれないと思い直しました。分かりづらかったですが、「本体の再起動」とはAndroid実機を電源OFF->ONで再起動しましたか。それでダメであれば、いったんアプリをアンインストールした後、再度インストールしてしてみてください。それでもダメなら実際のエラーメッセージとコードをご提示ください。
rinchu_17

2017/10/22 11:24

電源の再起動、再インストール、ともに治りませんでした。 質問本文の方にソースコードを追記いたしました。 エラーメッセージですが、LogCatの調子が悪く把握できておりません。申し訳ございません・・・。 親身なご回答、ありがとうございます。お忙しいところ恐縮ですが、よろしくお願いいたします。
rinchu_17

2017/10/22 21:24

わざわざ検証、エラーログまでありがとうございます、とても助かります。 SQLの構文にエラーがあったのですね・・・。ご指摘いただいた箇所、修正いたしました。 しかし、依然として改善せず、エラーログ見られないなりに色々試しまして、そもそもヘルパーのonCreateが呼ばれていないことが判明しました。 そこで、SQLiteDatabaseクラスのstaticメソッドを用いてデータベース自体を削除しまして(booleanが帰ってきますので確かに削除したことは確認できました)、再度インストールからやり直したのですが、それでもヘルパーのonCreateが呼ばれていません。データベース自体が無いのに、onCreateが呼ばれないなんてことはあるのでしょうか・・・? というような形で、そもそもonCreateが呼ばれていないことが問題であると特定できました。 この原因を探るために、自分なりに調べたり検証したりしてみたいと思います。 お心当たりございましたらコメント下さると幸いです。
rinchu_17

2017/10/22 21:35

連投ごめんなさい、onCreateが呼ばれていないと書きましたが、検証方法に不備があり、やはり呼ばれていたことがわかりました! さらに、ヘルパーのonCreate内でエラーが発生していることも確認できました。 取り急ぎSQL文のミスを探して、結果報告いたします!
rinchu_17

2017/10/22 21:42

見つけました!!! さきほどご指摘いただいた箇所を修正した際、カンマをひとつ消してしまっていたようです。 修正したところ、無事データベースを開けました! くだらないミスのためにお騒がせしてしまい申し訳ございません。 大変助かりました。ご尽力、感謝です。ありがとうございました。
dodox86

2017/10/23 00:50 編集

経過のご報告、どうもありがとうございます。動くようになって良かったです。先の回答でActivityのライフサイクルの話しを少し書きましたが、今のアプリであればタイミング的に今のまま、Activty#onCreateで良いと少なくとも個人的には思います。それが一般的だと思いますし。アプリの稼働中にアプリデータ/DBを消すのは意地悪なケースですので、「ああするとこうなる」と認識していれば当面、それで充分だと考えます。もし、例えばDBの存在チェックをしてToastで警告くらい出したいと言うのであれば、onResumeやonStartでの処理をご検討ください。アプリが突然落ちてしまうよりは親切かもしれません。
rinchu_17

2017/10/23 01:38

丁寧なアドバイス、ありがとうございます。ライフサイクルについて自分でも理解を深めていこうと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問