実現したいこと
いつもお世話になっております。Javaを最近学習し始めAndroidアプリを作成中なのですが、Fragment間での値の受け渡し方法について困っています。
MainActivityに紐づくMainFragmentでページビューによってReceiveFragmentとBlankFragmentがスワイプで表示される仕組みにしており、ReceiveFragmentから遷移したPassFragmentで入力した値をボタンクリックによって保存、ReceiveFragmentへ受け渡したいと思っています。
発生している問題・分からないこと
エラーから、ViewModelがnullとのことでどうしたら値の取得がうまくいくのか悩んでいます。
そもそもViewModelの使い方がまちがっているのでしょうか・・・
お手数ですがどうぞご教授よろしくお願いいたします。
該当のソースコード
Java
1package com.websarva.wings.android.sampleapp; 2 3import android.os.Bundle; 4import androidx.annotation.NonNull; 5import androidx.annotation.Nullable; 6import androidx.fragment.app.Fragment; 7import androidx.fragment.app.FragmentManager; 8import androidx.fragment.app.FragmentTransaction; 9import androidx.lifecycle.ViewModelProvider; 10import android.view.View; 11import android.widget.Button; 12import android.widget.TextView; 13 14 15public class PassFragment extends Fragment { 16 17 //ViewModelProviderでViewModelを取得 18 MainViewModel viewModel = new ViewModelProvider(this).get(MainViewModel.class); 19 20 //予算名取得用 21 private TextView etBudgetNameV; 22 23 public PassFragment() { 24 super(R.layout.fragment_pass); 25 } 26 27 @Override 28 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 29 super.onViewCreated(view, savedInstanceState); 30 31 //予算名受け渡しのためビューをあらかじめ取得 32 etBudgetNameV=view.findViewById(R.id.etBudgetName); 33 34 //保存ボタンにリスナ設定 35 Button btSave=view.findViewById(R.id.btSave); 36 btSave.setOnClickListener(new btSaveClickListener()); 37 } 38 39 40 //保存ボタンのリスナ 41 private class btSaveClickListener implements View.OnClickListener{ 42 @Override 43 public void onClick(View view) { 44 45 //画面遷移時に引き渡すBundleオブジェクトを定義 46 Bundle bundle=new Bundle(); 47 48 //入力ありならviewModelに引き継ぎデータを格納 49 if(etBudgetNameV.getText().toString().length()!=0){ 50 viewModel.budgetName.add(etBudgetNameV.getText().toString()); 51 //フラグメントマネージャーを取得 52 FragmentManager clfManager=getParentFragmentManager(); 53 //フラグメントトランザクションの開始 54 FragmentTransaction clfTransaction=clfManager.beginTransaction(); 55 //フラグメントトランザクションが正しく動作するように設定 56 clfTransaction.setReorderingAllowed(true); 57 //現在の表示内容をバックスタックに追加 58 clfTransaction.addToBackStack("createList"); 59 //リスト作成画面フラグメントをMainFragmentに置き換え 60 clfTransaction.replace(R.id.fragmentMainContainer,MainFragment.class,bundle); 61 //フラグメントトランザクションのコミット 62 clfTransaction.commit(); 63 } 64 } 65 } 66}
Java
1package com.websarva.wings.android.sampleapp; 2 3import android.os.Bundle; 4 5import androidx.annotation.NonNull; 6import androidx.annotation.Nullable; 7import androidx.fragment.app.Fragment; 8import androidx.fragment.app.FragmentManager; 9import androidx.fragment.app.FragmentTransaction; 10import androidx.lifecycle.ViewModelProvider; 11 12import android.view.LayoutInflater; 13import android.view.View; 14import android.view.ViewGroup; 15import android.widget.ArrayAdapter; 16import android.widget.ImageButton; 17import android.widget.ListView; 18import android.widget.SimpleAdapter; 19 20import java.util.ArrayList; 21import java.util.HashMap; 22import java.util.List; 23import java.util.Map; 24 25public class ReceiveFragment extends Fragment { 26 27 private MainViewModel viewModel; 28 29 //予算の入力数 30 private int inputNumber; 31 //予算名リスト 32 private List<Map<String,String>> budgetList; 33 private Map<String,String> budgetMap; 34 35 36 public ReceiveFragment() { 37 super(R.layout.fragment_receive); 38 } 39 40 @Override 41 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 42 super.onViewCreated(view, savedInstanceState); 43 44 //ボタンを取得 45 ImageButton ibAddButton =view.findViewById(R.id.ibAdd); 46 //戻るボタンにリスナを登録 47 ibAddButton.setOnClickListener(new ibAddClickListener()); 48 49 //ListViewオブジェクトを取得 50 ListView lvBudgetV =view.findViewById(R.id.lvBudget); 51 52 53 //受け渡されたデータ取得 54 //ViewModelProviderでViewModelを取得 55 viewModel = new ViewModelProvider(this).get(MainViewModel.class); 56 //予算の入力数を取得 57 inputNumber=viewModel.budgetName.size(); 58 //budgetNameに入力があればデータ取得 59 if(inputNumber != 0){ 60 //ListViewオブジェクトに表示するリストデータ用Listオブジェクトを作成 61 budgetList = new ArrayList<Map<String, String>>(); 62 for(int i=0 ; i<inputNumber ; i++){ 63 //項目データを格納するMapオブジェクトを用意 64 budgetMap= new HashMap<String,String>(); 65 budgetMap.put("budgetName",viewModel.budgetName.get(i)); 66 budgetList.add(budgetMap); 67 } 68 //アダプタオブジェクトを生成 69 ArrayAdapter budgetListAdapter=new ArrayAdapter(requireContext(),android.R.layout.simple_list_item_1,budgetList); 70 //リストビューにアダプタを設定 71 lvBudgetV.setAdapter(budgetListAdapter); 72 } 73 } 74 75 //ボタンをクリックしたときのリスナクラス 76 private class ibAddClickListener implements View.OnClickListener{ 77 @Override 78 public void onClick(View view){ 79 80 //引継ぎデータをまとめて格納できるBundleオブジェクトを作成 81 Bundle bundle=new Bundle(); 82 83 84 //フラグメントマネージャーを取得 85 FragmentManager lfManager=getParentFragmentManager(); 86 //フラグメントトランザクションの開始 87 FragmentTransaction transaction=lfManager.beginTransaction(); 88 //フラグメントトランザクションが正しく動作するように設定 89 transaction.setReorderingAllowed(true); 90 //現在の表示内容をバックスタックに追加 91 transaction.addToBackStack("List"); 92 //ListFragmentをリスト作成画面フラグメントに置き換え 93 transaction.replace(R.id.fragmentMainContainer,PassFragment.class,bundle); 94 //フラグメントトランザクションのコミット 95 transaction.commit(); 96 } 97 } 98}
Java
1package com.websarva.wings.android.sampleapp; 2 3import androidx.lifecycle.ViewModel; 4 5import java.util.List; 6 7public class MainViewModel extends ViewModel { 8 //予算名 9 public List<String> budgetName; 10 11} 12
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
最初はBundleで値を受け渡そうとしたのですが値の受け渡し先(ReceiveFragment)と画面の遷移先(MainFragment)が異なっており方法がわからなかったのと、別のFragmentでも書き換える可能性があり、ライフサイクルの観点でもViewModelを使用するのがよいと考えました。ViewModelを使用し、ネットで検索しながらコードを書いてみたのですが、nullになりうまく取得できませんでした。ViewModelに値が入っているかの確認方法が調べてもわからずこちらに質問させていただきました。
※PassFragmentから取得する値について
質問では簡単のため省略し予算名のみにしてありますが、現在PassFragmentのレイアウトは添付画像のようになっており、最終的には①~⑤の値を受け渡したいと思っております。
①予算名②期間③合計予算④項目(食費、医療費など)⑤項目別予算
④⑤はプラスボタンで追加、ListViewに表示できるようになっており⑤の合計が自動で③に入るようになっています。
補足
AndroidStudio Giraffe
回答1件
あなたの回答
tips
プレビュー