1.はじめに
山田著「初めてのAndroid開発Kotlin編」の478ページにStorage Access Framework(SAF)を利用してテキストファイルを開くサンプルアプリが掲載されている。このアプリは、起動した直後にファイル選択画面が呼び出されるのだが、この点に少し不満を感じた。
そこで、改造してオプションメニューを付けることとした。
動作のイメージは以下のスクリーンショットを参考にしてください。
2.参考文献
山田著「初めてのAndroid開発Kotlin編」
p411,478
3.ソースコード
(ソースコードをGithub上に公開しました。
Git(GitHub)のtag:SAF_OptionMenu(コミットハッシュ:5ce75e0e57d52181396fd25e6728cbf3251fa910)がこの記事と同じレビジョンだと思います。間違えていたらごめんなさい。)
今後、時々、機能が追加され、コードが増えていきます。)
3.1 オプションメニューを表示する領域を確保するために、アクションバーを表示する
以前投稿した「メニューバーを表示する方法」を参考にしてください。
3.2 MainActivity
参考文献p478と比べ、MainActivbityで工夫した点は、同p411のように変数startForResultを作り、ActivityResultLancherのインスタンスを代入したこと。変数startForResultはonCreate()メソッドとonOptionsItemSelected()メソッドの両方で使われるので、クラス直下の変数とし、遅延初期化(lateinit)とした。
変数startForResultがActivityResultLancher<I>型(クラス)であることは、参考文献p411に掲載されていたが、そのIが何総称型(ジェネリックス)かわからず、とりあえずコードを打ち込んでみたら、IntentであることをAndroidStuidoが教えてくれた(さすが、AndroidStuido、ほっとした。)
package io.github.let_us_study_with_textvoice.textvoiceplayerforandroid
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.widget.TextView
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
class MainActivity : AppCompatActivity() {
lateinit var startForResult : ActivityResultLauncher<Intent>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
val textSTS = findViewById<TextView>(R.id.textSTS)
// ファイル選択画面を起動するための準備と、ファイル選択後の処理
startForResult = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
// 選択時の処理
if (result.resultCode == RESULT_OK) {
result.data?.data?.let {
val str = StringBuilder()
// ファイルから行単位に読み込み、その内容をStringBuilderに保存
contentResolver.openInputStream(it)
?.bufferedReader()
?.forEachLine {
str.append(it)
str.append(System.lineSeparator())
}
// StringBuilderの内容をテキストエリアに反映
textSTS.setText(str.toString())
}
}
}
}
// StorageAccessFramewokeを使って、ファイルを選択する
fun openSTS_a() {
startForResult.launch(
Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
type = "text/plain"
putExtra(Intent.EXTRA_TITLE, "textSTS.txt")
// Android端末の\sdscar\Downloadディレクトリに何かテキストファイルを入れておく。
}
)
}
// オプションメニューのビューをインフレートする
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.option_menu, menu)
return super.onCreateOptionsMenu(menu)
}
// オプションメニューを選択した時の処理
override fun onOptionsItemSelected(item: MenuItem): Boolean {
Log.d("itemtitle", item.title.toString())
when (item.itemId) {
R.id.menuListOptionOpenVoice -> {}
R.id.menuListOptionOpenSTS -> { openSTS_a() }
R.id.menuListOptionOpenVoiceSTS -> {}
}
return super.onOptionsItemSelected(item)
}
}
3.3 その他のコード
その他のactivity_main.xmlやoption_menu.xmlは特別変わったことをしていないので掲載を省略します。参考文献などを参照してください。
#4 今後の予定
このアプリは、以前紹介した語学学習用アプリ TextVoicePlayerのAndroid版にです。今後、音声ファイルを再生するよう作り込んでいきます。