どうも、tatsuです!
今回はメモ帳アプリ制作その4ということでやっていこうと思います。
わからない箇所は他の記事を参考にしてみてください。
※この記事で使用しているAndroid Studioのバージョンは2.3.3です。
目次
作成手順
メモ帳アプリを作る上で必要な手順を以下にまとめました。
本記事では⑤と⑥を紹介します。
①②③④は以下の記事を参照してください。
- 新しくプロジェクトを作る
- 画面レイアウトを作る
- 画面に動きをつける
- データベースに保存する
- テスト&手直し
- 完成物披露
⑤テスト&手直し
それでは作成したメモ帳がきちんと動作するかをテストしたいと思います。
簡単ですが、以下のテストを行います。
- リスト画面で新規作成ボタンクリック⇒メモ作成画面に遷移すること
- メモ作成画面で登録ボタンをクリック⇒リスト画面に遷移して、登録した内容が一覧に表示されること
- メモ作成画面で戻るボタンをクリック⇒リスト画面に遷移して、入力した内容は破棄されること
- リスト画面で一覧から項目をクリック⇒メモ作成画面に遷移して、以前登録した内容が表示されること
- リスト画面で一覧から項目をクリック⇒メモ作成画面で編集して登録ボタンをクリック⇒リスト画面に遷移して内容が更新されていること
テスト1
リスト画面で新規作成ボタンクリック⇒メモ作成画面に遷移することを確認します。
1. アプリを立ち上げ、新規作成ボタンをクリックします。
2. メモ作成画面に遷移することを確認します。
テスト2
メモ作成画面で登録ボタンをクリック⇒リスト画面に遷移して、登録した内容が一覧に表示されることを確認します。
1. アプリを立ち上げ、新規作成ボタンをクリックします。
2. メモ作成画面に遷移することを確認します。
3. メモを記入して登録ボタンをクリックします。
4. リスト画面に遷移して、登録した内容が一覧に表示されることを確認します。
テスト3
メモ作成画面で戻るボタンをクリック⇒リスト画面に遷移して、入力した内容は破棄されることを確認します。
1. メモ作成画面で戻るボタンをクリックします。
2. リスト画面に遷移して、入力した内容は破棄されることを確認します。
テスト4
リスト画面で一覧から項目をクリック⇒メモ作成画面に遷移して、以前登録した内容が表示されることを確認します。
1. リスト画面で一覧から項目をクリックします。
2. メモ作成画面に遷移して、以前登録した内容が表示されることを確認します。
テスト5
リスト画面で一覧から項目をクリック⇒メモ作成画面で編集して登録ボタンをクリック⇒リスト画面に遷移して内容が更新されていることを確認します。
1. リスト画面で一覧から項目をクリックします。
2. メモ作成画面で編集して登録ボタンをクリックします。
3. リスト画面に遷移して内容が更新されていることを確認します。
手直し
みなさんお気づきでしょうか・・・
そう!このメモ帳アプリ、メモを削除できません!!笑
ということで項目長押しで削除する処理を追加します。
ListActivity.javaのリスト項目クリック処理の下に以下の処理を追加してください。
これで項目長押しで削除されるようになりました!
// リスト項目を長押しクリックした時の処理 listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener(){ /** * @param parent ListView * @param view 選択した項目 * @param position 選択した項目の添え字 * @param id 選択した項目のID */ public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { // 選択されたビューを取得 TwoLineListItemを取得した後、text2の値を取得する TwoLineListItem two = (TwoLineListItem)view; TextView idTextView = (TextView)two.getText2(); String idStr = (String) idTextView.getText(); // 長押しした項目をデータベースから削除 SQLiteDatabase db = helper.getWritableDatabase(); try { db.execSQL("DELETE FROM MEMO_TABLE WHERE uuid = '"+ idStr +"'"); } finally { db.close(); } // 長押しした項目を画面から削除 memoList.remove(position); simpleAdapter.notifyDataSetChanged(); // trueにすることで通常のクリックイベントを発生させない return true; } });
⑥完成物披露
最後に完成したメモ帳アプリのソースコードを全て紹介します。
今回リファクタリングを全くしていないのでソースが汚いと思います。時間がある方は知識の再確認の意味でリファクタリングもしてみてください。笑
ListActivity.java
public class ListActivity extends AppCompatActivity { // MemoOpenHelperクラスを定義 MemoOpenHelper helper = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_list); // データベースから値を取得する if(helper == null){ helper = new MemoOpenHelper(ListActivity.this); } // メモリストデータを格納する変数 final ArrayList<HashMap<String, String>> memoList = new ArrayList<>(); // データベースを取得する SQLiteDatabase db = helper.getWritableDatabase(); try { // rawQueryというSELECT専用メソッドを使用してデータを取得する Cursor c = db.rawQuery("select uuid, body from MEMO_TABLE order by id", null); // Cursorの先頭行があるかどうか確認 boolean next = c.moveToFirst(); // 取得した全ての行を取得 while (next) { HashMap<String,String> data = new HashMap<>(); // 取得したカラムの順番(0から始まる)と型を指定してデータを取得する String uuid = c.getString(0); String body = c.getString(1); if(body.length() > 10){ // リストに表示するのは10文字まで body = body.substring(0, 11) + "..."; } // 引数には、(名前,実際の値)という組合せで指定します 名前はSimpleAdapterの引数で使用します data.put("body",body); data.put("id",uuid); memoList.add(data); // 次の行が存在するか確認 next = c.moveToNext(); } } finally { // finallyは、tryの中で例外が発生した時でも必ず実行される // dbを開いたら確実にclose db.close(); } // Adapter生成 final SimpleAdapter simpleAdapter = new SimpleAdapter(this, memoList, // 使用するデータ android.R.layout.simple_list_item_2, // 使用するレイアウト new String[]{"body","id"}, // どの項目を new int[]{android.R.id.text1, android.R.id.text2} // どのidの項目に入れるか ); // idがmemoListのListViewを取得 ListView listView = (ListView) findViewById(R.id.memoList); listView.setAdapter(simpleAdapter); // リスト項目をクリックした時の処理 listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){ /** * @param parent ListView * @param view 選択した項目 * @param position 選択した項目の添え字 * @param id 選択した項目のID */ public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // インテント作成 第二引数にはパッケージ名からの指定で、遷移先クラスを指定 Intent intent = new Intent(ListActivity.this, com.android.tatsu.simplememo.CreateMemoActivity.class); // 選択されたビューを取得 TwoLineListItemを取得した後、text2の値を取得する TwoLineListItem two = (TwoLineListItem)view; // TextView idTextView = (TextView)two.findViewById(android.R.id.text2); TextView idTextView = (TextView)two.getText2(); String idStr = (String) idTextView.getText(); // 値を引き渡す (識別名, 値)の順番で指定します intent.putExtra("id", idStr); // Activity起動 startActivity(intent); } }); // リスト項目を長押しクリックした時の処理 listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener(){ /** * @param parent ListView * @param view 選択した項目 * @param position 選択した項目の添え字 * @param id 選択した項目のID */ public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { // 選択されたビューを取得 TwoLineListItemを取得した後、text2の値を取得する TwoLineListItem two = (TwoLineListItem)view; TextView idTextView = (TextView)two.getText2(); String idStr = (String) idTextView.getText(); // 長押しした項目をデータベースから削除 SQLiteDatabase db = helper.getWritableDatabase(); try { db.execSQL("DELETE FROM MEMO_TABLE WHERE uuid = '"+ idStr +"'"); } finally { db.close(); } // 長押しした項目を画面から削除 memoList.remove(position); simpleAdapter.notifyDataSetChanged(); // trueにすることで通常のクリックイベントを発生させない return true; } }); /** * 新規作成するボタン処理 */ // idがnewButtonのボタンを取得 Button newButton = (Button) findViewById(R.id.newButton); // clickイベント追加 newButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // CreateMemoActivityへ遷移 Intent intent = new Intent(ListActivity.this, com.android.tatsu.simplememo.CreateMemoActivity.class); intent.putExtra("id", ""); startActivity(intent); } }); } }
activity_list.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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" tools:context="com.android.tatsu.simplememo.ListActivity"> <ListView android:id="@+id/memoList" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="9"/> <Button android:id="@+id/newButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="新規作成する" /> </LinearLayout>
CreateMemoActivity.java
public class CreateMemoActivity extends AppCompatActivity { // MemoOpenHelperクラスを定義 MemoOpenHelper helper = null; // 新規フラグ boolean newFlag = false; // id String id = ""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_create_memo); // データベースから値を取得する if(helper == null){ helper = new MemoOpenHelper(CreateMemoActivity.this); } // ListActivityからインテントを取得 Intent intent = this.getIntent(); // 値を取得 id = intent.getStringExtra("id"); // 画面に表示 if(id.equals("")){ // 新規作成の場合 newFlag = true; }else{ // 編集の場合 データベースから値を取得して表示 // データベースを取得する SQLiteDatabase db = helper.getWritableDatabase(); try { // rawQueryというSELECT専用メソッドを使用してデータを取得する Cursor c = db.rawQuery("select body from MEMO_TABLE where uuid = '"+ id +"'", null); // Cursorの先頭行があるかどうか確認 boolean next = c.moveToFirst(); // 取得した全ての行を取得 while (next) { // 取得したカラムの順番(0から始まる)と型を指定してデータを取得する String dispBody = c.getString(0); EditText body = (EditText)findViewById(R.id.body); body.setText(dispBody, TextView.BufferType.NORMAL); next = c.moveToNext(); } } finally { // finallyは、tryの中で例外が発生した時でも必ず実行される // dbを開いたら確実にclose db.close(); } } /** * 登録ボタン処理 */ // idがregisterのボタンを取得 Button registerButton = (Button) findViewById(R.id.register); // clickイベント追加 registerButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 入力内容を取得する EditText body = (EditText)findViewById(R.id.body); String bodyStr = body.getText().toString(); // データベースに保存する SQLiteDatabase db = helper.getWritableDatabase(); try { if(newFlag){ // 新規作成の場合 // 新しくuuidを発行する id = UUID.randomUUID().toString(); // INSERT db.execSQL("insert into MEMO_TABLE(uuid, body) VALUES('"+ id +"', '"+ bodyStr +"')"); }else{ // UPDATE db.execSQL("update MEMO_TABLE set body = '"+ bodyStr +"' where uuid = '"+id+"'"); } } finally { // finallyは、tryの中で例外が発生した時でも必ず実行される // dbを開いたら確実にclose db.close(); } // 保存後に一覧へ戻る Intent intent = new Intent(CreateMemoActivity.this, com.android.tatsu.simplememo.ListActivity.class); startActivity(intent); } }); /** * 戻るボタン処理 */ // idがbackのボタンを取得 Button backButton = (Button) findViewById(R.id.back); // clickイベント追加 backButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 保存せずに一覧へ戻る finish(); } }); } }
activity_create_memo.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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" tools:context="com.android.tatsu.simplememo.CreateMemoActivity"> <EditText android:id="@+id/body" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="20sp" android:inputType="textMultiLine" android:lines="50" android:layout_weight="9" android:gravity="top|left" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_weight="1"> <Button android:id="@+id/register" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="登録する" /> <Button android:id="@+id/back" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="戻る" /> </LinearLayout> </LinearLayout>
MemoOpenHelper.java
public class MemoOpenHelper extends SQLiteOpenHelper { // データベース名 static final private String DBName = "MEMO_DB"; // データベースのバージョン(2,3と挙げていくとonUpgradeメソッドが実行される) static final private int VERSION = 1; // コンストラクタ 以下のように呼ぶこと public MemoOpenHelper(Context context){ super(context, DBName, null, VERSION); } // データベースが作成された時に実行される処理 // データベースはアプリを開いた時に存在しなかったら作成され、すでに存在していれば何もしない @Override public void onCreate(SQLiteDatabase db) { /** * テーブルを作成する * execSQLメソッドにCREATET TABLE命令を文字列として渡すことで実行される * 引数で指定されているものの意味は以下の通り * 引数1 ・・・ id:列名 , INTEGER:数値型 , PRIMATY KEY:テーブル内の行で重複無し , AUTOINCREMENT:1から順番に振っていく * 引数2 ・・・ uuid:列名 , TEXT:文字列型 * 引数3 ・・・ body:列名 , TEXT:文字列型 */ db.execSQL("CREATE TABLE MEMO_TABLE (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "uuid TEXT, " + "body TEXT)"); } // データベースをバージョンアップした時に実行される処理 @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { /** * テーブルを削除する */ db.execSQL("DROP TABLE IF EXISTS MEMO_TABLE"); // 新しくテーブルを作成する onCreate(db); } }
まとめ
いかがでしたか?
今回をもちまして、メモ帳を作ろう!シリーズは完結となります。
本ブログの記事を見て、これからAndroidアプリを作ろうと思っている方のお役にたてれば幸いです!
では!
非常に勉強になります。
本当にありがとうございます。
スマホでアプリプログラムに興味穂持ち入門中です
上から下に流すだけのスクリプト的なやつは、書いたことが有るのですが敷居が高いですね
因みにidを日時で作成編集表示出来るようにと苦戦しています。。てか。。発想だけの状態ですが(笑)
こんにちは先月はteratailのほうで間違った使い方をしてご迷惑をおかけして申し訳けございません。
ひとつだけ質問があるのですがcreatememoActivityとは別で音声入力機能を搭載したアプリを追加して作っております。そこで質問なのですがcreateActivityのように登録するをクリックするとlistActivityに戻って保存されてるようにするにはどのコードを使えばいいのでしょうか?もしお時間があるときでいいので答えてくださるとありがたいです。
こんにちは。
メモ帳アプリで使われているコードの中からという意味でしたら、CreateMemoActivityの「登録ボタン処理」というコメントがついている部分が該当箇所かと思われます。
こんにちはリスト画面にIdではなくdataクラス型で日付を表示するにはどのようにすればいいでしょうか?
// 現在の時刻を取得
Date date = new Date();
// 表示形式を設定
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy’年’MM’月’dd’日’ kk’時’mm’分’ss’秒'”);
dateText.setText(sdf.format(date));
これを組み込みたいとおもってるのですがなかなかうまくいきませんこれで最後なので教えていただけるとありがたいです。
それであれば、日付を保存するカラムをテーブルに追加しなければなりません。
次に、メモ登録(INSERT)時にnew Date()で取得した値を日付カラムに入れてあげます。
最後に、一覧取得時に取得しているid部分を日付に変更してあげればできるかと思います。
また、質問とは関係がありませんが、実名である必要はないのでもう少しきちんとした名前でコメントしていただけると助かります。
名前を呼ぶときに困ってしまうので・・w
こんにちは前の回答でわかりそうでわからないです。
1 日付を保存するカラムをテーブルに追加 MemoOpen.javaに日付用のカラムを追加
db.execSQL(“CREATE TABLE MEMO_TABLE (” +
“id INTEGER PRIMARY KEY AUTOINCREMENT, ” +
“uuid TEXT, ” +
“body TEXT)”);
であったってるでしょうか?現状2個ある状況です。語彙力壊滅級で申し訳ないです値は変える予定です。
はい、そのSQLにカラムを追加しましょう。
また、すでにスマートフォンの方にはテーブルが作成されているため、MemoOpenHelper内のバージョンを上げる必要があるかと思います。(バージョンを上げることでテーブルが作り直されます)
ありがとうございます今現状memoopenhelper内に2つある状況です(バージョンアップ済み)次にcreatememoActivityに一部変更しました
// 入力内容を取得する
EditText dateText = (EditText)findViewById(R.id.body);
String dateText = body.getText().toString();
Date date = new Date();
// 表示形式を設定
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy’年’MM’月’dd’日’ kk’時’mm’分’ss’秒’”);
dateText.setText(sdf.format(date));
のコードを追加しました。
qestion2 new Date()で取得した値を日付カラムに入れてあげます
new Dateの値とは上記のコードで言うdateの部分でしょうか?
長文で申し訳ないです
なにが2つあるのでしょうか?CREATEのSQLであれば新しいほうだけで良いです。
new Dateとはdateの部分です。
ありがとうございます。なんとかできました!
メモ帳を作ってみたかったのですごく参考になりました!
ソースコードの一部を利用してアプリをリリースしてみたいのですが大丈夫でしょうか?
どうぞ^^
ありがとうございます!!