初めての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>