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

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

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

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

Null

Nullとは、プログラミング言語やデータベースにおけるデータ表現の一種です。コンテキストによって"空"もしくは"長さ0の文字列"、”未知・不明”を意味します。

Android

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

Android Studio

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

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

解決済

1回答

3193閲覧

フラグメントのonViewCreatedメソッドでfindViewByIdがnullになる。

timobol

総合スコア13

XML

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

Null

Nullとは、プログラミング言語やデータベースにおけるデータ表現の一種です。コンテキストによって"空"もしくは"長さ0の文字列"、”未知・不明”を意味します。

Android

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

Android Studio

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

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2021/10/05 23:20

編集2021/10/06 08:50

前提・実現したいこと

お世話になっております。
Android初学者で書籍を使用して勉強している者です。
現在Kotlinでフラグメントについて学習しており、画面をタップした際の動きとして2種類の動きを実装しています。
スマホサイズでは第2のアクティビティが起動し、タブレットサイズではフラグメントが追加される動きになります。

ですが書籍の情報が少し古く、書籍のフラグメントのソースコードで使用しているonActivityメソッドが、Fragmentライブラリのバージョン1.3.0以降になった際に非推奨になっているようです。

そのため色々検索していたところ、現在はonViewCreatedメソッドを使うことが原則推奨されているようで、その中に書籍のonActivityメソッドと同じ処理を記述したのですが、デバッグしてみたところタブレットサイズの際にactivity?.findViewById<View>(R.id.menuThanksFrame)の処理で変数menuThanksFrameがnullになってしまいタブレットサイズだと認識されない状態です。

あまり知識が足りていなく、どのように解決して良いかわからないです。
是非お力をお借りしたく今回質問させていただきます。
よろしくお願いいたします。

該当のソースコード1

MenuListFragment.kt

Kotlin

