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

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

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

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

Android

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

Q&A

解決済

1回答

1215閲覧

Activity→Fragment間の移動でIllegalStateExceptionエラー (Android, Java)

Yakusugi

総合スコア123

Java

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

Android

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

0グッド

0クリップ

投稿2022/11/18 01:28

編集2022/12/07 05:04

JavaでAndroidの家計簿アプリを開発しています。

今回やりたいことは、
ActivityのListViewで選択したアイテムをタップした際に当該アイテムのデータを引数として渡し、
遷移先のFragment画面へ移動した際に、上記データをEditTextへ反映し、update, deleteを行う仕様にしたいです。

以前、別画面で画面遷移を実装した際は、Fragment→Fragment間の移動(それぞれ乗っかっているActivityが違った為)でnewInstanceを使うことで実装が出来ました。

SearchFragment.java

searchListView.setOnItemClickListener((adapterView, view1, position, id) -> { BudgetTrackerSpending spending = searchedSpendingList.get(position); MainActivity mainActivity = ((MainActivity)getActivity()); if(mainActivity != null) { Fragment fragment = AddSpendingFragment.newInstance(spending); mainActivity.getSupportFragmentManager() .beginTransaction() .replace(R.id.main_container, fragment) .addToBackStack(null) .commit(); } });

但し、今回はActivity→Fragment間の移動になり、
下記の様に実装した所、エラーが発生してしまいました。

SpendingTrackerActivity.java

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { BudgetTrackerSpending spending = budgetSpendingListItems.get(position); FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); Fragment fragment = AddSpendingFragment.newInstance(spending); fragmentTransaction.replace(R.id.main_container, fragment).commit(); } });

https://github.com/yakusugi/OfflineBudgetTrackerAppProject/blob/master/app/src/main/java/com/myproject/offlinebudgettrackerappproject/AddSpendingFragment.java

追記 11/30/2022

修正依頼のご指摘の中で、
Fragmentに入れ替える必要があるとの事でしたので、
下記2行に入れ替えてみたのですが、
IllegalArgumentExceptionが表示され、
エラー発生個所の表示がコンソール上にされなかったため、
原因の特定に苦労しております。

Fragment fragment = AddSpendingFragment.newInstance(spending);
fragmentTransaction.replace(R.id.main_container, fragment).commit();

追記 12/01/2022

今回の大まかな流れは下記となります。

SpendingTrackerActivity.java(LiveData/購入履歴閲覧画面)

ListView内のアイテムをクリック

AddSpendingFragment.javaへ移動(ここで、データ編集または削除を実施)

編集/削除後にSpendingTrackerActivity.javaに戻る。

AddSpendingFragment.javaはフラグメント画面となり、AddBudgetTracker.java(Activity/コンテナ)上で運用しております。

流れとしましては、AddBudgetTracker.java上で上記AddSpendingFragment.javaを含めて下記3つのFragmentを運用しています。

1:AddSpendingFragment.java - 購入履歴入力画面
2:AddIncomeFragment.java - 収入履歴入力画面
3:AddBankFragment.java - 銀行残高入力画面

その為、SpendingTrackerActivity.javaのListView内のアイテムをクリックした段階で、
AddBudgetTracker.javaコンテナの中からAddSpendingFragment.javaに移動する形にしたいです。

追記 12/01/2022 2回目

今回のご指摘の中で、アクティビティ1が不要になることについてご説明頂きましてありがとうございました。
アクティビティ1(下記SpendingTrackerActivity.java/Expenses画面)につきましては、独立したアクティビティとして運用しておりました。
下記画面青枠内のAddBudgetTracker.java(データ追加/編集/削除コンテナ)上では、
今回データ編集用の画面として使うAddSpendingFragment.javaを運用しており、
AddBudgetTracker.javaはデータ追加用の画面をまとめたコンテナとなりますので、
SpendingTrackerActivityを当該コンテナ上でフラグメントとして運用するのが現実的に難しかと思っております。

追記 12/07/2022

何度もすみません。
SpendingTrackerActivity.java

AddBudgetTracker

