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

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

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

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Java

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

Android

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

ダイアログ

ユーザーにウィンドウやボックス等の形で個別で表示されるフォームであり、ユーザーに判断を促す目的で表示される。ユーザーが見逃す事のないよう、操作中のフォーム上にポップアップして表示される。

Kotlin

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

Q&A

2回答

4376閲覧

RecyclerViewの更新が反映されない(Firebaseから取得したデータリストを並べる)

joseryo

総合スコア0

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Java

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

Android

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

ダイアログ

ユーザーにウィンドウやボックス等の形で個別で表示されるフォームであり、ユーザーに判断を促す目的で表示される。ユーザーが見逃す事のないよう、操作中のフォーム上にポップアップして表示される。

Kotlin

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

0グッド

0クリップ

投稿2020/12/23 13:51

編集2020/12/24 06:25

前提・実現したいこと

チーム管理系のアプリを作成しています。
アプリを起動すると、Firebaseへ自動ログインされ、その後Firebaseから、ユーザー固有のデータ(その人が所属しているチーム一覧データ)を取得し、RecyclerViewに反映させます。

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

起動しても、RecyclerViewが空のままで、反映されません。
しかし、FABをクリックして、ダイアログを表示させ、そこのEditTextをタップして、キーボードが出てくると、後ろのほうでチーム一覧が出現し、その後ダイアログを閉じてもそのまま残っています。(アプリを再起動するとまた最初、空のまま表示される。)

該当のソースコード

TeamActivity

