How do I change the viewmodel observable data in android? - android

I created a gridView that has an ArrayAdapter, the gridView contains only photos, I am fetching the image url in an Array and I am observing the array through my activity. Here is my viewmodel
class ProfileViewModel constructor(): ViewModel() {
var first_name: String? = null
var last_name: String? = null
var dob: String? = null
var address: String? = null
var organization: String? = null
var hobby: String? = null
var bio: String? = null
var imagePath: String = ""
private val imageList : MutableLiveData<ArrayList<ProfileViewModel>> = MutableLiveData()
constructor(photo : Photo) : this() {
this.imagePath = photo.imageUrl
}
fun getImageUrl() : String {
return imagePath
}
companion object {
#BindingAdapter("imageUrl")
#JvmStatic
fun loadImage(imageView: ImageView, imageUrl: String) {
Glide.with(imageView.context)
.load(imageUrl)
.apply(RequestOptions.centerCropTransform())
.placeholder(R.drawable.ic_add_icon)
.into(imageView)
}
}
val profileViewModels : MutableLiveData<ArrayList<ProfileViewModel>>
get() {
val profileViewModels = ArrayList<ProfileViewModel>()
val photo1 = Photo("")
val profileVM = ProfileViewModel(photo1)
repeat(6) {
profileViewModels.add(profileVM)
}
imageList.value = profileViewModels
return imageList
}
}
}
Here is my activity where I am observing the data
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityProfileBinding =
DataBindingUtil.setContentView(this, R.layout.activity_profile)
val viewModel = ViewModelProvider(this).get(ProfileViewModel::class.java)
viewModel.profileViewModels.observe(this,
Observer<ArrayList<ProfileViewModel>> { image_paths ->
Log.d("added", "$image_paths")
val imageAdapter = ImageAdapter(this#Profile, R.layout.image_card, image_paths!!)
gridView.adapter = imageAdapter
})
}
I am getting images in the gridView but I want to update the observable value on gridView Item click in the clicked position. How do I do that?

First, you can create a function in viewmodel, that you want to do when clicked. for example:
private fun doSomethingWhenClicked(listPosition: Int){
val clickedImage = profileViewModels[position]
//do something here for clicked image
//..
}
Then, initialize the viewmodel in adapter like this. So you can update your profileViewModels in onClickListener inside the ImageAdapter
viewmodel.doSomethingWhenClicked(position)
Hope this answer you!

Related

why is the key not added to the data in firebase?

I've been struggling with the problem for a long time and I can't solve it.I'm in EditActivity trying to add a key to the data from the firebase that I get from it with the help of Ad and process it using the AdsManager.
The key should not be equal to zero. In this line I check if the key is zero, then the Firebase writes data to empty.db.child (ad.key?: "Empty"). SetValue (ad). When I load the data to the Firebase, it shows them empty. Without displaying the key. You know what the problem is?
Ad
data class Ad(
var user_id : String? = null ,
var name : String? = null ,
var button1 : String? = null ,
val textTex : String? = null ,
val textk : String? = null ,
val description : String? = null,
val name_ads: String?=null,
val key :String? =null
)
AdsManager
class AdsManager(val readDataColbak : ReadDataColbak?) {
private lateinit var auth: FirebaseAuth
val db =Firebase.database.getReference("main")
fun pubilshAd(ad :Ad) {
db.child(ad.key?: "empty").setValue(ad)
}
fun ReadDataDb() {
db.addListenerForSingleValueEvent(object :ValueEventListener{
override fun onDataChange(snapshot : DataSnapshot) {
val adArray =ArrayList<Ad>()
for (item in snapshot.children){
val ad =item.children.iterator().next().child("ad").getValue(Ad::class.java)
adArray.add(ad !!)
}
readDataColbak?.readData(adArray)
}
override fun onCancelled(error : DatabaseError) {
}
})
}
}
EditActivity1
class EditActivity1: AppCompatActivity(), FfragmentInterfes{
lateinit var mBinder : ActivityEdit1Binding
private var dialog=D()
private var chooseImageFrog:FragmentList? =null
val adsManager = AdsManager(null)
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
imageAdapter = ImageAdapter()
mBinder=ActivityEdit1Binding.inflate(layoutInflater)
setContentView(mBinder.root)
init()
}
fun onClickPublish(view : View) {
adsManager.pubilshAd(fillAd())
}
private fun fillAd() : Ad {
var ad : Ad
mBinder.apply {
ad= Ad(
name_ads.text.toString(),
user_id.text.toString(),
name.text.toString(),
button1.text.toString(),
description.text.toString(),
textk.text.toString(),
adsManager.db.push().key
)
}
return ad
}