AddSpendingFragment
の流れで、以前頂いたサンプルコードを元に実装を試してみたのですが、
AddSpendingFragmentの部分でNullPointerExceptionが発生してしまいました。

SpendingTrackerActivityのlistViewをクリック→AddBudgetTrackerを呼び出し listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { Intent intent = new Intent(SpendingTrackerActivity.this, AddBudgetTracker.class); intent.putExtra(AddBudgetTracker.EXTRA_DATA, (BudgetTrackerSpending)listView.getItemAtPosition(position)); startActivity(intent); }

AddBudgetTracker.javaからAddSpendingFragmentへreplace FragmentManager fm = getSupportFragmentManager(); fm.setFragmentResultListener(REQUEST_EDIT, this, (requestKey, result) -> { finish(); }); if(savedInstanceState == null) { BudgetTrackerSpending budgetTrackerSpending = (BudgetTrackerSpending)getIntent().getSerializableExtra(EXTRA_DATA); fm.beginTransaction().replace(R.id.activity_add_container, AddSpendingFragment.newInstance(REQUEST_EDIT, budgetTrackerSpending)).commit(); }

public static AddSpendingFragment newInstance(String requestKey, BudgetTrackerSpending spending) { AddSpendingFragment fragment = new AddSpendingFragment(); Bundle args = new Bundle(); args.putString(ARG_REQUESTKEY, requestKey); args.putSerializable(ARG_DATA, spending); fragment.setArguments(args); return fragment; } <省略> public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_add_spending, container, false); <省略> String requestKey = getArguments().getString(ARG_REQUESTKEY); ←ここでNullpointerエラー発生 <省略> }

エラー内容

FATAL EXCEPTION: main Process: com.myproject.offlinebudgettrackerappproject, PID: 22194 java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference at com.myproject.offlinebudgettrackerappproject.AddSpendingFragment.onCreateView(AddSpendingFragment.java:129)

下記、GitHub上のそれぞれのページになります。

SpendingTrackerActivity.java
https://github.com/yakusugi/OfflineBudgetTrackerAppProject/blob/master/app/src/main/java/com/myproject/offlinebudgettrackerappproject/SpendingTrackerActivity.java

AddBudgetTracker.java
https://github.com/yakusugi/OfflineBudgetTrackerAppProject/blob/master/app/src/main/java/com/myproject/offlinebudgettrackerappproject/AddBudgetTracker.java

AddSpendingFragment.java
https://github.com/yakusugi/OfflineBudgetTrackerAppProject/blob/master/app/src/main/java/com/myproject/offlinebudgettrackerappproject/AddSpendingFragment.java

全体
https://github.com/yakusugi/OfflineBudgetTrackerAppProject/tree/master

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

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

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

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

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

hoshi-takanori

2022/11/18 05:07

Activity を自分で new してはいけません。というか、すでに存在してますよね?
jimbe

2022/11/18 11:54 編集

> 以前、別画面で画面遷移を実装した際は、Fragment→Fragment間の移動(それぞれ乗っかっているActivityが違った為)でnewInstanceを使うことで実装が出来ました。 この辺りから勘違いがあると思います。 SearchFragment.java として提示されているコードは、別のアクティビティのフラグメントにどうこうしているのではなく、 同じアクティビティ上でフラグメントを入れ替えているだけです。 newInstance メソッドは(フラグメント特有のパラメータ保存ロジックを隠すための)フラグメント生成の為の簡易メソッドで、画面遷移とは関係ありません。 あるアクティビティから別のアクティビティを直接操作することは出来ませんし、フラグメントを使ってればアクティビティを分ける必要は(特別の理由が無ければ)ないはずで、ここでも同じように必要なフラグメントに入れ替える構造にし、必要なら newInstance メソッドを定義してパラメータで渡すようにすれば良いように思います。
Yakusugi

2022/11/30 01:31

