苦節三週間。。。
遂にスマホアプリが出来た🎵
やったこと
・ボタン名整理
・ボタン処理時のバグ取り
・ファイル名取得
・ボタン名整理
ボタン名等を以下のとおりとした。
①保存File名を入力してください
音声テキスト変換したテキストをこのファイルに保存します。
②削除するFile名を入力してください
このファイルを削除します。
③音声入力してください
この文言の下のテキストエリアにカーソルを合わせて、Google音声入力としたあと、音声入力します。
④保存ボタン
このボタンを押すと上で定義したファイルにテキストが保存される。
⑤表示ボタン
このボタンを押すと上記の保存Fileに格納されているテキストが表示される。
⑥削除Fileボタン
このボタンを押すと、上記の削除するFile名に記載されたファイルが削除される。
また、何もファイル名がないあるいは、存在しないファイル名の場合は、存在するファイル名一覧を表示する。
⑦クリア
音声入力エリアと表示エリアをクリアします。
ただし、保存File名と削除File名はクリアしません。
※ここもクリアできますが残した方が使いやすいと思います
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Speech to Text</string>
<string name="file_name">保存File名を入力してください</string>
<string name="del_file_name">削除するFile名を入力してください</string>
<string name="tv_name">音声入力してください</string>
<string name="bt_click">保存</string>
<string name="bt_click1">表示</string>
<string name="bt_click2">File削除</string>
<string name="bt_clear">クリア</string>
</resources>
・ボタン処理時のバグ取り
削除Fileが存在しないのに削除しようとするとバグってアプリが落ちてしまいます。
そこで、それを検知して以下のように回避しました。
【参考】
Null Safety
val file1 = File(pathUtf8+"/"+ inputStr_delfile)
if (file1 != null && file1.length() > 0) {
file1.delete()
} else {
//file.delete()
}
・ファイル名取得
削除Fileボタンを押したときの振舞いが以下のとおりです。
削除部分のコードは上記のとおりですが、それ以外の部分でファイル一覧を表示しています。
ここでは以下の3つを参考としています。
【参考】
①【Android/Java】アプリ内のファイルの操作
②Using Replace function in Kotlin
③Kotlinの文字列を連結する
すなわち
①ファイルが存在するPathを取得し、ファイル名の一覧を取得する
var pathUtf8 = getFilesDir().getAbsolutePath();
//ファイル名の一覧を取得する
val file = File(pathUtf8)
val files = file.listFiles()
②③ファイルのPathを””に置き換えてファイル名のみにし、取得したファイル一覧を表示する
※コードは短いけど適度にハマりました
//取得した一覧を表示する
var f =""
for (i in files.indices) {
val fi= files[i]
val files_: String = fi.toString().replace( pathUtf8+ "/" ,"")
f = "ファイル" + (i + 1) +" "+ files_ +"\n"+ f
}
output.text = f
この部分のコード
R.id.btClick2 -> {
var pathUtf8 = getFilesDir().getAbsolutePath();
//ファイル名の一覧を取得する
val file = File(pathUtf8)
val files = file.listFiles()
//取得した一覧を表示する
var f =""
for (i in files.indices) {
val fi= files[i]
val files_: String = fi.toString().replace( pathUtf8+ "/" ,"")
f = "ファイル" + (i + 1) +" "+ files_ +"\n"+ f
}
output.text = f
val file1 = File(pathUtf8+"/"+ inputStr_delfile)
if (file1 != null && file1.length() > 0) {
file1.delete()
} else {
//file.delete()
}
}
完成イメージ
長いファイル名 | 多様な言語 |
---|---|
![]() |
![]() |
まとめ
・音声テキスト変換アプリが完成した
・ファイル名は何語でも長くても使えた
・GooglePlayに登録しようと思う
おまけ
MainActivity.kt
package com.example.hellosample
import android.content.Context
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//表示ボタンであるButtonオブジェクトを取得。
val btClick = findViewById<Button>(R.id.btClick)
//表示ボタンであるButtonオブジェクトを取得。
val btClick1 = findViewById<Button>(R.id.btClick1)
//表示ボタンであるButtonオブジェクトを取得。
val btClick2 = findViewById<Button>(R.id.btClick2)
//リスナクラスのインスタンスを生成。
val listener = HelloListener()
//表示ボタンにリスナを設定。
btClick.setOnClickListener(listener)
//表示ボタンにリスナを設定。
btClick1.setOnClickListener(listener)
//表示ボタンにリスナを設定。
btClick2.setOnClickListener(listener)
//クリアボタンであるButtonオブジェクトを取得。
val btClear = findViewById<Button>(R.id.btClear)
//クリアボタンにリスナを設定。
btClear.setOnClickListener(listener)
}
/**
* ボタンをクリックしたときのリスナクラス。
*/
private inner class HelloListener : View.OnClickListener {
override fun onClick(view: View) {
//名前入力欄であるEditTextオブジェクトを取得。
val input = findViewById<EditText>(R.id.etName)
//名前入力欄であるEditTextオブジェクトを取得。
val input_file = findViewById<EditText>(R.id.fileName)
//名前入力欄であるEditTextオブジェクトを取得。
val input_delfile = findViewById<EditText>(R.id.delfileName)
//メッセージを表示するTextViewオブジェクトを取得。
val output = findViewById<TextView>(R.id.tvOutput)
//入力された名前文字列を取得。
val inputStr = input.text.toString()
//入力された名前文字列を取得。
val inputStr_file = input_file.text.toString()
//入力された名前文字列を取得。
val inputStr_delfile = input_delfile.text.toString()
val df = SimpleDateFormat("HH:mm:ss") //"yyyy/MM/dd HH:mm:ss"
val date = Date()
//input_count.setText("0")
//idのR値に応じて処理を分岐。
when(view.id) {
//表示ボタンの場合…
R.id.btClick -> {
//入力された名前文字列を取得。
val inputStr = input.text.toString()
//入力された名前文字列を取得。
val inputStr_file = input_file.text.toString()
//メッセージを表示。
val inputStr1 = df.format(date) + "\n"+inputStr
output.text = inputStr1 //df.format(date) + "\n"+inputStr
//val fOut = openFileOutput("testfile.txt", Context.MODE_PRIVATE)
val fOut = openFileOutput(inputStr_file, Context.MODE_PRIVATE)
fOut.write(inputStr1.toByteArray())
fOut.close()
}
R.id.btClick1 -> {
var temp=""
var pathUtf8 = getFilesDir().getAbsolutePath(); //"com.example.hellosample/files/testfile.txt"
//temp = File(pathUtf8+"/testfile.txt").readText(Charsets.UTF_8)
temp = File(pathUtf8+"/"+ inputStr_file).readText(Charsets.UTF_8)
output.text = temp //df.format(date) + "\n" + temp
input.setText("")
}
R.id.btClick2 -> {
var pathUtf8 = getFilesDir().getAbsolutePath();
//ファイル名の一覧を取得する
val file = File(pathUtf8)
val files = file.listFiles()
//取得した一覧を表示する
var f =""
for (i in files.indices) {
val fi= files[i]
val files_: String = fi.toString().replace( pathUtf8+ "/" ,"")
f = "ファイル" + (i + 1) +" "+ files_ +"\n"+ f
}
output.text = f
val file1 = File(pathUtf8+"/"+ inputStr_delfile)
if (file1 != null && file1.length() > 0) {
file1.delete()
} else {
//file.delete()
}
}
//クリアボタンの場合…
R.id.btClear -> {
//名前入力欄を空文字に設定。
input.setText("")
//メッセージ表示欄を空文字に設定。
output.text = ""
}
}
}
}
}
activitymain.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/tv_name"/>
<EditText
android:id="@+id/etName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="保存File名を入力してください"/>
<EditText
android:id="@+id/fileName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="削除するFile名を入力してください"/>
<EditText
android:id="@+id/delfileName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btClick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bt_click"/>
<Button
android:id="@+id/btClick1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bt_click1" />
<Button
android:id="@+id/btClick2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bt_click2" />
<Button
android:id="@+id/btClear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bt_clear"/>
</LinearLayout>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".MainActivity">
<TextView
android:id="@+id/tvOutput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:text=""
android:textSize="25sp" />
</ScrollView>
</LinearLayout>
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Speech to Text</string>
<string name="file_name">保存File名を入力してください</string>
<string name="del_file_name">削除するFile名を入力してください</string>
<string name="tv_name">音声入力してください</string>
<string name="bt_click">保存</string>
<string name="bt_click1">表示</string>
<string name="bt_click2">File削除</string>
<string name="bt_clear">クリア</string>
</resources>