1package com.websarva.wings.android.fragmentsample 2 3import android.content.Intent 4import android.os.Bundle 5import androidx.fragment.app.Fragment 6import android.view.LayoutInflater 7import android.view.View 8import android.view.ViewGroup 9import android.widget.AdapterView 10import android.widget.ListView 11import android.widget.SimpleAdapter 12 13class MenuListFragment : Fragment() { 14 // 大画面かどうかの判定フラグ。 15 private var _isLayoutXLarge = true 16 17 // onActivityCreatedメソッドはver1.3以降非推奨になった。 18 // 以下、書籍ではonActivityCreatedメソッドを使用する。 19 override fun onViewCreated(view: View,savedInstanceState: Bundle?) { 20 // 親クラスのメソッド呼び出し。 21 super.onViewCreated(view,savedInstanceState) 22 // 自分が所属するアクティビティからmenuThanksFrameを取得。 23 // ここの処理でnullになる。 24 val menuThanksFrame = activity?.findViewById<View>(R.id.menuThanksFrame) 25 // menuThanksFrameがnull,つまり存在しないなら・・・。 26 if (menuThanksFrame == null) { 27 // 画面判定フラグを通常画面とする。 28 _isLayoutXLarge = false 29 } 30 } 31 32 33 override fun onCreateView( 34 inflater: LayoutInflater, container: ViewGroup?, 35 savedInstanceState: Bundle? 36 ): View? { 37 // フラグメントで表示する画面をXMLファイルからインフレートする。 38 val view = inflater.inflate(R.layout.fragment_menu_list, container, false) 39 // 画面部品ListViewを取得。 40 val lvMenu = view.findViewById<ListView>(R.id.lvMenu) 41 42 // SimpleAdapterで使用するMutableListオブジェクトを用意。 43 val menuList: MutableList<MutableMap<String, String>> = mutableListOf() 44 45 // 「から揚げ定食」のデータを格納するMapオブジェクトの用意とmenuListへのデータ登録。 46 var menu = mutableMapOf("name" to "から揚げ定食", "price" to "800円") 47 menuList.add(menu) 48 // 「ハンバーグ定食」のデータを格納するMapオブジェクトの用意とmenuListへのデータ登録。 49 menu = mutableMapOf("name" to "ハンバーグ定食", "price" to "850円") 50 menuList.add(menu) 51 // 以下データ登録の繰り返しのため省略。 52 53 // SimpleAdapter第4引数from用のデータの用意。 54 val from = arrayOf("name", "price") 55 // SimpleAdapter第5引数to用のデータの用意。 56 val to = intArrayOf(android.R.id.text1, android.R.id.text2) 57 // SimpleAdapterを生成。 58 val adapter = SimpleAdapter(activity, menuList, 59 android.R.layout.simple_list_item_2, from, to) 60 // アダプタの登録。 61 lvMenu.adapter = adapter 62 63 // リスナの登録。 64 lvMenu.onItemClickListener = ListItemClickListener() 65 66 // インフレートされた画面を戻り値として返す。 67 return view 68 } 69 70 private inner class ListItemClickListener : AdapterView.OnItemClickListener { 71 override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) { 72 // タップされた行のデータを取得。SimpleAdapterでは1行分のデータはMutableMap型! 73 val item = parent.getItemAtPosition(position) as MutableMap<String, String> 74 // 定食名と金額を取得。 75 val menuName = item["name"] 76 val menuPrice = item["price"] 77 78 // 引継ぎデータをまとめて格納できるBundleオブジェクトを生成。 79 val bundle = Bundle() 80 // Bundleオブジェクトに引継ぎデータを格納。 81 bundle.putString("menuName", menuName) 82 bundle.putString("menuPrice", menuPrice) 83 84 // 大画面の場合。 85 if (_isLayoutXLarge) { 86 // フラグメントトランザクションの開始。 87 // 以下のfragmentManagerは非推奨になった。 88 // val transaction = fragmentManager?.beginTransaction() 89 // parentFragmentManagerを使うことが推奨になった。 90 // parentFragmentManagerはnullチェックがある為。 91 val transaction = parentFragmentManager?.beginTransaction() 92 // 注文完了フラグメントを生成。 93 val menuThanksFragment = MenuThanksFragment() 94 // 引継ぎデータを注文完了フラグメントに格納。 95 menuThanksFragment.arguments = bundle 96 // 生成した注文完了フラグメントをmenuThanksFrameレイアウト部品に追加(置き換え)。 97 transaction?.replace(R.id.menuThanksFrame, menuThanksFragment) 98 // フラグメントトランザクションのコミット。 99 transaction?.commit() 100 } 101 // 通常画面の場合。 102 else { 103 // インテントオブジェクトを生成。 104 // activityは現在所属するアクティビティを示す(今回はMainActivity)。 105 val intent2MenuThanks = Intent(activity, MenuThanksActivity::class.java) 106 // 第2画面に送るデータを格納。 107 intent2MenuThanks.putExtras(bundle) 108 // 第2画面の起動。 109 startActivity(intent2MenuThanks) 110 } 111 } 112 } 113}

該当のソースコード2

activity_main.xml(xlarge)

xml

1<?xml version="1.0" encoding="utf-8"?> 2<LinearLayout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 android:baselineAligned="false" 7 android:orientation="horizontal"> 8 9 <fragment 10 android:id="@+id/fragmentMenuList" 11 android:name="com.websarva.wings.android.fragmentsample.MenuListFragment" 12 android:layout_width="0dp" 13 android:layout_height="match_parent" 14 android:layout_weight="0.4"/> 15 16 <FrameLayout 17 android:id="@+id/menuThanksFrame" 18 android:layout_width="0dp" 19 android:layout_height="match_parent" 20 android:layout_marginRight="10dp" 21 android:layout_marginLeft="50dp" 22 android:layout_weight="0.6" 23 android:background="?android:attr/detailsElementBackground" /> 24</LinearLayout>

試したこと

検索して以下のサイトを見つけたので、onActivityメソッドではなく、onViewCreatedメソッドで実装しました。
https://minpro.net/onactivitycreated-deprecated

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

Fragmentライブラリのバージョンは1.3.6で使用しています。

(追記)スマートフォンサイズのレイアウトファイルは以下の通りになります。
activity_main.xml

xml

1<?xml version="1.0" encoding="utf-8"?> 2<FrameLayout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent"> 6 7 <fragment 8 android:id="@+id/fragmentMenuList" 9 android:name="com.websarva.wings.android.fragmentsample.MenuListFragment" 10 android:layout_width="match_parent" 11 android:layout_height="match_parent"/> 12</FrameLayout>

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

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

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

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

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

jimbe

2021/10/06 06:03

どこで「タブレットサイズだと認識」しているのでしょうか。
timobol

2021/10/06 06:14

質問ありがとうございます。 _isLayoutXLargeという変数がtrueの場合、タブレットサイズであるという認識です。
jimbe

2021/10/06 07:00

> _isLayoutXLargeという変数がtrueの場合 それは MenuListFragment 内でのお話ですね。 通常(?)、画面の大きさに合わせて画面構造を変える場合、予めリソースに各大きさ(や向き)に合わせたレイアウトを作成しておくと、OS が自動でレイアウトを選択してくれます。 ですので、もし「スマホサイズ」のレイアウトには R.id.menuThanksFrame が無く、「タブレットサイズ」のレイアウトには R.id.menuThanksFrame が有るというのであれば、タブレットで実行しているのに R.id.menuThanksFrame が無い=そのタブレットのサイズに合うレイアウトを OS が見つけられず、デフォルトとして「スマホサイズ」のレイアウトが使用されている・・・と見ることが出来ます。 どのような環境で実行されての結果か分かりませんが、その環境に合うタブレットサイズのレイアウトは定義されているのでしょうか。
timobol

2021/10/06 07:33 編集

今回該当のソースコード2に記載されているXMLがactivity_main.xml(xlarge)となっており、タブレットサイズ用のレイアウトになっております。 スマホサイズ用には別途activity_main.xmlのレイアウトファイルがあり、その中ではmenuThanksFrameの項目はありません。
timobol

2021/10/06 07:23

補足情報の欄にスマホサイズのレイアウトファイルactivity_main.xmlを追記いたしました。
timobol

2021/10/06 07:34 編集

実行については、タブレットはPixel Cのエミュレータを起動させて動作確認しております。 スマホはPixel 4で実行しております。
guest

回答1

0

ベストアンサー

再現しました。

結論から言いますと、レイアウトにフラグメントを直接書いた場合、フラグメントの onViewCreated の実行される段階では、まだアクティビティにレイアウトが全ては設定されていません。

ですので、レイアウトにフラグメントを直接書くのではなくホルダだけとし、アクティビティの onCreate で FragmentManager を利用してホルダにフラグメントを展開しますと、onViewCreated でアクティビティの他の View を獲得できます。

ここからは私の考えですが、折角フラグメントを利用するのですから、スマホサイズ時も別アクティビティに遷移するのではなくフラグメントの切り替えで対応し、かつ、フラグメントから他の View に直接アクセスするのではなく、 ViewModel を用いて間接的に処理を依頼・データを取得するほうが、他の View から独立しますのでコード上分かり易くなるかと思います。

投稿2021/10/06 10:28

jimbe

総合スコア13209

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

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

timobol

2021/10/07 04:12

>結論から言いますと、レイアウトにフラグメントを直接書いた場合、フラグメントの onViewCreated の実行される段階では、まだアクティビティにレイアウトが全ては設定されていません。 なるほど。そうなのですね…。 初歩的な質問で申し訳ないのですが、ホルダとはどういうものなのでしょうか? 調べてみたのですがわかなかったです。 MenuListFragment.ktの中でonCreateをoverrideして、FragmentManagerを使うという認識なのですが、合っていますでしょうか?ホルダの展開方法がわからなかったので参考になるものがあるとありがたいです。
jimbe

2021/10/07 04:27

ホルダと言ったのは、ご質問のコードでも使われている「Fragment を置く場所として書いているモノ」のことです。id:menuThanksFrame の役割のことですね。 id:menuThanksFrame に MenuThanksFragment を replace しているのと同じように、 今はスマホ/タブレットとも直接(fragment タグの) MenuListFragment を書いている所を例えば FrameLayout タグの id:menuListFrame とし、onCreate で MenuListFragment を replace する形とすれば、ご質問の状態にはならないと思います。
jimbe
timobol

2021/10/07 05:51

少し内容が理解できました。 アクティビティのonCreateを以下のようにしたところ、変数menuThanksFrameがnullにならず想定していた動きになりました! MainActivity.kt ``` package com.websarva.wings.android.fragmentsample import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.fragment.app.FragmentManager class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) if (savedInstanceState == null) { val fragmentManager = supportFragmentManager val transaction = fragmentManager.beginTransaction() transaction?.replace(R.id.fragmentMenuList,MenuListFragment()) transaction?.commit() } } } ``` (最初MenuListFragmentクラスのonCreateメソッドをオーバーライドするのだと勘違いしていました。申し訳ありません。) タブレット時にフラグメントを使った処理に現在はなっていますが、jimbeさんのおっしゃる通りにスマホ時もフラグメントでの処理するように統一した方がいいと思いました。 まだ書籍で学習中の身なので、ひと段落したら色々改良してみたいと思います! 私のような初心者に様々なアドバイスをしていただきありがとうございました。 今後ともよろしくお願いいたします。 今回jimbeさんの回答をベストアンサーにさせていただきます!
timobol

2021/10/07 05:55

jimbeさんのコードも後で見てみて参考にしてみたいと思います。 まだViewModelの概念も理解できていないので、これからも勉強を続けていきたいと思います。 何から何までありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問