返信が遅れました。 以前のご指摘の中で、 「必要なフラグメントに入れ替える構造にし、必要なら newInstance メソッドを定義してパラメータで渡すようにすれば良いように思います。」 とアドバイスを頂きましたが、 フラグメントに入れ替えると言うのは、replaceを使うと言う認識で正しいでしょうか。 また、実装を更新してみたのですが、 IllegalArgumentExceptionエラーが発生してしまい、 エラー発生個所の行数が表示されない為、エラーの特定に時間がかかっています。 詳細については、更新内容をご確認頂ければと思います。
jimbe

2022/11/30 17:20

すみません、思い違いをしていたかも知れません。 「今回はActivity→Fragment間の移動」というのは、例えばアクティビティの上半分が ListView で下半分がフラグメントコンテナで、上のリストで選択したデータを詳細フラグメントで下に表示ということでしょうか。
Yakusugi

2022/12/01 00:24

ご質問頂きありがとうございます。 今回の大まかな流れは下記となります。 SpendingTrackerActivity.java(LiveData/購入履歴閲覧画面) ↓ ListView内のアイテムをクリック ↓ AddSpendingFragment.javaへ移動(ここで、データ編集または削除を実施) ↓ 編集/削除後にSpendingTrackerActivity.javaに戻る。 AddSpendingFragment.javaはフラグメント画面となり、AddBudgetTracker.java(Activity/コンテナ)上で運用しております。 流れとしましては、AddBudgetTracker.java上で上記AddSpendingFragment.javaを含めて下記3つのFragmentを運用しています。 1:AddSpendingFragment.java - 購入履歴入力画面 2:AddIncomeFragment.java - 収入履歴入力画面 3:AddBankFragment.java - 銀行残高入力画面 その為、SpendingTrackerActivity.javaのListView内のアイテムをクリックした段階で、 AddBudgetTracker.javaコンテナの中からAddSpendingFragment.javaに移動する形にしたいです。 同文を本文の方にも記載いたしました。
jimbe

2022/12/01 05:12 編集

更新ありがとうございます。 アクティビティ1の ListView を選択したら、アクティビティ2に遷移してその上に詳細フラグメントを表示して選択したデータを表示する・・・ですね。 やはり勘違いしてました。失礼しました。 アクティビティが分かれているなら、必要なパラメータを設定してアクティビティの遷移をし、遷移先のアクティビティでパラメータから自身の表示するフラグメントを決定・設定するしかないでしょう。 遷移元から遷移先のアクティビティを直接操作することは出来ません。 github のソースを元に回答の方も修正しようと思いますが、回答自体よりも、そもそもなぜアクティビティを分けているのでしょうか。 まだ github の詳細を見ていないのですが、フラグメントの上にさらにフラグメントを載せることが可能です。 つまり、 SpendingTrackerActivity や AddBudgetTracker 自体もフラグメント化して、 アプリ全体の土台となるアクティビティを新たに作って、フラグメント化したそれらを切り替えることが出来ます。 蛇足ですが、 AddBudgetTracker も AddBudgetTrackerActivity と命名されたほうがよいかと思います^^;
Yakusugi

2022/12/01 06:52

