Jetpack Paging 3.0 with Airbnb/epoxy only load the first page - kotlin

I am trying to use Jetpack Paging 3.0 to get all the characters in Rick and Morty API using retrofit and display it using Airbnb/epoxy. But I only get the first page I've spent several hours trying to look for a solution but no luck.
Link to API
(Rick and Morty API)
CODE:
1 Retrofit
#GET("character/")
suspend fun getAllCharactersByPage(
#Query("page") pageIndex : Int
): Response<GetAllCharactersByPageResponse>
[2] Paging Source
class AllCharacterPagingSource(
private val repository: AllCharactersRepository) : PagingSource<Int, Character>() {
override suspend fun load(
params: LoadParams<Int>
): LoadResult<Int, Character> {
val pageNumber = params.key ?: 1
val prevKey = if (pageNumber == 1) null else pageNumber + 1
val response = NetworkLayer.apiClient.getAllCharactersByPage(pageNumber)
response.getException?.let {
return LoadResult.Error(it)
}
return LoadResult.Page(
data = response.body.results.map { CharacterMapper.buildFrom(it) },
prevKey = prevKey,
nextKey = getPageIndexFromNext(response.body.info.next)
)
}
override fun getRefreshKey(state: PagingState<Int, Character>): Int? {
return state.anchorPosition?.let {
state.closestPageToPosition(it)?.prevKey?.plus(1)
?: state.closestPageToPosition(it)?.nextKey?.minus(1)
}
}
private fun getPageIndexFromNext(next: String?): Int?{
return next?.split("?page=")?.get(1)?.toInt()
}
}
[3] View Model (Pager)
class AllCharactersViewModel : ViewModel() {
private val repository = AllCharactersRepository()
val flow = Pager(
PagingConfig(Constants.PAGE_SIZE, Constants.PREFETCH_SIZE, enablePlaceholders = false)
) {
AllCharacterPagingSource(repository)
}.flow.cachedIn(viewModelScope)
}
[4] Fragment (Submitting data)
iewLifecycleOwner.lifecycleScope.launch {
allCharactersViewModel.flow.collectLatest {
pagingEpoxyController.submitData(it)
}
}
binding.charactersEpoxyRecyclerView.setController(pagingEpoxyController)
[5] Epoxy Controller
class CharactersPagingEpoxyController : PagingDataEpoxyController<Character>() {
var context : Context? = null
override fun buildItemModel(currentPosition: Int, item: Character?): EpoxyModel<*> {
return CharacterCardModel(
character = item!!,
context = context!!,
onClick = { characterId ->
}
).id("characters_${item.id}")
}
data class CharacterCardModel(
val character : Character,
val context : Context,
val onClick: (Int) -> Unit
) : ViewBindingKotlinModel<CharacterCardContainerModelBinding>(R.layout.character_card_container_model) {
override fun CharacterCardContainerModelBinding.bind() {
Glide.with(context)
.load(character.image)
.into(imageView)
characterName.text = character.name
mirroredCharacterName.text = character.name
}
}
}
Thanks in advance!!!

I guess prevKey should be something like this
val previewPage= if (pageNumber ==1 ) null else pageNumber -1

Related

Observing live data from an API is not updating ui when data changes