1class TeamActivity : AppCompatActivity() { 2 3 4 override fun onCreate(savedInstanceState: Bundle?) { 5 super.onCreate(savedInstanceState) 6 7 //端末内に保存されているメアドパスデータを取得 8 val data = getSharedPreferences("Data", Context.MODE_PRIVATE) 9 var Emaildata = data.getString("Email", null) 10 var Passdata = data.getString("Passwoed", null) 11 12 if ((Emaildata != null) && (Passdata != null)) { 13 val mAuth = FirebaseAuth.getInstance() 14 mAuth.signInWithEmailAndPassword(Emaildata, Passdata) 15 .addOnCompleteListener { 16 if (it.isSuccessful) { 17 Toast.makeText(applicationContext, "ログインしました", Toast.LENGTH_LONG).show() 18 // 成功処理 19 } else { 20 Toast.makeText( 21 applicationContext, 22 "ログインに失敗しました\n申し訳ありませんがもう一度\nもう一度登録しなおしてください", 23 Toast.LENGTH_LONG 24 ).show() 25 // 失敗処理 26 } 27 } 28 29 // [START check_current_user] 30 } 31 32 33 val user = Firebase.auth.currentUser 34 if (user != null) { 35 // User is signed in 36 } else { 37 // No user is signed in 38 val intent = Intent(applicationContext, LoginActivity::class.java) 39 //第2画面に送るデータを格納。 40 startActivity(intent) 41 } 42 // [END check_current_user] 43 setContentView(R.layout.activity_team) 44 45 val layoutManager = GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false) 46 47 // アダプターとレイアウトマネージャーをセット 48 val TeamRecyclerView = findViewById<RecyclerView>(R.id.TeamRecyclerView) 49 val adapter = CustomAdapter(TeamList()) 50 TeamRecyclerView.layoutManager = layoutManager 51 TeamRecyclerView.setHasFixedSize(true) 52 TeamRecyclerView.adapter = adapter 53 54 val makefab = findViewById<FloatingActionButton>(R.id.sub_btn1) 55 val joinfab = findViewById<FloatingActionButton>(R.id.sub_btn2) 56 makefab.setOnClickListener(MakeFabClickListener()) 57 joinfab.setOnClickListener(JoinFabClickListener()) 58 } 59 60 private inner class MakeFabClickListener : View.OnClickListener { 61 override fun onClick(v: View?) { 62 val dialogFragment = MakeTeamDialogFragment() 63 dialogFragment.show(supportFragmentManager, "MakeTeamDialogFragment") 64 } 65 } 66 67 private inner class JoinFabClickListener : View.OnClickListener { 68 override fun onClick(v: View?) { 69 val dialogFragment = JoinTeamDialogFragment() 70 dialogFragment.show(supportFragmentManager, "JoinTeamDialogFragment") 71 } 72 } 73} 74fun TeamList(): MutableList<MutableMap<String, String>> { 75 val uid = Firebase.auth.currentUser?.uid.toString() 76 val dbc = FirebaseFirestore.getInstance() 77 val teamList: MutableList<MutableMap<String, String>> = mutableListOf() 78 dbc.collection("Users").document(uid).get() 79 .addOnSuccessListener { 80 val dataList = it.data 81 var team = mutableMapOf<String,String>() 82 dataList?.forEach { 83 team = mutableMapOf("team" to it.value.toString()) 84 teamList.add(team) 85 } 86 } 87 return teamList 88} 89// ViewHolderクラスを作成 90class CustomViewHolder(val view: View) : RecyclerView.ViewHolder(view) { 91 val tvTeamname = view.tvteamname 92} 93 94class CustomAdapter(private val customList: MutableList<MutableMap<String,String>>) : RecyclerView.Adapter<CustomViewHolder>() { 95 96 // 上記のViewHolderクラスを使ってViewHolderを作成 97 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder { 98 val Inflater = LayoutInflater.from(parent.context) 99 val item = Inflater.inflate(R.layout.grid_view, parent, false) 100 return CustomViewHolder(item) 101 } 102 103 // ViewHolderに表示するデータを挿入 104 override fun onBindViewHolder(holder: CustomViewHolder, position: Int) { 105 val item = customList[position] 106 val teamname = item["team"] as String 107 holder.view.tvteamname.text = teamname 108 } 109 110 // getItemCount onCreateViewHolder onBindViewHolderを実装 111 // recyclerViewのコンテンツのサイズ 112 override fun getItemCount(): Int { 113 return customList.size 114 } 115}

activity_team.xml
イメージ説明
grid_view.xml
イメージ説明

JoinTeamDialogFragment

1class JoinTeamDialogFragment: DialogFragment() { 2 private val TAG = "JoinFragment" 3 4 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { 5 val activity = requireActivity() 6 val builder = AlertDialog.Builder(activity) 7 val inflater = activity.layoutInflater 8 val teamjoinview = inflater.inflate(R.layout.team_join_dialog,null) 9 10 11 builder.setView(teamjoinview) 12 .setTitle("チームを追加") 13 .setPositiveButton("参加"){dialog,id-> 14 //入力欄の有無を判別する// 15 val teamid =teamjoinview.findViewById<EditText>(R.id.etteamid) 16 val mynamej = teamjoinview.findViewById<EditText>(R.id.etmynamej) 17 val teamidEdi = teamid.text 18 val mynamejEdi = mynamej.text 19 20 //チームに参加(チームにuid追加)して、uidに所属チームを紐づける 21 if(!TextUtils.isEmpty(teamidEdi) && !TextUtils.isEmpty(mynamejEdi)){ 22 val uid = Firebase.auth.currentUser?.uid.toString() 23 val teamidStr = teamidEdi.toString() 24 val mynamejStr = mynamejEdi.toString() 25 val dbc = FirebaseFirestore.getInstance() 26 27 28 dbc.collection("Teams") 29 .document(teamidStr) 30 .collection("members") 31 .document("members") 32 .set(mapOf(uid to mynamejStr), SetOptions.merge()) 33 34 dbc.collection("Teams") 35 .document(teamidStr) 36 .get() 37 .addOnCompleteListener { task -> 38 if (task.isSuccessful) { 39 val document = task.result 40 if (document != null && document.data != null) { 41 val tname = document.data?.get("teamname") 42 dbc.collection("Users") 43 .document(uid) 44 .set(mapOf(teamidStr to tname), SetOptions.merge()) 45 }else { 46 } 47 }else { 48 } 49 } 50 .addOnFailureListener { e -> } 51 52 dbc.collection("Users").document(uid).get() 53 .addOnSuccessListener { 54 val dataList = it.data 55 val teamlist: MutableList<MutableMap<String, String>> = mutableListOf() 56 dataList?.forEach { 57 var team = mutableMapOf("team" to it.value.toString()) 58 teamlist.add(team) 59 } 60 61 val adapter = CustomAdapter(teamlist) 62 adapter.notifyDataSetChanged() 63 } 64 }else{ 65 Toast.makeText(activity,"チームコードとあなたのお名前を\n入力してください。",Toast.LENGTH_LONG).show() 66 } 67 //入力欄有無判別終了 68 } 69 .setNegativeButton("キャンセル"){dialog,id->} 70 return builder.create() 71 } 72 73 74}

画面がこうなります
イメージ説明

イメージ説明

イメージ説明
↓ここでうしろにうっすらとチームのカードが出現している。
イメージ説明

イメージ説明

試したこと

Firebaseからデータを持ってくる前に描画してしまっているのかなとは思いましたが、なんとも原因がわかりません。TeamActivityでadapterを設定した直後にnotifydatasetchangedを呼んでもみましたが、最初に描画はされないままでした。
ちなみにアダプタに渡すリストを固定の用意したリストにしたら、普通に最初から描画されました。ので、firebaseからとってきたデータをリストにして、アダプタに渡すところに問題があるのかなと思いました。

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

ちなみに、もうひとつのエラーとして、ダイアログにチームコードと名前を入力して、参加を押して、Firebaseのユーザーの所属チーム一覧に新しいチームのデータを追加して、notifydatasetchangedでRecyclerViewを更新しても、ダイアログが消えた後、RecyclerViewは更新されてないまま、前のチーム一覧が載っていたので、そちらもわかるかた、解決法ご教授いただきたいです。

何卒、皆様のお力をお貸しくださいmm

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

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

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

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

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

hoshi-takanori

2020/12/24 04:24

teamList の内容が変化した時に、CustomAdapter の notifyDataSetChanged() を呼んで表示を更新する必要がある気がします。
joseryo

2020/12/24 06:28

それは、foreachでaddしていくたびにnotifyをよぶということでしょうか。 試したことに追記しましたが、TeamActivityでアダプタ呼んでセットした後にnotifyしても、変化はありませんでした。
guest

回答2

0

JoinTeamDialogFragment で notifyDataSetChanged 自体は呼んでますが、

JoinTeamDialogFragment

1 val adapter = CustomAdapter(teamlist) 2 adapter.notifyDataSetChanged()

としているので、RecyclerView に設定された adapter ではなく、新しく別の CustomAdapter を作ってそれに対して呼んでいるので、これでは意味がありません。

とりあえず adapter を TeamActivity のプロパティにして、

diff

1 class TeamActivity : AppCompatActivity() { 2 3+ lateinit var adapter: CustomAdapter 4 5 override fun onCreate(savedInstanceState: Bundle?) { 6 super.onCreate(savedInstanceState) 7 8 // 略 9 10 // アダプターとレイアウトマネージャーをセット 11 val TeamRecyclerView = findViewById<RecyclerView>(R.id.TeamRecyclerView) 12- val adapter = CustomAdapter(TeamList()) 13+ adapter = CustomAdapter(TeamList())

CustomAdapter の customList を外から設定できるようにして、

diff

1- class CustomAdapter(private val customList: MutableList<MutableMap<String,String>>) : RecyclerView.Adapter<CustomViewHolder>() 2+ class CustomAdapter(var customList: MutableList<MutableMap<String,String>>) : RecyclerView.Adapter<CustomViewHolder>()

JoinTeamDialogFragment で呼び出し元の Activity を取得して、その adapter に対して操作を行うようにすればいいと思います。

diff

1- val adapter = CustomAdapter(teamlist) 2- adapter.notifyDataSetChanged() 3+ val adapter = (activity as TeamActivity).adapter 4+ adapter.customList = teamlist 5+ adapter.notifyDataSetChanged()

参考: Android - DialogFragmentでどのボタンがクリックされたか、呼び出し元のActivityに知らせたい。|teratail

投稿2020/12/24 07:58

hoshi-takanori

総合スコア7901

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

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

joseryo

2020/12/25 11:43

hoshi様、補足の方のエラーの解決策ということで、ご回答ありがとうございます。 早速ご教授いただいた、コードを試してみましたが、ダイアログに入力し参加を押し、ダイアログが閉じたあと、以前と同様にRecyClerViewが変化することはありませんでした。 やはり、今回の質問のメインエラーである、アプリ立ち上げ時にリストが反映されない(EditTextwをいじると出現するという変なタイミングで反映される)の方に根本的な問題があるように思えます。 そちらの方でなにか心当たりのあることありましたら、ご教授お願いしたく存じますm(_ _)m
guest

0

TeamRecyclerView.layoutManager = layoutManager
TeamRecyclerView.setHasFixedSize(true)
adapter = CustomAdapter(TeamList())
Handler().postDelayed(Runnable {
adapter.notifyDataSetChanged()
TeamRecyclerView.adapter = adapter
}, 3000)

このように、一部を3秒の遅延処理にすることで、更新されました。
補足での、ダイアログフラグメントからのアダプタ呼び出しについても、hoshi様のご回答により解決できましたが、

遅延処理はその場しのぎの解決方法なので、どなたか、読み込み次第更新されるような解決策がわかるかた、ご教授お願いいたします。

投稿2020/12/25 13:32

編集2020/12/26 01:57
joseryo

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問