ご返信頂きありがとうございます。 以下インラインにて回答致します。 github のソースを元に回答の方も修正しようと思いますが、回答自体よりも、そもそもなぜアクティビティを分けているのでしょうか。 →色々な検索機能などを試しているうちに、アクティビティや画面が増えてしまいました(;^_^A まだ github の詳細を見ていないのですが、フラグメントの上にさらにフラグメントを載せることが可能です。 つまり、 SpendingTrackerActivity や AddBudgetTracker 自体もフラグメント化して、 アプリ全体の土台となるアクティビティを新たに作って、フラグメント化したそれらを切り替えることが出来ます。 →ご教示頂きありがとうございます。 フラグメントの上にさらにフラグメントを載せることが出来るのは知りませんでした。勉強になります。 蛇足ですが、 AddBudgetTracker も AddBudgetTrackerActivity と命名されたほうがよいかと思います^^; →確かに私も修正しようかと思っていました。
jimbe

2022/12/01 10:17

> 色々な検索機能などを試しているうちに、アクティビティや画面が増えてしまいました(;^_^A 既存コードからサンプルを作れるかと部分々々をダウンロードして修正してみていますが、あちこちで異なる書き方がされていて、散らかっている感じです。 コードは散らかれば散らかる程、さらに散らかります。「これが出来たら整理するかな、いやもちょっとこっちがなんとかなったら…」とかやっていると、やがて怪物になります。 作りたい機能を思いつくと少しでも早くそれを形にしたくなるのは良く分かりますが、コードの見晴らし・風通しが悪くなるとゴミが溜まり易くなりますので、注意したほうが良いです。
Yakusugi

2022/12/01 10:40

いつも本当にありがとうございます。 おっしゃる通り、色々な機能を試しているうちに、見通しが悪くなっていたのは確かですね。 今後、今回の修正がひと段落したら一旦整理していこうと思います。
guest

回答1

0

ベストアンサー

作られているアプリが相当な行数になっている模様なのと過去の質問からの経緯等で状況が分かり難いので、とりあえずアクティビティ上で リストフラグメントと詳細フラグメントで行き来するようなサンプルを作りましたが、ココに乗りきらないので GitHub です。
https://github.com/Jimbe-github/teratail.q_9hx1zcp8jip3fo
(ViewModel は使わず ) データはアクティビティが保持して両フラグメントの生成時パラメータと FragmentResult でやりとりしています。

流れとしては次のようになると思います。

処理フロー図
※説明が抜けてました。 Activity2 から Fragment への矢印の受けは「パラメータからデータを取り出して EditView 等に設定する」です。

Github のコードを上図のような感じに修正してみました。
データベースの代わりにローカルファイルで、読み書きに Gson(Json) を使用していますので、 build.gradle(Module) の dependencies 内に implementation 'com.google.code.gson:gson:2.10' を追加しています。
詳細画面では削除と修正しか出来ませんので、削除し尽すと戻せません。その場合はアンインストール→インストールをしてください(@w@

ただ、 Activity1 とそのリストの処理をフラグメントにして Activity2 の上で動く他のフラグメントと同様にして Activity2 に載せてしまえば、 Activity1 は不要になり以前と同様にフラグメントの切り替えだけで済むようになると思います。

投稿2022/11/30 07:06

編集2022/12/02 04:19
jimbe

総合スコア12648

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

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

Yakusugi

2022/11/30 08:26

いつも本当にありがとうございます。 ご回答に乗せて頂いたコードを見ながら、実装試してみます。
jimbe

2022/11/30 09:42 編集

過去の質問に何度かコメントや回答等書かせて頂きましたが、どこまで説明頂いたか等大分忘れてしまっており、過去時点に対するものと本件とで異なることを言っているかもしれませんので、ご了承ください。 ( ViewModel から LiveData 経由で search のリストを取ってましたっけ…?)
Yakusugi

2022/12/01 11:15

本当にありがとうございます。 上記で示してい頂いた仕様で実装を進めていこうと思います。 また、本文の方にも記載した内容になるのですが、 今回のご指摘の中で、アクティビティ1が不要になることについてご説明頂きましてありがとうございました。 アクティビティ1(下記SpendingTrackerActivity.java/Expenses画面)につきましては、独立したアクティビティとして運用しておりました。 下記画面青枠内のAddBudgetTracker.java(データ追加/編集/削除コンテナ)上では、 今回データ編集用の画面として使うAddSpendingFragment.javaを運用しており、 AddBudgetTracker.javaはデータ追加用の画面をまとめたコンテナとなりますので、 SpendingTrackerActivityを当該コンテナ上でフラグメントとして運用するのが現実的に難しかと思っております。
jimbe

2022/12/01 12:51

イメージ的にアプリの大きな機能毎にアクティビティにするという考え方は分かりますし、「しなければならない(出来ない)」ことではありませんので。最終的には作者たる Yakusugi さんの意向が一番です。 が、今一度、 Android (=Google?) としては 1 アプリ= 1 アクティビティ的な方向らしぃことや、フラグメントで連携が出来るのにアクティビティを使っている為に本件が発生していること、マルチアクティビティはマルチフラグメントよりはメモリ等の資源を食うだろうこと等、アプリ自体の質・開発の手間としても良いことは無さそうに思いますので、 *私としては* アクティビティを 1 つにすることをお勧めする次第です。 私のイメージとしては、コード全部を見たわけではありませんが、現実的に難しいとは見えていません。
Yakusugi

2022/12/01 13:38

こちら、誠にありがとうございます。 回答用のソースコードまでご用意して頂き、本当にありがとうございます。 また、1アプリ=1アクティビティというのは初めて知りました。 色々勉強になります。 ご回答頂いたソースコードをモデルに実装してみようと思います。 再度、この度はご助力頂き大変ありがとうございました。
Yakusugi

2022/12/02 07:39

上記リンク頂きありがとうございます。 確認させて頂きます。 ご提示頂いたサンプルプロジェクトのSubActivityの23行目なのですが、 こちらのDataとキャストしているほうのDataはどちらをインポートすれば適切でしょうか。 ※私の不手際で、頂いたサンプルコードをzipから回答したのですが、何故かクラスとして読み込まれず。。。 候補となるインポートについては、本文の方に追記しました。 Data data = (Data)getIntent().getSerializableExtra(EXTRA_DATA); 何度も申し訳ございません。
Yakusugi

2022/12/02 10:46

ありがとうございます。 当該クラス確認出来ました。
Yakusugi

2022/12/07 05:07

何度もすみません。 AddSpendingFragmentの129行目でNullPointerExceptionが発生してしまい、 問題解決に時間がかかっています。 もし、お時間があれば確認頂けますと幸いです。 詳細に関しては、本文の方に記載しております。
jimbe

2022/12/07 05:15

github 側が問題の発生しているコードになっていないようですのでこちらで調べることは出来ませんが、 getArgument() が null を返しているということでしたら、 フラグメントを作成する所で AddSpendingFragment.newInstance(~) を使わず直接 new AddSpendingFragment() とやっているのではないでしょうか。
Yakusugi

2022/12/07 05:55

ご返信頂きありがとうございます。 先ほど、プッシュ致しました。 今回の実装では、AddSpendingFragment.newInstanceを使用していおります。
jimbe

2022/12/07 06:22 編集

ありがとうございます。 ぱっと見ですが AddSpendingFragment を生成している所は一箇所では無いですよね。 それと、 AddSpendingFragment に newInstance が増えていますが、そこでは ARG_SPENDING しか設定していませんが、 onCreate では無条件に ARG_REQUEST を パラメータから取り出して使っていますので、 ARG_SPENDING のほうの newInstance で作ったフラグメントは FragmentResult でアクティビティに通知が届きません。(アクティビティのほうが ARG_REQUESTKEY で指定した文字列の FragmentResult を待っているためです。) 元々 ARG_DATA は spending を回答用に簡略化したモノのつもりで書きましたので、パラメータを二つ取る newInstance を利用して頂ければと思います。
jimbe

2022/12/07 06:44 編集

少々厳しいことを書かせて頂きますが、コードは程度の差はあれそれぞれに理由があって書かれています。 newInstance() はフラグメントに最低限必要なパラメータがあるからこそ(パラメータを指定するコンストラクタの代わりとして)作っているものですので、内部では指定されることを前提に書いてあるのを確認もされないようでは、細かい問題の発生がなかなか直らないでしょう。 一部のコードに注力すると全体が見えなくなって、全体の中でのそのコードの意味が捉えにくくなります。それを補う為にまたコードを作るの繰り返しによってでも(質問へのコメントにも書きましたが)すぐにコードが肥大し、さらに分かり難くなっていきます。 最小のコードで最大の結果を得るにはどうするのが良いのか、数行のコードからメソッド・クラス・システム全体の設計まであらゆるスケールでの視点を意識出来ると良いと思います(自戒も含めてです ><)
Yakusugi

2022/12/07 06:54

ありがとうございます! ARG_SPENDINGを設定しているもう一方のnewInstanceをコメントアウトしたところ、 問題無く、Fragmentまでいきつきました。 また、アドバイスも含めて、お言葉ありがとうございます。 今後、頂いたアドバイスも含めて、コードを書く際に設計も意識しながら進めていきたいと思います。 再度、この度はありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問