I am trying to develop a football app demo. Data comes from an API from the api
It loads data as expected when app started, but when score of match changes, ui is not updating for scores by itself. I am using DiffUtil getChangePayload() to detect changes in score and status fields of Match objects which comes from the response. But it is not triggering when live match data changes. What am i missing?
P.S. I put layout in SwipeRefreshLayout and when i refresh, it gets scores and update the ui. But i want to see the match status and scores updating by itself.
Here is my code:
class MatchesViewModel(
app: Application,
private val repository: MatchesRepository
): AndroidViewModel(app) {
val matchesToday: MutableLiveData<List<Matche>> = MutableLiveData()
init {
getMatchesToday()
}
fun getMatchesToday() = viewModelScope.launch {
safeMatchesToday()
}
private suspend fun safeMatchesToday() {
if (Constants.checkConnection(this)) {
val response = repository.getMatchesToday()
if (response.isSuccessful) {
response.body()?.let {
matchesToday.postValue(it.matches)
}
}
}
}
}
class MatchesTodayFragment : Fragment() {
private var _binding: FragmentMatchesTodayBinding? =null
private val binding get() = _binding!!
private lateinit var mMatchesAdapter: MatchesAdapter
private val viewModel: MatchesViewModel by viewModels {
MatchesViewModelFactory(requireActivity().application, (requireActivity().application as MatchesApplication).repository)
}
#RequiresApi(Build.VERSION_CODES.N)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupRecyclerView()
viewModel.matchesToday.observe(viewLifecycleOwner) { matches ->
mMatchesAdapter.differ.submitList(matches)
}
binding.srlMatchesToday.setOnRefreshListener {
viewModel.getMatchesToday()
binding.srlMatchesToday.isRefreshing = false
}
}
}
class MatchesAdapter(val fragment: Fragment): RecyclerView.Adapter<MatchesAdapter.ViewHolder>() {
private val differCallback = object: DiffUtil.ItemCallback<Matche>() {
override fun areItemsTheSame(oldItem: Matche, newItem: Matche): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Matche, newItem: Matche): Boolean {
return oldItem.status == newItem.status &&
oldItem.score.fullTime.home == newItem.score.fullTime.home &&
oldItem.score.fullTime.away == newItem.score.fullTime.away &&
oldItem == newItem
}
override fun getChangePayload(oldItem: Matche, newItem: Matche): Any? {
val bundle: Bundle = bundleOf()
if (oldItem.status != newItem.status) {
bundle.apply {
putString(Constants.MATCH_STATUS, newItem.status)
}
}
if (oldItem.score.fullTime.home != newItem.score.fullTime.home) {
bundle.apply {
putInt(Constants.HOME_SCORE, newItem.score.fullTime.home)
}
}
if (oldItem.score.fullTime.away != newItem.score.fullTime.away) {
bundle.apply {
putInt(Constants.AWAY_SCORE, newItem.score.fullTime.away)
}
}
if (bundle.size() == 0) {
return null
}
return bundle
}
}
val differ = AsyncListDiffer(this, differCallback)
#SuppressLint("UseCompatLoadingForDrawables")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val match = differ.currentList[position]
holder.apply {
Glide.with(fragment)
.load(match.homeTeam.crest)
.placeholder(fragment.resources.getDrawable(R.drawable.ic_ball))
.into(ivHomeTeamImage)
Glide.with(fragment)
.load(match.awayTeam.crest)
.placeholder(fragment.resources.getDrawable(R.drawable.ic_ball))
.into(ivAwayTeamImage)
tvHomeTeamName.text = match.homeTeam.name
tvAwayTeamName.text = match.awayTeam.name
when (match.status) {
Constants.TIMED -> {
tvMatchTime.text = Constants.toTimeForTR(match.utcDate)
tvHomeTeamScore.text = "-"
tvAwayTeamScore.text = "-"
}
Constants.PAUSED -> {
tvMatchTime.text = Constants.FIRST_HALF
tvHomeTeamScore.text = match.score.fullTime.home.toString()
tvAwayTeamScore.text = match.score.fullTime.away.toString()
}
Constants.FINISHED -> {
tvMatchTime.text = Constants.FINISHED
tvHomeTeamScore.text = match.score.fullTime.home.toString()
tvAwayTeamScore.text = match.score.fullTime.away.toString()
}
else -> {
tvMatchTime.text = Constants.IN_PLAY
tvHomeTeamScore.text = match.score.fullTime.home.toString()
tvAwayTeamScore.text = match.score.fullTime.away.toString()
}
}
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
if (payloads.isNotEmpty()) {
val item = payloads[0] as Bundle
val status = item.getString(Constants.MATCH_STATUS)
val homeScore = item.getInt(Constants.HOME_SCORE)
val awayScore = item.getInt(Constants.AWAY_SCORE)
holder.apply {
tvMatchTime.text = status
tvHomeTeamScore.text = homeScore.toString()
tvAwayTeamScore.text = awayScore.toString()
Log.e("fuck", status.toString())
}
}
super.onBindViewHolder(holder, position, payloads)
}
override fun getItemCount(): Int {
return differ.currentList.size
}
}
LiveData only pushes new values if you command it to. Since you want to do it repeatedly, you need to create a loop. This is very easy to do using the liveData coroutine builder.
class MatchesViewModel(
app: Application,
private val repository: MatchesRepository
): AndroidViewModel(app) {
val matchesToday = liveData {
while (true) {
if (Constants.checkConnection(this)) {
val response = repository.getMatchesToday()
if (response.isSuccessful) {
response.body()?.let {
emit(it.matches)
}
}
}
delay(5000) // however many ms you want between fetches
}
}
}
If this is a Retrofit response, I think checking isSuccessful is redundant because body() will be non-null if and only if isSuccessful is true. So it could be simplified a bit from what you have:
class MatchesViewModel(
app: Application,
private val repository: MatchesRepository
): AndroidViewModel(app) {
val matchesToday = liveData {
while (true) {
if (Constants.checkConnection(this)) {
repository.getMatchesToday()?.body()?.matches?.let(::emit)
}
delay(5000) // however many ms you want between fetches
}
}
}

