Reputation: 373
MainFragment contains a RecyclerView of paths, when the user selects a path it navigates to CourseFragment which contains a RecyclerView of relevant courses. However, if the user goes back to choose a different path, the same course items are shown every time.
Course Fragment
class CourseFragment : Fragment(),
CourseRecyclerAdapter.CourseItemListener {
private lateinit var viewModel: CourseViewModel
private lateinit var recyclerView: RecyclerView
private lateinit var navController: NavController
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
Log.i(LOG_TAG, "Course Fragment onCreateView(): selectedItem = $globalSelectedPath")
val view = inflater.inflate(R.layout.fragment_course, container, false)
recyclerView = view.findViewById(R.id.courseRecyclerView)
navController = Navigation.findNavController(requireActivity(), R.id.nav_host )
viewModel = ViewModelProvider(requireActivity()).get(CourseViewModel::class.java)
viewModel.courseData.observe(viewLifecycleOwner, Observer {
val adapter =
CourseRecyclerAdapter(
requireContext(),
it,
this
)
recyclerView.adapter = adapter
} )
return view
}
CourseViewModel
class CourseViewModel(app: Application): AndroidViewModel(app) {
private val courseDataRepository = CourseRepository(app)
val courseData = courseDataRepository.courseData
val selectedCourse = MutableLiveData<Course>()
}
Course Repository
class CourseRepository(val app: Application) {
val courseData = MutableLiveData<List<Course>>()
init {
CoroutineScope(Dispatchers.IO).launch {
callWebService()
}
}
@WorkerThread
suspend fun callWebService() {
if (Utility.networkAvailable(app)) {
val retrofit = Retrofit.Builder().baseUrl(WEB_SERVICE_URL).addConverterFactory(MoshiConverterFactory.create()).build()
val service = retrofit.create(CourseService::class.java)
val serviceData = service.getCourseData(globalSelectedPath).body() ?: emptyList()
courseData.postValue(serviceData)
}
else
Toast.makeText(app, Resources.getSystem().getString(R.string.noConnectivity), Toast.LENGTH_LONG).show()
}
}
After logging it shows that CourseRepository is only called once, hence, the callWebService() is only triggered once, and new data is not retrieved.
2020-05-02 12:24:02.520 I/mylog: Course Fragment onCreateView(): selected path = MOB001
2020-05-02 12:24:02.529 I/mylog: Course Repository callWebService(): selected path = MOB001
-------------------------------
2020-05-02 12:24:35.009 I/mylog: Course Fragment onCreateView(): selected path = WEB999
To make sure i made an Okhttp interceptor log of the callWebService() which confirmed that data was only fetched once:
12:24:02.551 D/OkHttp: --> GET https://.../mobile/feed/course_data.php?pathName=MOB001
12:24:02.551 D/OkHttp: --> END GET
12:24:03.007 D/OkHttp: <-- 200 https://.../mobile/feed/course_data.php?pathName=MOB001 (455ms)
12:24:03.007 D/OkHttp: date: Sat, 02 May 2020 09:24:03 GMT
12:24:03.007 D/OkHttp: server: Apache
12:24:03.007 D/OkHttp: x-powered-by: PHP/5.6.40
12:24:03.007 D/OkHttp: vary: Accept-Encoding
12:24:03.007 D/OkHttp: content-type: text/html; charset=UTF-8
12:24:03.009 D/OkHttp: [{"courseName":"Android App Development Essentials","instructor":"John Lennon","courseDescription":"Description ...","courseImage":"android_development_essentials.jpg","instructorImage":"john.jpg"}]
12:24:03.009 D/OkHttp: <-- END HTTP (206-byte body)
Upvotes: 0
Views: 172
Reputation: 373
It turns out that in the following line:
viewModel = ViewModelProvider(requireActivity()).get(CourseViewModel::class.java)
I had used requireActivity()
which will scope my fragment's viewmodel to the activity lifecycle, so the RecyclerView will update correctly when the app (and therefore activity) first starts but does not update again when navigating forth and back between fragments.
So to solve this issue i replaced requireActivity()
with this
which means the viewmodel is scoped to the fragment it is in only and therefore the RecyclerView will update whenever the user enters and re-enters the fragment
viewModel = ViewModelProvider(this).get(CourseViewModel::class.java)
Upvotes: 0
Reputation:
It is most likely that is issue is cause because the observer is not getting updated. You could use Fragment's view lifecycle through getViewLifeCycleOwner() or getViewLifeCycleLiveData() so that LiveData will remove observers every single time the fragment is destroyed.
Upvotes: 1
Reputation: 763
ViewModelProvider(requireActivity()) cause the retrieve the previous view model because the view model store keeps reference to previously created view model then serve it if you want again. You should give the fragment as a view model store owner rather than activity. Additionally I think your repository design is not correct if you don't need same course list in another place, you should call the method with corresponding argument whenever the course list fragment is created so you retrieve the appropriate data from server.
Upvotes: 0