extras.getString() returns null in Kotlin Android

The result is always return null, I don't know what mistake, I have seen other people problems I am not getting what I need exactly.
class DatabaseLists(private val context: Context?) {
private lateinit var database: SQLiteDatabase
val getPrayerContentList: ArrayList<PrayerModel>
#SuppressLint("Recycle")
get() {
database = DatabaseOpenHelper(context).readableDatabase
val cursor: Cursor = database.query(
"table_prayer",
null,
null,
null,
null,
null,
null,
null
)
val contentList = ArrayList<PrayerModel>()
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast) {
val contents = PrayerModel(
cursor.getString(cursor.getColumnIndex("prayer_name")),
cursor.getString(cursor.getColumnIndex("ayah_name")),
cursor.getString(cursor.getColumnIndex("arabic")),
cursor.getString(cursor.getColumnIndex("latin")),
cursor.getString(cursor.getColumnIndex("translate")),
cursor.getString(cursor.getColumnIndex("description"))
)
contentList.add(contents)
cursor.moveToNext()
if (cursor.isClosed) {
cursor.close()
}
}
}
return contentList
}
class PrayerActivity : AppCompatActivity(), MainContract.MainView {
private lateinit var binding: ActivityPrayerBinding
private var database: SQLiteDatabase? = null
private lateinit var preferences: SharedPreferences
private lateinit var editor: SharedPreferences.Editor
lateinit var carlist: ArrayList<PrayerModel>
private lateinit var prayerContentList: MutableList<PrayerModel>
private lateinit var prayerAdapter: PrayerAdapter
private lateinit var mainPresenterImpl: MainPresenterImpl
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_prayer)
setSupportActionBar(binding.toolbar)
preferences = PreferenceManager.getDefaultSharedPreferences(this)
editor = preferences.edit()
PreferenceManager.getDefaultSharedPreferences(this)
database = DatabaseOpenHelper(this).readableDatabase
prayerContentList = DatabaseLists(this).getPrayerContentList
mainPresenterImpl = MainPresenterImpl(this, this)
initMainContent()
}
override fun initMainContent() {
val verticalLayout = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
binding.rvMainContent.layoutManager = verticalLayout
prayerAdapter = PrayerAdapter(this, prayerContentList)
binding.rvMainContent.adapter = prayerAdapter
}
}
data class PrayerModel (
val strPrayerName: String?,
val strAyahName: String?,
val strContentArabic: String?,
val strContentLatin: String?,
val strContentTranslation: String?,
val strContentDescription: String?)
myAdapter
class PrayerAdapter(context: Context, private val prayerContentList: MutableList<PrayerModel>) :
RecyclerView.Adapter<PrayerViewHolder>() {
private val context: Context? = null
private val inflater = LayoutInflater.from(context)
private var currentIndex: Int = -1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PrayerViewHolder {
return PrayerViewHolder(inflater.inflate(R.layout.item_prayer_content, parent, false))
}
override fun getItemCount(): Int {
return prayerContentList.size
}
override fun onBindViewHolder(holder: PrayerViewHolder, position: Int) {
val strContentArabic = prayerContentList[position].strContentArabic
val strContentLatin = prayerContentList[position].strContentLatin
val strContentTranslation = prayerContentList[position].strContentTranslation
val strContentDescription = prayerContentList[position].strContentDescription
val strPrayerName = prayerContentList[position].strPrayerName
val strAyahName = prayerContentList[position].strAyahName
holder.tvContentPrayerName.text = strPrayerName
holder.tvContentAyahName.text = strAyahName
holder.itemView.setOnClickListener { v ->
val context: Context = v.context
val intent = Intent(context, PrayerReadActivity::class.java)
intent.putExtra("ARABIC_TEXT", strContentArabic?.get(position))
intent.putExtra("LATIN_TEXT", strContentLatin!![position])
intent.putExtra("TRANSLATION_TEXT", strContentTranslation!![position])
intent.putExtra("DESCRIPTION_TEXT", strContentDescription!![position])
context.startActivity(intent)
Log.d(TAG, "-->name = $strContentArabic")
}
}
}
my 2Activity can have code like this, and trying to get that string extra in another activity but is returning null?
class PrayerReadActivity() : AppCompatActivity() {
private var database: SQLiteDatabase? = null
private lateinit var prayerContentList: MutableList<PrayerModel>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_prayer_read)
LockOrientation(this).lock()
PreferenceManager.getDefaultSharedPreferences(this)
database = DatabaseOpenHelper(this).readableDatabase
prayerContentList = DatabaseLists(this).getPrayerContentList
val extras = intent.extras
if (null != extras) {
val arabic = extras.getString("ARABIC_TEXT").toString()
val latin = extras.getString("LATIN_TEXT").toString()
val translation = extras.getString("TRANSLATION_TEXT").toString()
val description = extras.getString("DESCRIPTION_TEXT").toString()
Log.d(ContentValues.TAG, "-->arabic = $arabic")
tvContentArabic2.text = arabic
tvContentLatin2.text = latin
tvContentTranslation2.text = translation
tvContentDescription2.text = description
Log.d(ContentValues.TAG, "-->arabic = $arabic")
Log.d(ContentValues.TAG, "-->latin = $latin")
Log.d(ContentValues.TAG, "-->translation = $translation")
Log.d(ContentValues.TAG, "-->description = $description")
}
I tried by replacing
val arabic = intent.getStringExtra("ARABIC_TEXT").toString()
also still it is returning null?
2021-07-22 22:31:16.411 9607-9607/com.example.yasiin D/ContentValues: -->arabic = null
2021-07-22 22:31:16.411 9607-9607/com.example.yasiin D/ContentValues: -->arabic = null
2021-07-22 22:31:16.411 9607-9607/com.example.yasiin D/ContentValues: -->latin = null
2021-07-22 22:31:16.411 9607-9607/com.example.yasiin D/ContentValues: -->translation = null
2021-07-22 22:31:16.411 9607-9607/com.example.yasiin D/ContentValues: -->description = null
Try replacing this
intent.putExtra("ARABIC_TEXT", strContentArabic?.get(position))
intent.putExtra("LATIN_TEXT", strContentLatin!![position])
intent.putExtra("TRANSLATION_TEXT", strContentTranslation!![position])
intent.putExtra("DESCRIPTION_TEXT", strContentDescription!![position])
With this
intent.putExtra("ARABIC_TEXT", strContentArabic)
intent.putExtra("LATIN_TEXT", strContentLatin)
intent.putExtra("TRANSLATION_TEXT", strContentTranslation)
intent.putExtra("DESCRIPTION_TEXT", strContentDescription)
You have already have the string, just put it in the extras.
Please just try the below line of code to update and check in your PrayerActivity, for this you can create one interface callback and call interface method(varargs with multiple params or string or pojo class) from adapter class where you are opening intent currently, then from PrayerActivity activity you can open it
val intent = Intent(this#PrayerActivity, PrayerReadActivity::class.java)
intent.putExtra("ARABIC_TEXT", strContentArabic?.get(position))
intent.putExtra("LATIN_TEXT", strContentLatin!![position])
intent.putExtra("TRANSLATION_TEXT", strContentTranslation!![position])
intent.putExtra("DESCRIPTION_TEXT", strContentDescription!![position])
startActivity(intent)
hope it may help you

RecyclerView make endless scrolling with JSON

I'm trying to make my Android App (I'm only experienced in iOS).
I created a RecyclerView that gets the data from a web. I tried everything to implement endless scrolling to load more items, but when I call the function to get the items, the entire RecyclerView loads again and no attach the new results on the bottom.
This is my code:
ConversationUser.kt
data class ConversationUser(
val message_nickname: String,
val message_image_thumb: String,
val message_large_thumb: String,
val message_modified: String,
val message_status: String,
val message_unread: Int,
val conv_id: String,
val message_dest: String) {
}
ConversacionesActivity.kt
class ConversacionesActivity : AppCompatActivity() {
// MARK: Variables
var user_token = ""
var user_id = ""
override fun onCreate(savedInstanceState: Bundle?) {
// User Defaults
val sharedPreferences = getSharedPreferences("Preferences", Context.MODE_PRIVATE)
user_token = sharedPreferences.getString("user_token", "")!!
user_id = sharedPreferences.getString("user_id", "")!!
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_conversaciones)
recyclerConv.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
getConversationsData()
recyclerConv.setLoadingListener(object : LoadingListener {
override fun onRefresh() {
//refresh data here
}
override fun onLoadMore() {
// load more data here
getConversationsData()
}
})
}
fun getConversationsData() {
val httpAsync = "https://mywebsite.com/conversations/${user_token}"
.httpPost()
.responseString { request, response, result ->
when (result) {
is Result.Failure -> {
val ex = result.getException()
println(ex)
}
is Result.Success -> {
val data = result.get()
runOnUiThread {
val conversaciones = processJson(data)
show(conversaciones)
return#runOnUiThread
}
}
}
}
httpAsync.join()
}
fun processJson(json: String): List<ConversationUser> {
val gson: Gson = GsonBuilder().create()
val conversaciones: List<ConversationUser> = gson.fromJson(
json,
Array<ConversationUser>::class.java
).toList()
return conversaciones
}
fun show(conversaciones: List<ConversationUser>) {
recyclerConv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
recyclerConv.adapter = AdaptadorConv(conversaciones, this, user_token, user_id)
}
AdaptadorConv.kt
class AdaptadorConv(
val conversaciones: List<ConversationUser> = ArrayList(),
val context: Context,
val user_token: String,
val user_id: String) : RecyclerView.Adapter<AdaptadorConv.ConvViewHolder>() {
override fun onBindViewHolder(holder: ConvViewHolder, position: Int) {
holder.convName.text = conversaciones[position].message_nickname
holder.convTime.text = conversaciones[position].message_modified
}
override fun getItemCount(): Int {
return conversaciones.size - 1
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ConvViewHolder {
val view: View = LayoutInflater.from(parent.context).inflate(
R.layout.conversaciones,
parent,
false
)
return ConvViewHolder(view)
}
class ConvViewHolder(vista: View): RecyclerView.ViewHolder(vista) {
val convImg: ImageView = itemView.findViewById(R.id.convImg)
val convStatus: ImageView = itemView.findViewById(R.id.convStatus)
val convName: TextView = itemView.findViewById(R.id.convName)
val convUnread: TextView = itemView.findViewById(R.id.convUnread)
val convTime: TextView = itemView.findViewById(R.id.convTime)
}
Thanks for any help or hint.
Please check your show () method, you are creating new Adapter every time with the new dataset. You have to append the new items to the adapter's list and adapter should be set to list once. Helpful tutorial can be found at here.

Not sure where to implements parcelable ArrayList after click item in RecyclerView

I wanna pass some of informations of the selected item to be viewed in new activity AboutApp.kt, but here I test by one info only (name). I do not have any trouble with RecyclerView, it works. I've seen many ways to do parcelable ArrayList object but feeling confuse where activity to be implemented, so it's getting error in MainActivity and AboutApp (destination intent).
A piece code MainActivity.kt getting error in showSelectedHerbal, when I use position to putExtra
class MainActivity : AppCompatActivity() {
private lateinit var rvHerbal: RecyclerView
private var list: ArrayList<Herbal> = arrayListOf()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
rvHerbal = findViewById(R.id.rv_herbal)
rvHerbal.setHasFixedSize(true)
list.addAll(HerbalData.listData)
showRecyclerList()
}
private fun showRecyclerList() {
rvHerbal.layoutManager = LinearLayoutManager(this)
val listHerbalAdapter = ListHerbalAdapter(list)
rvHerbal.adapter = listHerbalAdapter
listHerbalAdapter.setOnItemClickCallback(object : ListHerbalAdapter.OnItemClickCallback {
override fun onItemClicked(data: Herbal) {
showSelectedHerbal(data)
}
})
}
........
private fun showSelectedHerbal(data: Herbal) {
val moveIntent = Intent(this, AboutApp::class.java)
moveIntent.putExtra("Example_Item", list!![position])
this.startActivity(moveIntent)
}
.......
}
A piece code from AboutApp.kt that getting error in herbalName(). I know that I haven't implemented the parcelable so it's wrong
val intent = intent
val herbalData: HerbalData = intent.getParcelableExtra("Example_Item")
val title: String = herbalData.herbalName()
val itemName = findViewById<TextView>(R.id.item_name)
itemName.text = title
I'm so sorry, I attach you some of activities that I confuse may be one of them is the right place to be implement parcelable. Here is my data class Herbal.kt
data class Herbal(
var name: String = "",
var detail: String = "",
var photo: Int = 0
)
A piece code of the object HerbalData.kt
object HerbalData {
private val herbalName = arrayOf("Cengkeh",
"Ginseng",
"Jahe")
..........
val listData: ArrayList<Herbal>
get() {
val list = arrayListOf<Herbal>()
for (position in herbalName.indices) {
val herbal = Herbal()
herbal.name = herbalName[position]
herbal.detail = herbalDetail[position]
herbal.photo = herbalImage[position]
list.add(herbal)
}
return list
}
}
Help me please where activity to be write the parcelable ArrayList and how to fix it. Thanks in advance for any help.
First of all the error in your AboutApp.kt is because you have herbalName private in your HerbalData object. Remove the private modifier to access it there.
Just add #Parcelize annotation over your data class to automatically generate writeToParcel and createFromParcel methods for you!
#Parcelize
data class Herbal(...) : Parcelable
Add this in your build.gradle file:
androidExtensions {
features = ["parcelize"]
}
PS: Reference: https://medium.com/#BladeCoder/a-study-of-the-parcelize-feature-from-kotlin-android-extensions-59a5adcd5909
I recommend you read this.
You just have to make the Herbal class Parcelable.
data class Herbal(
var name: String = "",
var detail: String = "",
var photo: Int = 0
) : Parcelable {
companion object {
#JvmField
val CREATOR = object : Parcelable.Creator<Herbal> {
override fun createFromParcel(parcel: Parcel) = Herbal(parcel)
override fun newArray(size: Int) = arrayOfNulls<Herbal>(size)
}
}
private constructor(parcel: Parcel) : this(
name = parcel.readString(),
detail = parcel.readString(),
photo = parcel.readInt(),
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
parcel.writeString(detail)
parcel.writeInt(photo)
}
override fun describeContents() = 0
}

How to initialize Array<List<Model>> in Kotlin?

I have a JSON string which coming from rest API and I'm binding that into List<CategoryDO> object. I have all category/sub-category data into this list object List<CategoryDO> but I don't know how to separate sub-categories from those data into Array<List<CategoryDO>> format.
How can I add sub-category list into Array<List<CategoryDO>> object? How can I declare and initialize Array<List<CategoryDO>> in Kotlin?
All categories should be in List<CategoryDO> format and all sub-categories in Array<List<CategoryDO>> format.
For Example:
List<CategoryDO of Cat-1, CategoryDO of cat-2, ... etc>
Array<List<CategoryDO of SubCat-1 of Cat-1, CategoryDO of SubCat-2 of Cat-1>>, List<CategoryDO of SubCat-12 of Cat-2, CategoryDO of SubCat-22 of Cat-2>>, ...etc>>
CategoryDO data class:
data class CategoryDO( #SerializedName("Id")
#Expose
var id: Long? = null,
#SerializedName("Name")
#Expose
var name: String? = null,
#SerializedName("SubCategories")
#Expose
var subCategories: List<CategoryDO>? = null)
Actually, I need to pass this separate Category/Sub-Category things to CategoryAdapter class.
CategoryAdapter class sample:
class CategoryAdapter : BaseExpandableListAdapter {
private var groupItem: List<CategoryDO>
private var contentItem: Array<List<CategoryDO>>
private var context: Context
private var imageOnClickListener: View.OnClickListener
constructor(context: Context, groupItem: List<CategoryDO>, contentItem: Array<List<CategoryDO>>, imageOnClickListener: View.OnClickListener) {
this.groupItem = groupItem
this.contentItem = contentItem
this.context = context
this.imageOnClickListener = imageOnClickListener
}
.
.
.
}
If you need to convert a List<CategoryDO> to an Array<List<CategoryDO>> where the inner List is the subcategory list from each CategoryDO, you can map over the original list and convert the results to an array...
// Given
val categories: List<CategoryDO> = TODO()
val allSubCats: Array<List<CategoryDO>> =
categories.map { it. subCategories }.toTypedArray()
I try json data into recycler view adapter and it is working you can try if solved your problem..
class HeroAdapter(val item: MutableList<Hero>, val context: Context, val itemClick:OnRecyclerViewItemClickListener) : RecyclerView.Adapter<HeroAdapter.ItemViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ItemViewHolder {
val v = LayoutInflater.from(parent?.context).inflate(R.layout.adapter_layout, parent, false)
return ItemViewHolder(v)
}
var onClickListener: OnRecyclerViewItemClickListener? = null
open interface OnRecyclerViewItemClickListener {
fun click(hero: Hero)
}
override fun onBindViewHolder(holder: ItemViewHolder?, position: Int) {
var hero: Hero = item[position]
onClickListener=itemClick
holder?.mTvName?.text = hero.getName()
holder?.mTvBio?.text = hero.getBio()
holder?.mTvReal?.text = hero.getRealname()
holder?.mTvFirst?.text = hero.getFirstappearance()
holder?.mTvTeam?.text = hero.getTeam()
holder?.mTvPublisher?.text = hero.getPublisher()
holder?.mTvCreate?.text = hero.getCreatedby()
Glide.with(context)
.load(hero.getImageurl())
.into(holder?.mIvImage)
holder?.itemView?.setOnClickListener(View.OnClickListener {
this.onClickListener?.click(hero)
})
}
override fun getItemCount(): Int {
return item.size
}
class ItemViewHolder : RecyclerView.ViewHolder {
var mTvName: TextView? = null
var mTvReal: TextView? = null
var mTvCreate: TextView? = null
var mTvBio: TextView? = null
var mTvTeam: TextView? = null
var mTvPublisher: TextView? = null
var mTvFirst: TextView? = null
var mIvImage: ImageView? = null
constructor(itemView: View) : super(itemView) {
mTvName = itemView.findViewById(R.id.alTvName)
mTvReal = itemView.findViewById(R.id.alTvRealName)
mTvFirst = itemView.findViewById(R.id.alTvFirst)
mTvCreate = itemView.findViewById(R.id.alTvcreatedby)
mTvBio = itemView.findViewById(R.id.alTvBio)
mTvTeam = itemView.findViewById(R.id.alTvTeam)
mTvPublisher = itemView.findViewById(R.id.alTvpublisher)
mIvImage = itemView.findViewById(R.id.alIvUserImage)
}
}
}

Categories

Resources