How to parse two data list from one PagingData Source in Android Kotlin?

This is My ViewModle Class
#HiltViewModel
class MainViewModel #Inject constructor(
private val movieRepository: MovieRepository,
private val favMovieRepository: FavMovieRepository
) : ViewModel() {
...
private var _movieState = mutableStateOf(false)
val movieState = _movieState
val nowPlayingMovies: Flow<PagingData<Movie>> = Pager(PagingConfig(pageSize = 10)) {
MoviePagingSource(movieRepository)
}.flow
val popularMovies: Flow<PagingData<Movie>> = Pager(PagingConfig(pageSize = 10)) {
MoviePagingSource(movieRepository)
}.flow
...
fun setListToPopular(){
_movieState.value = true
}
}
PagingSource file is here
class MoviePagingSource(
private val movieRepository: MovieRepository
) : PagingSource<Int , Movie>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Movie> {
return try {
val nextPage = params.key ?: 1
val nowPlayingMovieResponse = movieRepository.getNowPlayingMovies(nextPage)
val popularMovieResponse = movieRepository.getPopularMovies(nextPage)
LoadResult.Page(
data = nowPlayingMovieResponse.results,
prevKey = if (nextPage == 1) null else nextPage - 1,
nextKey = nowPlayingMovieResponse.page.plus(1)
)
LoadResult.Page(
data = popularMovieResponse.results,
prevKey = if (nextPage == 1) null else nextPage - 1,
nextKey = popularMovieResponse.page.plus(1)
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
...
}
Here I define two LoadResult one for NowPlaying other for popluar movies.
I want to get the follwing result as expected Below.
Here whenever i choose one result should be in my favour for that i have my Home screen.
#Composable
fun MovieListView(viewModel: MainViewModel) {
val lazyMovieItems = viewModel.nowPlayingMovies.collectAsLazyPagingItems()
val lazyPopularMovieItems = viewModel.popularMovies.collectAsLazyPagingItems()
val movieItems = if (!viewModel.movieState.value) lazyMovieItems else lazyPopularMovieItems
LazyColumn {
item {
Row(... ) {
PopularityDropDown(){
viewModel.setListToPopular()
}
} }
items(movieItems) { item ->
MovieCard(movie = item!!) {
...
)
}else Log.d(TAG, "MovieListView: ${item.original_title} with id ${item.id} It is Not favorite ")
}
}
movieItems.apply {
...
}
}
What should be the way for fetching data from PagingSource ? and please suggest better way for handling NowPlaying and popular movie.

Can't Update child item in NestedRecyclerView

How do I update the child when clicking on the categories item or when doing a search like the one in the picture
I am updating the data from Viewmodel but the child element does not update
I also tried calling the adapter child and updating it directly, but to no avail
This is the code, if you need any additional details, I will add it down
In ParentAdapter
class BaseAdapter(private val listener: OnItemClickListener
): RecyclerView.Adapter<BaseViewHolder>() {
var items : MutableList<HomeItem<Any>> = mutableListOf()
lateinit var adapter : SubjectsAdapter
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
return when (viewType){
VIEW_ITEM_SEARCH ->{
val view = LayoutInflater.from(parent.context).inflate(
R.layout.item_search_view,
parent,false
)
BaseViewHolder.SearchItemViewHolder(view)
}
VIEW_ITEM_STUDENT ->{
val view = LayoutInflater.from(parent.context).inflate(
R.layout.item_student, parent,false
)
BaseViewHolder.StudentItemViewHolder(view)
}
VIEW_ITEM_COLOR ->{
val view = LayoutInflater.from(parent.context).inflate(
R.layout.item_chip_list, parent,false
)
BaseViewHolder.YearsItemViewHolder(view)
}
VIEW_ITEM_SUBJECT ->{
val view = LayoutInflater.from(parent.context).inflate(
R.layout.item_subject_list, parent,false
)
BaseViewHolder.SubjectsItemViewHolder(view)
}
else -> throw Exception("UnKnow View Type")
}
}
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
when (holder){
is BaseViewHolder.SearchItemViewHolder -> bindSearch(holder,position)
is BaseViewHolder.StudentItemViewHolder -> bindStudent(holder,position)
is BaseViewHolder.YearsItemViewHolder -> bindYears(holder,position)
is BaseViewHolder.SubjectsItemViewHolder -> bindSubjects(holder,position)
}
}
fun bindYears(holder: BaseViewHolder.YearsItemViewHolder,position: Int){
val p = items[position].item as List<SubjectsColor>
val adapterchip = ChipAdapter { chip ->
listener.onSubjectColorClick(chip)
}
holder.binding.apply {
recyclerChipList.layoutManager = LinearLayoutManager(root.context,
LinearLayoutManager.HORIZONTAL,
false)
recyclerChipList.adapter = adapterchip
recyclerChipList.setHasFixedSize(true)
}
adapterchip.submitList(p)
}
fun bindSubjects(holder :BaseViewHolder.SubjectsItemViewHolder,position: Int){
val p = items[position].item as List<SubjectStudent>
adapter = SubjectsAdapter{ subject->
listener.onSubjectStudentClick(subject)
}
holder.binding.apply {
recyclerSubjectList.layoutManager = LinearLayoutManager(root.context,
LinearLayoutManager.VERTICAL,
false)
recyclerSubjectList.adapter = adapter
recyclerSubjectList.setHasFixedSize(true)
}
Log.d("BindSubjects","BindSubjects : $p")
adapter.submitList(p)
}
In ViewModel
#HiltViewModel
class HomeViewModel #Inject constructor(
private val subDao : SubjectsDao,
//state : SavedStateHandle
) : ViewModel(){
private val colorId = MutableLiveData(1)
val colorIdResult = colorId.asFlow().flatMapLatest(){ id ->
id.let {
subDao.getAllSubjectStudentByColor(id)
}
}.stateIn(viewModelScope, SharingStarted.Lazily, null)
fun getAllSubjectsColor() :Flow<List<SubjectsColor>> =
subDao.getAllSubjectColors()
fun onSubjectColorClick(colorI:Int){
colorId.postValue(colorI)
}}
In Fragment
adapterBase = BaseAdapter(this)
val itemsList: MutableList<HomeItem<Any>> = mutableListOf()
itemsList.add(HomeItem("Google Home", HomeItemType.TYPE_SEARCH))
itemsList.add(HomeItem("Student", HomeItemType.TYPE_PROFILE))
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewModel.getAllSubjectsColor().collect {
itemsList.add(HomeItem(it, HomeItemType.TYPE_COLORS))
}
}
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewModel.colorIdResult.collect { id ->
val result = id ?: return#collect
itemsList.add(HomeItem(result.subjectStudent, HomeItemType.TYPE_SUBJECTS))
//adapterBase.notifyDataSetChanged()
}
}
binding.apply {
recyclerBaseFragment.layoutManager = LinearLayoutManager(requireContext())
recyclerBaseFragment.setHasFixedSize(true)
recyclerBaseFragment.adapter = adapterBase
}
adapterBase.items = itemsList
}
enum class HomeItemType {
TYPE_SEARCH,
TYPE_PROFILE,
TYPE_COLORS,
TYPE_SUBJECTS
}
data class HomeItem<T>(
var item :T,
val type: HomeItemType
)

