初めてのAndroidアプリを作りました
以下サイトを参考にして、登録日時を表示する機能を加えたメモアプリです。
アプリ名:ListMemo
Androidアプリ開発入門
http://androidguide.nomaki.jp/html/memo_app/memo_app_main.html
Google Play に登録しました。
https://play.google.com/store/apps/details?id=com.github.fumio_shimamura.listmemo
なおアイコンは、はてなココのものを使用しました。
http://d.hatena.ne.jp/tikeda/20101215/1292412046
主なソースコードを下に載せます。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.github.fumio_shimamura.listmemo" > <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".EditActivity" android:label="@string/edit_activity_title" > </activity> </application> </manifest>
MainActivity.java
package com.github.fumio_shimamura.listmemo; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.Toast; import java.io.BufferedReader; import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; public class MainActivity extends AppCompatActivity { // ListView 用アダプタ SimpleAdapter mAdapter = null; // ListView に設定するデータ List<Map<String, String>> mList = null; // 日時+SPACE(YYYY/MM/DD HH:MM )の文字数は19 public static final int DATE_LENGTH = 19; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // ListView 用アダプタのリストを生成 mList = new ArrayList<Map<String, String>>(); // ListView 用アダプタを生成 mAdapter = new SimpleAdapter( this, mList, android.R.layout.simple_list_item_2, new String [] {"title", "content"}, new int[] {android.R.id.text1, android.R.id.text2} ); // ListView にアダプターをセット ListView list = (ListView)findViewById(R.id.listView); list.setAdapter(mAdapter); // ListView のアイテム選択イベント list.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick( AdapterView<?> parent, View view, int pos, long id) { // 日時+タイトルから日時を削除する String title_tmp = mList.get(pos).get("title"); String title = removeDateFromTitle(title_tmp); // 編集画面に渡すデータをセットし、表示 Intent intent = new Intent(MainActivity.this, EditActivity.class); intent.putExtra("NAME", mList.get(pos).get("filename")); //intent.putExtra("TITLE", mList.get(pos).get("title")); intent.putExtra("TITLE", title); intent.putExtra("CONTENT", mList.get(pos).get("content")); startActivity(intent); } }); // ListView をコンテキストメニューに登録 registerForContextMenu(list); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement // menu_main.xmlでidを定義している if (id == R.id.action_add) { // 編集画面への遷移処理 Intent intent = new Intent(MainActivity.this, EditActivity.class); startActivity(intent); return true; } return super.onOptionsItemSelected(item); } @Override protected void onResume() { super.onResume(); // ListView 用アダプタのデータをクリア mList.clear(); // ここでファイルを読み込み、リスト表示処理を行う // アプリの保存フォルダ内のファイル一覧を取得 String savePath = this.getFilesDir().getPath().toString(); File[] files = new File(savePath).listFiles(); // ファイル名の降順でソート Arrays.sort(files, Collections.reverseOrder()); // テキストファイル(*.txt)を取得し、ListView用アダプタのリストにセット for (int i=0; i<files.length; i++) { String fileName = files[i].getName(); if (files[i].isFile() && fileName.endsWith(".txt")) { String title_tmp; String title = null; String content = null; // ファイルを読み込み try { // ファイルオープン InputStream in = this.openFileInput(fileName); BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8")); char[] buf = new char[(int)files[i].length()]; // タイトル(1行目)を読み込み //title = reader.readLine(); title_tmp = reader.readLine(); // ファイル名とタイトルを連結して日時+タイトルを作成する title = makeDateAndTitle(fileName,title_tmp); // 内容(2行目以降)を読み込み int num = reader.read(buf); if (num > 0) { content = new String(buf, 0, num); } // ファイルクローズ reader.close(); in.close(); } catch (Exception e) { Toast.makeText(this, "File read error!", Toast.LENGTH_LONG).show(); } // ListView用のアダプタにデータをセット Map<String, String> map = new HashMap<String, String>(); map.put("filename", fileName); map.put("title", title); map.put("content", content); mList.add(map); } } // ListView のデータ変更を表示に反映 mAdapter.notifyDataSetChanged(); } // ファイル名とタイトルを連結して日時+タイトルを作成する private String makeDateAndTitle(String filename, String title){ // ファイル名から日付を切り出す String file_date = filename.substring(0,8); // ファイル名から時刻を切り出す String file_time = filename.substring(9,13); // YYYY/MM/DD HH:MM + タイトルを返す return file_date.substring(0,4) + "-" + file_date.substring(4,6) + "-" + file_date.substring(6,8) + " " + file_time.substring(0,2) + ":" + file_time.substring(2,4) + " " + title; } // 日時+タイトルから日時を削除する private String removeDateFromTitle(String title){ // 先頭19文字は日時+SPACE(YYYY/MM/DD HH:MM )のため削除する。文字数は19。 return title.substring(DATE_LENGTH); } // コンテキストメニュー作成処理 @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) { super.onCreateContextMenu(menu, view, info); getMenuInflater().inflate(R.menu.main_context, menu); } // コンテキストメニュー選択処理 @Override public boolean onContextItemSelected(MenuItem item) { AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo(); switch(item.getItemId()) { case R.id.context_del: // [削除] 選択時の処理 // ファイル削除 if (this.deleteFile(mList.get(info.position).get("filename"))) { Toast.makeText(this, R.string.msg_del, Toast.LENGTH_SHORT).show(); } // リストからアイテム処理 mList.remove(info.position); // ListView のデータ変更を表示に反映 mAdapter.notifyDataSetChanged(); break; default: break; } return false; } }
EditActivity.java
package com.github.fumio_shimamura.listmemo; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.widget.EditText; import android.widget.Toast; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; /** * Created by shima on 2015/09/02. */ public class EditActivity extends AppCompatActivity { // 保存ファイル名 String mFileName = ""; // 保存なしフラグ boolean mNotSave = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_edit); // タイトルと内容入力用の EditText を取得 EditText eTxtTitle = (EditText)findViewById(R.id.eTxtTitle); EditText eTxtContent = (EditText)findViewById(R.id.eTxtContent); // メイン画面からの情報受け取り、EditTextに設定 // (情報がない場合(新規作成の場合)は、設定しない) Intent intent = getIntent(); String name = intent.getStringExtra("NAME"); if (name != null) { mFileName = name; eTxtTitle.setText(intent.getStringExtra("TITLE")); eTxtContent.setText(intent.getStringExtra("CONTENT")); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_edit, menu); return true; } @Override protected void onPause() { super.onPause(); // ここでファイル保存処理を行う // [削除] で画面を閉じるときは、保存しない if (mNotSave) { return; } // タイトル、内容を取得 EditText eTxtTitle = (EditText)findViewById(R.id.eTxtTitle); EditText eTxtContent = (EditText)findViewById(R.id.eTxtContent); String title = eTxtTitle.getText().toString(); String content = eTxtContent.getText().toString(); // タイトル、内容が空白の場合、保存しない if (title.isEmpty() && content.isEmpty()) { Toast.makeText(this, R.string.msg_destruction, Toast.LENGTH_SHORT).show(); return; } // ファイル名を生成 ファイル名 : yyyyMMdd_HHmmssSSS.txt // (既に保存されているファイルは、そのままのファイル名とする) if (mFileName.isEmpty()) { Date date = new Date(System.currentTimeMillis()); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.JAPAN); mFileName = sdf.format(date) + ".txt"; } // 保存 OutputStream out = null; PrintWriter writer = null; try{ out = this.openFileOutput(mFileName, Context.MODE_PRIVATE); writer = new PrintWriter(new OutputStreamWriter(out,"UTF-8")); // タイトル書き込み writer.println(title); // 内容書き込み writer.print(content); writer.close(); out.close(); }catch(Exception e){ Toast.makeText(this, "File save error!", Toast.LENGTH_LONG).show(); } } // メニュー選択時の処理 @Override //public boolean onMenuItemSelected(int featureId, MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()) { case R.id.action_del: // [削除] 選択処理 // ファイル削除 if (!mFileName.isEmpty()) { this.deleteFile(mFileName); } // 保存せずに、画面を閉じる mNotSave = true; this.finish(); break; default: break; } //return super.onMenuItemSelected(featureId, item); return super.onOptionsItemSelected(item); } }
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:background="#FFD5D5D5" tools:context=".MainActivity"> <ListView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/listView" android:layout_centerVertical="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:background="#FFE3E3E3" android:divider="#FFD5D5D5" android:dividerHeight="8dp" /> </RelativeLayout>
activity_edit.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <EditText android:id="@+id/eTxtTitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/hint_title" android:textSize="22sp" android:layout_marginBottom="5dip" android:inputType="text" /> <EditText android:id="@+id/eTxtContent" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/hint_content" android:textSize="18sp" android:gravity="top|start" android:layout_below="@+id/eTxtTitle" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_alignParentBottom="true" /> </RelativeLayout>
string.xml
<resources> <!-- AndroidManifest.xml --> <string name="app_name">ListMemo</string> <string name="edit_activity_title">Edit</string> <!-- MainActivity.java --> <string name="msg_del">Deleted</string> <!-- EditActivity.java --> <string name="msg_destruction">Canceled</string> <!-- activity_edit.xml --> <string name="hint_title">Title</string> <string name="hint_content">Content</string> <!-- main_context.xml --> <string name="context_del">Delete</string> <!-- menu_edit.xml --> <string name="action_delete">Delete</string> <!-- menu_main.xml --> <string name="action_add">Add</string> </resources>