質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Q&A

解決済

3回答

1300閲覧

ArraylistのArrayIndexOutOfBoundsExceptionを解決したい

Cider_docx

総合スコア0

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

0グッド

0クリップ

投稿2021/07/06 17:50

編集2021/07/06 18:10

前提・実現したいこと

Android StudioでAndroidアプリを開発しています。
内部ストレージ内のMusicフォルダに格納されているmp3ファイルとディレクトリを読み込んでリストで表示させ、ファイルをタッチした場合は再生し、ディレクトリをタッチした場合はディレクトリの中身をさらに表示し、その中のファイルをタッチすると再生するというものです。

発生している問題・エラーメッセージ

参照するディレクトリ直下に置かれているmp3ファイルは表示され、再生されるのですが、ディレクトリをタッチすると、中身のファイル一覧は表示されるのですが、タッチするとアプリがクラッシュしてしまいます。
おそらく、最初に作った配列が残ってしまっているものだと思うのですが、どのように解決して良いのかわかりません。

java.lang.ArrayIndexOutOfBoundsException: length=4; index=5 at com.example.mp3player_process.MainActivity$1.onItemClick(MainActivity.java:65)

該当のソースコード

package com.example.mp3player_process; import android.media.MediaPlayer; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CompoundButton; import android.widget.ListView; import androidx.appcompat.app.AppCompatActivity; import com.google.android.material.switchmaterial.SwitchMaterial; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { //メディアプレイヤーフィールドを作成 private MediaPlayer _player = null; //音楽リスト格納フィールド作成 private List<String> songList = new ArrayList<>(); private ListView lv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //アダプターの作成 lv = findViewById(R.id.songList); songList = new ArrayList<>(); //指定したディレクトリ内のmp3フォルダすべて読み込み File songDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC); String songPath = songDir.getPath(); File[] files = new File(songPath).listFiles(); ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, songList); if (files != null) { //Musicディレクトリ以下のmp3ファイルをリストに格納 for (int i = 0; i < files.length; i++) { //ファイルであること、.mp3で名前が終わっている事を条件にリストに追加 if (files[i].isFile() && files[i].getName().endsWith(".mp3")) { songList.add(files[i].getName()); //ディレクトリだった場合… } else if (files[i].isDirectory()) { songList.add(files[i].getName()); } } //アダプターをセット lv.setAdapter(adapter); lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //タッチした項目がファイルだった場合… Log.d("onClick", "取得したパスは"+files[position].getAbsolutePath()+""); ListView listView = (ListView) parent; //songの中にはパスが入っている?(ファイル名?) String song = (String) listView.getItemAtPosition(position); //フルパスを取っておく String Fpath = files[position].getAbsolutePath(); play(Fpath); //タッチした項目がディレクトリだった場合… if (files[position].isDirectory()){ Log.d("onClick", "取得したパスは"+files[position].getAbsolutePath()+""); //リストを初期化 songList.clear(); lv.setAdapter(adapter); //選択したディレクトリの中にあるmp3ファイルを格納するフィールド作成 File songDir = new File(files[position].getAbsolutePath()); Log.d("OnclickDir", "取得したディレクトリのパスは"+songDir+"です"); String selectedDirPath = songDir.getPath(); File[] Selectedfiles = new File(selectedDirPath).listFiles(); if (Selectedfiles != null) { //タッチしたディレクトリ内のmp3フォルダすべて読み込み for (int i = 0; i < Selectedfiles.length; i++){ if (Selectedfiles[i].isFile() && Selectedfiles[i].getName().endsWith("mp3")) { //ファイル名をリストに収納 songList.add(Selectedfiles[i].getName()); Log.d("selectedDir", i+"番目に"+ Selectedfiles[i].getName()+"が格納されました"); } } } lv.setAdapter(adapter); Log.d("OnclickDir", "現在の配列の長さは"+ Selectedfiles.length+"です"); } } }); } //ループ処理 SwitchMaterial loopswitch = findViewById(R.id.swloop); //リピート再生のスイッチのリスナ loopswitch.setOnCheckedChangeListener(new LoopSwitchChangedListener()); }

試したこと

配列の参照がおかしいことがわかっているのですが、どのようにコードを書き換えてよいかわかりません。

補足情報(FW/ツールのバージョンなど)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2021/07/06 18:53

表示項目の参照に files と songList の両方が使われてますが、ディレクトリを選択すると songList だけ更新されて files はそのままだからでしょうね…。
Cider_docx

2021/07/07 02:53

filesの更新を試みているのですが、更新の仕方がわかりません…
hoshi-takanori

2021/07/07 03:22

files を更新できるようにするには、files をローカル変数ではなくフィールドにする必要があります。 また、files から songList を作るときに、条件によっては songList に追加しないこともあるため、files と songList の要素数が食い違う可能性もあるので、できればどちらか片方に統一したいところです…。
Cider_docx

2021/07/07 18:56

filesをnewして、更新するようにしたら解決しました。ありがとうございました。重ねて質問なのですが、filesとsonglistどちらかに統一するとしたらどのように改善すればよいでしょうか。おそらく選択したディレクトリ内に何も入っていない場合にエラーが出てしまう可能性がある、ということですよね?
guest

回答3

0

その例外は、リストの範囲を超えてアクセスしようとしたときに出るもんです
まずは、そいつがでた行にでてくるリストのサイズと、アクセスしようとしているインデックスの数値を確認してみては

投稿2021/07/06 21:34

y_waiwai

総合スコア88042

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Cider_docx

2021/07/07 03:01

回答ありがとうございます。リストの範囲を超えてアクセスしようとしていることはわかっているのですが、それをどうやって直せばよいのかわからず、困っています。具体的には、最初に読み込んだディレクトリにはディレクトリ1つ、ファイル3つの全部で4つデータが入っているのですが、その1つのディレクトリには14個のファイルが入っています。それで、14個の配列を作成し、リストに表示させることはできているのですが、タッチしても思い通りの動きがなく…といった感じです。リストの更新を試みているのですが、どのようにすればよいでしょうか。
y_waiwai

2021/07/07 03:14

そのリストのナカミをみて、それが正しい内容なのか、違っているなら、どの段階でどう間違ったのか、をさぐっていくことです。 それを、デバッグする、といいます
guest

0

自己解決

hoshi-takanoriさんの提示案が私の問題の解決に最も近かったため参考にさせていただき、無事解決することができました。
filesをフィールドにし、 if (files[position].isDirectoryの部分で新しく配列を作っていたのを、filesをnewする形にすることでもともとの配列を更新するように解決しました。また、for文で回していた部分も修正しました。配列を更新せず、新しく配列を作ってしまったことで、最初に作った配列と参照を混同していたことが問題でした。回答を寄せていただいた方々、ありがとうございました。

投稿2021/07/07 18:52

Cider_docx

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

エラーメッセージぐらい読みましょう。
(今回は『例外』ですが)

java.lang.ArrayIndexOutOfBoundsException: length=4; index=5 [訳] ArrayIndexOutOfBoundsException (配列でアクセス可能範囲**以外**にアクセスしているときに投げられる例外) が投げられています。 配列のサイズは4ですが、なぜか5番目にアクセスしています。 at com.example.mp3player_process.MainActivity$1.onItemClick(MainActivity.java:65) [訳] 場所はMainActivity.javaの65行目である、com.example.mp3player_process.MainActivity$1.onItemClick内です。

メッセージを読むと、『範囲外系の例外』が投げられています。
(本来はこんな呼び方しないだろうけど)

例えば要素数が10の配列は
0〜9番目しかアクセスできません。
なのに、arr[20] とかみたいなアクセス可能な範囲を超えた部分とかにアクセスしているとか。

で、スタックトレースを読むと、
MainActivity.javaの65行目の
なんちゃらonItemClickメソッドから飛んできているようです。

スタックトレースは見ていると、
後ろから読んでいくスタイルのようです。
(メッセージが英語の場合。まあ英語がそうだからだろうけど)

まずは怪しいと思われるメソッドの中の処理を追ってみてください。

コードを読むコツは『一行レベルで、何をしているのかを考えながら読む』です。

例えば『コメントにする』とか。

まずはそこからやってみてください。


[追記1]

えーっと、MainActivity.javaの65行目は何になっていますか?

私の環境(packageの前に改行が複数あるのにそれを削除したコードになっているとかの可能性も考えて)
では、

Java

1String song = (String) listView.getItemAtPosition(position);

ですね。

では、listView とはなんでしょうか。

android.view.View.(中略).ListViewですよね。

getItemAtPositionメソッドはこのListViewのメソッドですね。(厳密には親であるAdapterViewのメンバですが)

では、このメンバは何をするためのものでしょうか。
そう、『ListViewのposition番目にあるデータを取得する』ですね。

では、positionとは何でしょうか。
int positionですね。

つまり、『ListViewのposition番目にあるデータを取得する』ですね。

よーく考えてみてください。

もしListViewが持つデータが8個しかないのに、「10番目のデータをくれ」としたらどうでしょうか?
無理ですね。

だって、8個しかないんですよ?
それをあたかも11個以上あるような無茶ぶりです。

なので、「いや、そんなに無いから……」と突っ込まれますよね。

こういう場合はデバッグ(debug)をしましょう。

プロでもデバッグぐらいはします

たとえば、デバッガなり、いわゆるprintfデバッグ(JavaだとSystem.out.printメソッド等に相当)なりでデバッグします。

実際にデバッグとして、System.out.printlnメソッド等で
「positionの値」と「ListViewが持つデータの個数」をそれぞれ出力してみてください。

そうすると、

"position = 5, ListViewのデータの個数 = 5" とかみたいな感じのメッセージになるはずです。
(もちろん、出力する文字列データやその書式によって変わるけど)

配列やリスト( LinkedListとか )のようなデータ列は、
「0番目」から「(n-1)番目」までしかアクセスできません。

つまり、アクセスできるのは0番目から「要素数の -1 した分」だけです。

要素数10 なら 0番目から (10 - 1 = 9) で 9番目までしかアクセスできません。

それなのに、arr[10] とかをするとどうなるでしょうか。

「えーっと……そんなに無いんだけど……?」と言われますよね?

10階建てのビルなのに11階(ただし屋上ではない)に行こうとするようなものです。

できませんね。

それが原因。

原因が分かれば対処も簡単。

「要素数を超えなければいい」という考えになりませんか?

後は仕様とかそういうので変わります。

投稿2021/07/06 23:23

編集2021/07/07 06:06
BeatStar

総合スコア4962

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Cider_docx

2021/07/07 02:57

回答ありがとうございます。エラーメッセージはすでに読んでいて、作った配列に対して領域を超えた参照をすることで生じるエラーだということはわかっているのですが、それの具体的な解決方法がわからないです。 ディレクトリを選択したとき、ディレクトリの中身を読み込んで、それをリストで表示させたいのですが、ディレクトリを選択したときに、その中身がもともとの配列より大きいときはどうすればよいのでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問