NavArgs not returning a value, I just get this when I try to update through the setOnClickListener in update fragment:
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
Caused by: java.lang.IllegalArgumentException: Required argument "currentAlarm" is missing and does not have an android:defaultValue
I need to return the ID from the alarm selected in the RecyclerView, so a default value wouldn't make sense here.
The NavArgs are set in the nav-view correctly, with no default. Could the model and ID be set up wrong with autoGenerate? or is going via the adapter the problem here?
update fragment:
class UpdateFragment : Fragment() {
private val timePickerUtil = TimePickerUtil()
lateinit var binding: FragmentUpdateBinding
private lateinit var alarmViewModel: AlarmViewModel
private val args by navArgs<UpdateFragmentArgs>()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentUpdateBinding.inflate(inflater, container, false)
alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java]
binding.fragmentBtnUpdateAlarm.setOnClickListener {
updateAlarm()
Navigation.findNavController(requireView())
.navigate(R.id.action_updateFragment_to_homeFragment)
}
return binding.root
}
private fun updateDatabase(id: Int, hour: Int, minute: Int, repeat: Boolean) {
val alarm = Alarm(id, hour, minute, repeat)
alarmViewModel.update(alarm)
}
private fun updateAlarm() {
val timePicker = binding.fragmentUpdateAlarmTimePicker
val id = args.currentAlarm.id
val hour = timePickerUtil.getTimePickerHour(timePicker)
val minute = timePickerUtil.getTimePickerMinute(timePicker)
val repeat = binding.fragmentUpdateAlarmRecurring.isChecked
val alarmManager = AlarmManager(
id,
hour,
minute,
true,
binding.fragmentUpdateAlarmRecurring.isChecked
)
updateDatabase(id, hour, minute, repeat)
alarmManager.cancel(requireContext())
alarmManager.schedule(requireContext())
}
}
adapter:
class AlarmListAdapter() :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
class MyViewHolder(binding: LayoutAlarmBinding) : RecyclerView.ViewHolder(binding.root)
private var alarmList = ArrayList<Alarm>()
private var onItemClickListener: OnItemClickListener? = null
interface OnItemClickListener{
fun onClick(alarm: Alarm)
fun onLongClick(alarm: Alarm)
}
fun setOnItemClickListener(listener: OnItemClickListener){
onItemClickListener = listener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val binding = LayoutAlarmBinding.inflate(LayoutInflater.from(parent.context))
return MyViewHolder(binding)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val currentItem = alarmList[position]
val minute = currentItem.minute
holder.itemView.findViewById<TextView>(R.id.tv_alarm_time).text =
if (minute >= 10) {
"${currentItem.hour}:${currentItem.minute}"
} else {
"${currentItem.hour}:0${currentItem.minute}"
}
holder.itemView.setOnClickListener{
if(onItemClickListener != null){
onItemClickListener?.onClick(currentItem)
}
}
holder.itemView.setOnLongClickListener {
if(onItemClickListener != null){
onItemClickListener?.onLongClick(currentItem)
}
true
}
}
override fun getItemCount(): Int {
return alarmList.size
}
fun setData(alarm: List<Alarm>) {
alarmList.clear()
alarmList.addAll(alarm)
notifyDataSetChanged()
}
}
HomeFragment:
class HomeFragment : Fragment() {
lateinit var binding: FragmentHomeBinding
private lateinit var alarmViewModel: AlarmViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentHomeBinding.inflate(inflater, container, false)
// RecyclerView
val adapter = AlarmListAdapter()
val recyclerView = binding.recyclerView
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(requireContext())
//ViewModel
alarmViewModel = ViewModelProvider(this).get(AlarmViewModel::class.java)
alarmViewModel.readAlarmData.observe(viewLifecycleOwner, Observer { alarm ->
adapter.setData(alarm)
})
binding.btnAddAlarm.setOnClickListener {
Navigation.findNavController(requireView())
.navigate(R.id.action_homeFragment_to_newAlarmFragment)
}
adapter.setOnItemClickListener(object : AlarmListAdapter.OnItemClickListener {
override fun onClick(alarm: Alarm) {
Navigation.findNavController(requireView())
.navigate(R.id.action_homeFragment_to_updateFragment)
}
override fun onLongClick(alarm: Alarm) {
val deleteBuilder = AlertDialog.Builder(requireContext())
deleteBuilder.setPositiveButton("Delete") { _, _ ->
alarmViewModel.delete(alarm)
Toast.makeText(context, "Alarm Deleted", Toast.LENGTH_SHORT)
.show()
}
deleteBuilder.setNegativeButton("Cancel") { _, _ ->
}
deleteBuilder.setTitle("Delete Alarm?")
deleteBuilder.create().show()
}
})
return binding.root
}
}
and my alarm model:
#Parcelize
#Entity(tableName = "alarm_table")
data class Alarm(
#PrimaryKey(autoGenerate = true)
val id: Int,
val hour: Int,
val minute: Int,
val repeat: Boolean
): Parcelable
Safe args creates its own classes (like here HomeFragmentDirections). So in homeFragment, where you are setting up onclick listeners for the adapter, you should use->
adapter.setOnItemClickListener(object : AlarmListAdapter.OnItemClickListener {
override fun onClick(alarm: Alarm) {
Navigation.findNavController(requireView())
.navigate(HomeFragmentDirections.actionHomeFragmentToUpdateFragment(params))
}
override fun onLongClick(alarm: Alarm) {
// preform longclick action here
}
})
And add a param (in your case, id may be of type int or String) of the required type in UpdateFragment in the corresponding navgraph.
I hope you got my point and if not don't hesitate to comment.
You can read about this on the android developer website here.
Related
Fragment1 exists in MainActivity and Fragment2 exists in Fragment1.
Fragment2 contains a recycler view, and inside the recycler view there are items with a move button. When I click the go button, I want to switch to a screen other than the RcyclerView with the items currently displayed in Fragment2.
adpater
class Quality_Material_Certification(
val material_name : String,
val use_type : String,
val standard : String,
val material_num : String
)
class QualityMaterialCertificationAdapter(private val dataset:
List<Quality_Material_Certification>) :RecyclerView.Adapter<QualityMaterialCertificationAdapter.QualityMaterialCertificationViewHolder>() {
class QualityMaterialCertificationViewHolder(val binding:
ItemQualityMaterialCertificationBinding) :
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int):
QualityMaterialCertificationViewHolder {
val view =LayoutInflater.from(viewGroup.context).inflate(R.layout.item_quality_material_certification, viewGroup, false)
return QualityMaterialCertificationViewHolder(ItemQualityMaterialCertificationBinding.bind(view))
}
override fun onBindViewHolder(viewHolder: QualityMaterialCertificationViewHolder, position: Int) {
val listposition = dataset[position]
viewHolder.binding.materialName.text= listposition.material_name
viewHolder.binding.useType.text = listposition.use_type
viewHolder.binding.standard.text = listposition.standard
viewHolder.binding.goToMoreBtn.setOnClickListener {
setDataAtFragment(Fragment2(), listposition.material_num)
}
}
override fun getItemCount() = dataset.size
private fun setDataAtFragment(fragment: Fragment, material : String)
{
val bundle = Bundle()
val transaction = binding.root.supportFragmentManager?.beginTransaction()
bundle.putString("material", material)
fragment.arguments = bundle
transaction?.replace(R.id.appro_fl, fragment)?.commit()
}
}
fragment1
private var token : String? = null
private var const_code : String? = null
private var list = arrayListOf<Quality_Material_Certification>()
class Fragment1 : Fragment() {
private lateinit var binding:
FragmentQualityManagementFirefightingMaterialsCertificationBinding
var material: GetApproMaterListDTO? = null
lateinit var data: Quality_Material_Certification
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = FragmentQualityManagementFirefightingMaterialsCertificationBinding.inflate(layoutInflater)
binding.materialRecycler.layoutManager = LinearLayoutManager(context)
binding.materialRecycler.adapter = QualityMaterialCertificationAdapter(list)
arguments?.let {
token = it.getString("token").toString()
const_code = it.getString("cons_code").toString()
}
val dto = RequestDTO( "0", "9")
retrofit.requestservice(sysCd, token.toString(), dto).enqueue(object :
Callback<GetApproMaterListDTO> {
override fun onFailure(call: Call<GetApproMaterListDTO>, t: Throwable) { Log.d("retrofit", t.toString()) }
#SuppressLint("NotifyDataSetChanged")
override fun onResponse(call: Call<GetApproMaterListDTO>, response: Response<GetApproMaterListDTO>) {
material = response.body()
list.clear()
for (i in 0 until material?.value?.list!!.size) {
val material_name = material?.value?.list?.get(i)?.material_name.toString()
val use_type = material?.value?.list?.get(i)?.use_type.toString()
val standard = material?.value?.list?.get(i)?.standard.toString()
val material_num = material?.value?.list?.get(i)?.material_num.toString()
data = Quality_Material_Certification(material_name, use_type, standard ,material_num )
list.add(data)
}
binding.materialRecycler.adapter?.notifyDataSetChanged()
}
})
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return binding.root
}
companion object {
#JvmStatic
fun newInstance(param1: String, param2: String) =
Fragment1().apply {
arguments = Bundle().apply {
}
}
}
}
modified comment opinion
apdapter
interface clicktoDetail{
fun onClickDetail(model : CertificationDTO)
}
class CertificationAdapter(
private val context: Context,
private val dataset: List<CertificationDTO>,
private val clickListener: clicktoDetail)
: RecyclerView.Adapter<QualityMaterialCertificationAdapter.ChangeHolder>() {
inner class ChangeHolder(val binding: ItemCertificationBinding) : RecyclerView.ViewHolder(binding.root){
//val btn :Button = button.findViewById(R.id.go_to_more_btn)
init{
binding.goToMoreBtn.setOnClickListener { clickListener.onClickDetail(dataset[position]) }
}
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ChangeHolder {
val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.item_certification, viewGroup, false)
return ChangeHolder(ItemCertificationBinding.bind(view))
}
override fun onBindViewHolder(viewHolder: ChangeHolder, position: Int) {
val listposition = dataset[position]
viewHolder.binding.materialName.text= listposition.material_name
viewHolder.binding.useType.text = listposition.use_type
viewHolder.binding.standard.text = listposition.standard
viewHolder.binding.madeCompanyName.text = listposition.produce_co
/* viewHolder.binding.goToMoreBtn.setOnClickListener {
val intent = Intent(context, Fragment1::class.java)
intent.putExtra("cons_code", listposition.project_const)
intent.run{
context.startActivity(this)
(context as Activity).finish()
}
}*/
}
override fun getItemCount() = dataset.size
}
Fragment
private var token : String? = null
private var const_code : String? = null
private var material_list = arrayListOf<Quality_Material_CertificationDTO>()
class Certification_Fragment : Fragment() {
private lateinit var binding: FragmentQualityManagementFirefightingMaterialsCertificationBinding
var material: GetListDTO? = null
lateinit var material_data : Quality_Material_CertificationDTO
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = FragmentCertificationBinding.inflate(layoutInflater)
val retrofitApproMaterList = RetrofitC("http://")
val GetApproMaterListService: GetApproMaterListService = retrofitApproMaterList.create(GetListService::class.java)
binding.materialRecycler.layoutManager = LinearLayoutManager(context)
binding.materialRecycler.adapter = CertificationAdapter(requireContext(), material_list, GotoDetail())
arguments?.let {
token = it.getString("token").toString()
const_code = it.getString("cons_code").toString()
}
val mdto = RequestDTO("", "")
GetApproMaterListService.requestappromaterial(sysCd, token, mdto).enqueue(object :
Callback<GetListDTO> {
override fun onFailure(call: Call<GetListDTO>, t: Throwable) { Log.d("retrofit", t.toString()) }
#SuppressLint("NotifyDataSetChanged")
override fun onResponse(call: Call<GetAListDTO>, response: Response<GetListDTO>) {
material = response.body()
material_list.clear()
for (i in 0 until material?.value?.list!!.size) {
val material_name = material?.value?.list?.get(i)?.material_name.toString()
val use_type = material?.value?.list?.get(i)?.use_type.toString()
val standard = material?.value?.list?.get(i)?.standard.toString()
val produce_co = material?.value?.list?.get(i)?.produce_co.toString()
val material_num = material?.value?.list?.get(i)?.material_num.toString()
material_data = Quality_Material_CertificationDTO(material_name, use_type, standard, produce_co ,material_num)
material_list.add(material_data)
CertificationAdapter(requireContext(), material_list, GotoDetail())
}
binding.materialRecycler.adapter?.notifyDataSetChanged()
}
})
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return binding.root
}
companion object {
#JvmStatic
fun newInstance(param1: String, param2: String) =
Quality_Management_Firefighting_Materials_Certification_Fragment().apply {
arguments = Bundle().apply {
}
}
}
class GotoDetail : Fragment(), clicktoDetail{
override fun onClickDetail(model: Quality_Material_CertificationDTO) {
val bundle = Bundle()
val transaction = activity?.supportFragmentManager?.beginTransaction()
bundle.putString("cons_code", const_code)
bundle.putString("token", token)
Fragment().arguments = bundle
transaction?.replace(R.id.appro_fl, Certification_More_Fragment())!!.commit()
}
}
}
You are trying to access activities and fragments inside your adapter class which is incorrect. Never do that! Instead, create an item click listener and create a reference to it in your activity. This way you can handle item click in your activity and perform fragment transactions.
Here, You can take help on how to do so by making an onClickInterface
I have home fragment and I want it to go to another fragment which will show its "details", which passes the data of the clicked recyclerview item to that "details" fragment.
When I click the article it will move to detail article which passes the data.
As for the code, here's the adapter:
class ArticleAdapter(private val articleList: ArrayList<Article>) :
RecyclerView.Adapter<ArticleAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val binding = ItemArticleBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return MyViewHolder(binding)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val data = articleList[position]
holder.bind(data)
}
class MyViewHolder(private val binding: ItemArticleBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(data: Article) {
Glide.with(binding.root.context)
.load(data.img)
.into(binding.articleImage)
binding.articleTitle.text = data.title
binding.root.setOnClickListener {
val article = Article(
data.title,
data.img,
data.content
)
}
}
}
override fun getItemCount(): Int {
return articleList.size
}
}
Here's my detailFragment
class DetailArticleFragment : Fragment() {
private var _binding: FragmentDetailArticleBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentDetailArticleBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val intent = Intent(binding.root.context, DetailArticleFragment::class.java)
val article = intent.getParcelableExtra<Article>(DETAIL_ARTICLE) as Article
Glide.with(this)
.load(article.img)
.into(_binding!!.articleImage)
_binding!!.articleTitle.text = article.title
_binding!!.articleDescription.text = article.content
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object {
const val DETAIL_ARTICLE = "detail_article"
}
}
You need to pass click listener interface to adapter, for example:
typealias OnArticleClick = (article: Article) -> Unit
class ArticleAdapter(
private val articleList: ArrayList<Article>
) :
RecyclerView.Adapter<ArticleAdapter.MyViewHolder>() {
var onArticleClick: OnArticleClick? = null
...
binding.root.setOnClickListener {
val article = Article(
data.title,
data.img,
data.content
)
onArticleClick?.invoke(article)
}
...
}
And init onArticleClick in your home fragment with RecyclerView:
adapter.apply {
onArticleClick = {
// show details fragment
}
}
I am creating a news app, I have a recycler view with buttons that have the name of category of news. I want to save the state of recycler view after I destroyed the app. Example if I click in Sport Categories, after I destroy the app and reopen it, the app should have sport category selected. The code its not having a bug but it doesn't save the state. The code it's written in fragment
Some of my code
var isFilterFromCategories = false
class HomeFragment : Fragment(), Callback, HomePageAdapter.Listener,CategoryListener {
private lateinit var binding : FragmentHomeBinding
private lateinit var adapter: HomePageAdapter
private lateinit var menuAdapter: MenuAdapter
private lateinit var currentCategory : String
private val viewModel by activityViewModels<ArticleViewModel>()
private var lastPosition : Int = 0
private var firstTime = true
private fun showPopUp(view: View) {
val popup = PopupMenu(context, view, Gravity.RIGHT)
popup.inflate(R.menu.content_of_dropdown_menu)
popup.setOnMenuItemClickListener(PopupMenu.OnMenuItemClickListener { item: MenuItem? ->
when (item!!.itemId) {
R.id.dm_raportimi -> {
reportArticle()
}
}
true
})
popup.show()
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
binding = DataBindingUtil.inflate(inflater,R.layout.fragment_home, container, false)
val window = requireActivity().window
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.statusBarColor = Color.BLACK
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val snapHelper = PagerSnapHelper()
snapHelper.attachToRecyclerView(binding.recyclerView)
setDrawerOpeningFunctionality()
initRecyclerView()
initMenuRecyclerView()
viewModel.initializeList()
val pref = requireActivity()!!.getPreferences(Context.MODE_PRIVATE)
lastPosition = pref.getInt("lastpos",0)
topMenuRecyclerView.scrollToPosition(lastPosition)
topMenuRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
lastPosition =
(topMenuRecyclerView.layoutManager as LinearLayoutManager?)!!.findFirstVisibleItemPosition()
}
})
viewModel.getArrayList().observe(requireActivity()){
adapter.setArticles(it)
}
}
override fun onDestroy() {
super.onDestroy()
//save position in Shared Preferences
val pref = requireActivity()!!.getPreferences(Context.MODE_PRIVATE)
val e = pref.edit()
e.putInt("lastpos",lastPosition)
Log.d("lololo",lastPosition.toString())
e.apply()
}
override fun onResume() {
super.onResume()
if (isFilterFromCategories) {
isFilterFromCategories = false
setUpComingFromCategorySelection()
}
}
private fun initRecyclerView(){
adapter = HomePageAdapter(requireContext(), this)
binding.recyclerView.adapter = adapter
}
private fun initMenuRecyclerView(){
menuAdapter = MenuAdapter(requireContext(),this)
binding.topMenuRecyclerView.apply {
adapter = menuAdapter
}
}
private fun openWebLink(url: String){
val webIntent: Intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(webIntent)
}
private fun shareLink(title: String, url: String){
val sharingIntent = Intent.createChooser(Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, "https://developer.android.com/training/sharing/")
putExtra(Intent.EXTRA_SUBJECT,url)
// (Optional) Here we're setting the title of the content
putExtra(Intent.EXTRA_TITLE, title)
// (Optional) Here we're passing a content URI to an image to be displayed
type = "rext/plain"
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
}, null)
startActivity(sharingIntent)
}
override fun sourceOfInformationClicked(link: String) {
openWebLink(link)
}
override fun shareLinkInformationClicked(name:String, link:String){
shareLink(name,link)
}
override fun showMoreOnClicked(view: View){
showPopUp(view)
}
private fun reportArticle() {
val action = HomeFragmentDirections.actionHomeFragmentToReportFragment()
findNavController().navigate(action)
}
private fun setDrawerOpeningFunctionality() {
val drawerLayout = requireActivity().findViewById<DrawerLayout>(R.id.drawer_layout)
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
binding.btnNavDraw.setOnClickListener {
with(drawerLayout){
if (!isDrawerOpen(GravityCompat.END)){
openDrawer(GravityCompat.END)
} else {
closeDrawer(GravityCompat.END)
}
}
}
}
override fun changeCategory(category: String){
viewModel.setNews(category)
binding.topMenuRecyclerView.adapter?.notifyDataSetChanged()
}
override fun selectCategoryListener(category: String, pos: Int) {
TODO("Not yet implemented")
}
private fun setUpComingFromCategorySelection(){
val args: HomeFragmentArgs by navArgs()
currentCategory = args.category
menuAdapter.setCategory(currentCategory)
menuAdapter.selected.add(args.position)
binding.topMenuRecyclerView.scrollToPosition(args.position)
viewModel.setNews(currentCategory)
}
}
You should save position on item click.Dont save position on onDestroy
private const val TAG = "DeviceAdapter"
class DeviceAdapter(
private val context: Context
, private val list: MutableList<UsbDevice>
, private val callback: (device: UsbDevice) -> Unit): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(context)
val binding = ItemDeviceBinding.inflate(inflater,parent,false)
return MyViewHolder(binding)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val device = list[position]
if (holder is MyViewHolder){
holder.binding.textHere.text = device.deviceName
holder.binding.textHere.setOnClickListener {
val pref = context.getSharedPreferences("SHARED_PREFERENCES_KEY",
Context.MODE_PRIVATE)
val editor = pref.edit()
editor.putInt("lastPos",position)
editor.apply()
}
}
}
override fun getItemCount(): Int {
return list.size
}
class MyViewHolder(val binding: ItemDeviceBinding): RecyclerView.ViewHolder(binding.root)
}
I have a RecyclerView in MVVM project. I have to get text from editText (searchWordEt) and then pass it to the function that invokes API method in viewmodel.API works fine and returns data. But when I invoke searchDefAdapter.submitList(response) in SearchFragment nothing happens and RecyclerView data not showing.
class SearchDefAdapter(
private var infoListener: OnItemClickListener,
private var addListener: OnItemClickListener
):
ListAdapter<Def, SearchDefViewHolder>(differCallback) {
interface OnItemClickListener {
fun onItemClick(position: Int)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchDefViewHolder {
return SearchDefViewHolder(
SearchWordCardBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
),
addListener,
infoListener
)
}
override fun onBindViewHolder(holder: SearchDefViewHolder, position: Int) {
holder.bind(getItem(position))
}
}
class SearchDefViewHolder(
private val binding: SearchWordCardBinding,
addListener: SearchDefAdapter.OnItemClickListener,
infoListener: SearchDefAdapter.OnItemClickListener
): RecyclerView.ViewHolder(binding.root) {
fun bind(data: Def) {
with (binding) {
searchCardTv.text = "${data.text} - ${data.tr[0].text}"
}
}
init {
binding.addSearchCard.setOnClickListener {
addListener.onItemClick(adapterPosition)
}
binding.infoSearchCard.setOnClickListener {
infoListener.onItemClick(adapterPosition)
}
}
}
val differCallback = object : DiffUtil.ItemCallback<Def>() {
override fun areItemsTheSame(oldItem: Def, newItem: Def): Boolean {
return oldItem.text == newItem.text
}
override fun areContentsTheSame(oldItem: Def, newItem: Def): Boolean {
return oldItem == newItem
}
}
#AndroidEntryPoint
class SearchFragment : Fragment() {
private var _binding: FragmentSearchBinding? = null
private val binding get() = _binding!!
lateinit var searchDefAdapter: SearchDefAdapter
private val viewModel: DictionaryViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentSearchBinding.inflate(inflater, container, false)
val view = binding.root
searchDefAdapter = SearchDefAdapter(
object : SearchDefAdapter.OnItemClickListener {
override fun onItemClick(position: Int) {
Log.d("tag", "Item Added!")
//viewModel.saveWord(position)
}
},
object : SearchDefAdapter.OnItemClickListener {
override fun onItemClick(position: Int) {
val wordFragment = WordFragment()
fragmentManager?.beginTransaction()?.replace(
R.id.nav_host_fragment_container,
wordFragment
)?.commit()
}
}
)
setUpRecyclerView(searchDefAdapter)
var job: Job? = null
binding.searchWordEt.addTextChangedListener { editable ->
job?.cancel()
job = MainScope().launch {
delay(SEARCH_WORD_TIME_DELAY)
editable?.let {
if (editable.toString().isNotEmpty())
viewModel.getTranslation(editable.toString())
}
}
}
viewModel.def.observe(viewLifecycleOwner, Observer { response ->
binding.apply {
searchDefAdapter.submitList(response)
}
})
return view
}
override fun onDestroyView() {
_binding = null
super.onDestroyView()
}
private fun setUpRecyclerView(adapter: SearchDefAdapter){
binding.searchRv.apply {
adapter
layoutManager = LinearLayoutManager(activity)
}
}
}
You haven't actually set the adapter in setUpRecyclerView()
private fun setUpRecyclerView(myAdapter: SearchDefAdapter){
binding.searchRv.apply {
layoutManager = LinearLayoutManager(activity)
adapter = myAdapter // here
}
}
Not sure why is this behaviour, but almost tried everything, please let me know in case you are aware of the fix for the issue
When I return from SellerAddNewProductActivity by clicking back button then RecyclerView always scroll to beginning
class SellerHomeFragment : Fragment() {
private var searchInputText:String = ""
private var sellerProductsViewListRecyclerView: RecyclerView? = null
private var layoutManager: RecyclerView.LayoutManager? = null
private var scroll_state: Parcelable? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.fragment_seller_home, container, false)
sellerProductsViewListRecyclerView = root.findViewById(R.id.seller_products_view_list)
layoutManager = LinearLayoutManager(this.context)
sellerProductsViewListRecyclerView?.layoutManager = layoutManager
val searchText: EditText = root.findViewById(R.id.seller_search_product_name)
val searchProductsBtn: Button = root.findViewById(R.id.seller_search_products_btn)
val sellerViewByProductState: Spinner = root.findViewById(R.id.seller_view_by_product_state)
sellerViewByProductState.setSelection(0)
searchProductsBtn.setOnClickListener {
searchInputText = searchText.text.toString()
createProductRecyclerView()
}
sellerViewByProductState?.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
createProductRecyclerView()
}
}
return root
}
override fun onResume() {
super.onResume()
if(scroll_state!=null){
sellerProductsViewListRecyclerView!!.layoutManager!!.onRestoreInstanceState(scroll_state)
}
}
override fun onPause() {
super.onPause()
scroll_state = sellerProductsViewListRecyclerView!!.layoutManager!!.onSaveInstanceState()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
createProductRecyclerView()
}
private fun createProductRecyclerView() {
var productRef: DatabaseReference = FirebaseDatabase.getInstance().reference.child(
PRODUCTS_DB_NAME
)
var options: FirebaseRecyclerOptions<Products>? = null
val sellerViewByProductState: Spinner =
requireView().findViewById(R.id.seller_view_by_product_state)
val selectedProductState = sellerViewByProductState.selectedItem.toString()
options = FirebaseRecyclerOptions.Builder<Products>().setQuery(
productRef.child(selectedProductState).orderByChild(SID_PROPERTY)
.equalTo(FirebaseAuth.getInstance().currentUser!!.uid), Products::class.java
).setLifecycleOwner(this).build()
val adapter = object : FirebaseRecyclerAdapter<Products, ProductViewHolder>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
return ProductViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.product_items_layout, parent, false)
)
}
protected override fun onBindViewHolder(
holder: ProductViewHolder,
position: Int,
model: Products
) {
holder.txtProductName.text = model.pname
holder.txtProductDescription.text = model.description
holder.txtProductPrice.text = "Price = ₹ " + model.price.toString()
val context = holder.itemView.context
Picasso.with(this#SellerHomeFragment.context).load(model.image).networkPolicy(
NetworkPolicy.OFFLINE
).tag(context).into(holder.imageView,
object : Callback {
override fun onSuccess() {
}
override fun onError() {
Picasso.with(this#SellerHomeFragment.context).load(model.image)
.into(holder.imageView)
}
})
holder.itemView.setOnClickListener {
val intent: Intent = Intent(
this#SellerHomeFragment.context,
SellerAddNewProductActivity::class.java
)
intent.putExtra("category", model.category)
intent.putExtra("pid", model.pid)
val sellerViewByProductState: Spinner =
requireView().findViewById(R.id.seller_view_by_product_state)
val existingProductState = sellerViewByProductState.selectedItem.toString()
intent.putExtra("existingProductState", existingProductState)
startActivity(intent)
}
}
}
sellerProductsViewListRecyclerView?.setAdapter(adapter)
adapter.startListening()
}
}
I'm not sure I understand your code, but I think if you call function setAdapter(adapter) after added product you reload adapter.
When you add item to adapter use function notifyItemInserted() or notifyItemRangeInserted(position, range) on adapter.