Unresolved reference: myViewHolder after switching to View Binding

After switching from removing kotlin_extensions and switching to view binding, I received a "Unresolved reference: myViewHolder" in my onBindViewHolder method and when I replace "myViewHolder" with "holder", it then gives me a "Unresolved reference: bind". How do I resolve this.
MyAdapter
class MyAdapter(private val context: Context, private val mHelper : TaskDbHelper) : RecyclerView.Adapter<MyAdapter.MyViewHolder>(),
SwipeAndDragHelper.ActionCompletionContract {
class MyViewHolder(val binding: CellCardsBinding): RecyclerView.ViewHolder(binding.root ) {
fun binding() {
}
}
private var touchHelper: ItemTouchHelper? = null
private var list = mutableListOf<MyObject>()
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
initList()
super.onAttachedToRecyclerView(recyclerView)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(CellCardsBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
#RequiresApi(Build.VERSION_CODES.P)
#SuppressLint("ClickableViewAccessibility")
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val myObject = list[position]
myViewHolder.bind(myObject)
val activity: Activity = context as Activity
holder.binding.text.setOnClickListener{
activity.launchActivity<AddNoteActivity>(42) {
putExtra("PositionInList", position.toString())
putExtra("TaskTitle", myObject.title)
putExtra("TaskText", myObject.text)
}
}
activity.findViewById<RecyclerView>(R.id.recyclerView).setOnTouchListener { _, event ->
when (event.actionMasked) {
MotionEvent.ACTION_UP -> {
updateNotesPositionInDb()
false
}
else -> {
false
}
}
}
holder.binding.title.setOnTouchListener { _, event ->
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
touchHelper!!.startDrag(holder)
false
}
else -> {
false
}
}
}
}
private fun initList() {
list.clear()
val db = mHelper.readableDatabase
val cursor = db.query(
TaskContract.TaskEntry.TABLE,
arrayOf(
TaskContract.TaskEntry.ID,
TaskContract.TaskEntry.COL_TASK_TITLE,
TaskContract.TaskEntry.COL_TASK_TEXT,
TaskContract.TaskEntry.COL_TASK_DATE),null, null, null, null, TaskContract.TaskEntry.ID)
while (cursor.moveToNext()) {
val id = cursor.getColumnIndex(TaskContract.TaskEntry.ID)
val idTitle = cursor.getColumnIndex(TaskContract.TaskEntry.COL_TASK_TITLE)
val idText = cursor.getColumnIndex(TaskContract.TaskEntry.COL_TASK_TEXT)
val idDate = cursor.getColumnIndex(TaskContract.TaskEntry.COL_TASK_DATE)
list.add(MyObject(cursor.getString(id), cursor.getString(idTitle), cursor.getString(idText), cursor.getString(idDate)))
}
notifyDataSetChanged()
cursor.close()
db.close()
}
override fun getItemCount(): Int {
return list.size
}
override fun onViewMoved(oldPosition: Int, newPosition: Int) {
val target = list[oldPosition]
list.removeAt(oldPosition)
list.add(newPosition, target)
notifyItemMoved(oldPosition, newPosition)
}
override fun onViewSwiped(position: Int) {
deleteTask(list[position].ID)
list.removeAt(position)
notifyItemRemoved(position)
updateNotesPositionInDb()
}
fun setTouchHelper(touchHelper: ItemTouchHelper) {
this.touchHelper = touchHelper
}
fun addTask(taskTitle : String, taskText: String) {
val values = ContentValues()
val sdf = SimpleDateFormat("dd/MM/yyyy/", Locale.US)
val date = sdf.format(Date())
values.put(TaskContract.TaskEntry.ID, list.size)
values.put(TaskContract.TaskEntry.COL_TASK_TITLE, taskTitle)
values.put(TaskContract.TaskEntry.COL_TASK_TEXT, taskText)
values.put(TaskContract.TaskEntry.COL_TASK_DATE, date)
val db = mHelper.readableDatabase
db.insertWithOnConflict(TaskContract.TaskEntry.TABLE,
null,
values,
SQLiteDatabase.CONFLICT_REPLACE)
db.close()
list.add(MyObject(list.size.toString(), taskTitle, taskText, date))
notifyItemInserted(list.size)
}
fun addTask() {
val test: Activity = context as Activity
test.launchActivity<AddNoteActivity>(42) {
/* putExtra("user", "854")
p utExtra("user2", "46850") */
}
}
private fun deleteTask(taskId: String) {
val db = mHelper.readableDatabase
db.delete(TaskContract.TaskEntry.TABLE,
"id=$taskId", null)
db.close()
}
fun modifyTask(taskPosition: String, taskTitle: String, taskText: String) {
val target = list[taskPosition.toInt()]
target.title = taskTitle
target.text = taskText
val values = ContentValues()
val sdf = SimpleDateFormat("dd/MM/yyyy/", Locale.US)
val date = sdf.format(Date())
values.put(TaskContract.TaskEntry.ID, taskPosition)
values.put(TaskContract.TaskEntry.COL_TASK_TITLE, taskTitle)
values.put(TaskContract.TaskEntry.COL_TASK_TEXT, taskText)
values.put(TaskContract.TaskEntry.COL_TASK_DATE, date)
val db = mHelper.readableDatabase
db.update(TaskContract.TaskEntry.TABLE,
values, TaskContract.TaskEntry.ID + "=" + target.ID, null)
db.close()
notifyItemChanged(taskPosition.toInt())
}
private fun updateNotesPositionInDb() {
val db = mHelper.readableDatabase
var i = 0
while (i < list.size) {
val values = ContentValues()
values.put(TaskContract.TaskEntry.ID, i)
db.update(TaskContract.TaskEntry.TABLE,
values, TaskContract.TaskEntry.ID + "=? AND " + TaskContract.TaskEntry.COL_TASK_TITLE + "=?", arrayOf(list[i].ID, list[i].title))
i++
}
db.close()
}
I've tried reading Android Studio's official documentation, but it cannot solve my specific problem.
in your class MyViewHolder you have method called binding and you need also to implement it and add paramter
shoud be
class MyViewHolder(private val binding: CellCardsBinding): RecyclerView.ViewHolder(binding.root ) {
fun bind(data:MyObject) {
binding.yourView=data.title ...
}
}
in onBindViewHolder
..
holder.bind(myObject)
After switching from removing kotlin_extensions and switching to view binding, I received a "Unresolved reference: myViewHolder" in my onBindViewHolder method
Well, your onBindViewHolder method is passing a variable called holder and you're trying to use a variable called myViewHolder, so that seems like a problem.
// --------------------this-----v
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val myObject = list[position]
// v--- doesn't match this
myViewHolder.bind(myObject)
and when I replace "myViewHolder" with "holder", it then gives me a "Unresolved reference: bind". How do I resolve this.
Your MyViewHolder class has a method called binding that takes no arguments. There is no bind method that takes a "myObject".
class MyViewHolder(val binding: CellCardsBinding): RecyclerView.ViewHolder(binding.root ) {
fun binding() {
}
}
Edit
You should pass an instance of the data class
class MyViewHolder(val binding: CellCardsBinding): RecyclerView.ViewHolder(binding.root ) {
fun bind(object: MyObject) {
// Set variables on binding
}
}
Then pass an instance from your list via onBindViewHolder:
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val myObject = list[position]
holder.bind(myObject)
Please check this blog post for more.
I got my answer.
class MyAdapter(private val context: Context, private val mHelper : TaskDbHelper) : RecyclerView.Adapter<MyAdapter.MyViewHolder>(),
SwipeAndDragHelper.ActionCompletionContract {
class MyViewHolder(val binding: CellCardsBinding): RecyclerView.ViewHolder(binding.root ) {
private val titleView: TextView = itemView.findViewById<View>(R.id.title) as TextView
val textView: TextView = itemView.findViewById<View>(R.id.text) as TextView
private val dateTextView: TextView = itemView.findViewById<View>(R.id.date) as TextView
fun binding (myObject: MyObject) {
titleView.text = myObject.title
textView.text = myObject.text
dateTextView.text = myObject.date
}
}
I simply initialised the view I wanted to reference in my layout and called them in the binding() function.

how to get the data from an getParcelableArrayListExtra<Parcelable> in kotlin

How to get the data from an getParcelableArrayListExtra in kotlin?.
I have a Parceable data class called FoodParceable
data class FoodParceable(val idCover: Int, val name: String, val
price: Double):Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString(),
parcel.readDouble()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(idCover)
parcel.writeString(name)
parcel.writeDouble(price)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<FoodParceable> {
override fun createFromParcel(parcel: Parcel): FoodParceable {
return FoodParceable(parcel)
}
override fun newArray(size: Int): Array<FoodParceable?> {
return arrayOfNulls(size)
}
}
}
In the current Acitvity A, fill in the arrayListParceable and send it to activity B.
val arrayListParceable = ArrayList<FoodParceable>()
for (Food in listFood) {
arrayListParceable.add(FoodParceable(R.mipmap.ic_food_meat, "Carne", 9.99))
arrayListParceable.add(FoodParceable(R.mipmap.ic_food_meat, "Vegetales", 29.99))
arrayListParceable.add(FoodParceable(R.mipmap.ic_food_meat, "Frutas", 39.99))
}
val intent = Intent()
intent.putParcelableArrayListExtra(LIST_PRODUCT,arrayListParceable)
activity?.setResult(Activity.RESULT_OK, intent)
When I get the value in activity B, in list item, I can not enter its content.
if(resultCode == Activity.RESULT_OK){
if(data != null){
val listItems = data.getParcelableArrayListExtra<Parcelable>(LIST_PRODUCT)
listItems[0]. //ERROR
}
}
I am new to kotlin, thank you for your comments. Regards
You have to give Kotlin more information about the type of your object list. Try this:
val listItems : ArrayList<FoodParceable> = data.getParcelableArrayListExtra(LIST_PRODUCT)