RecyclerView add dynamically item. NotifyDataChanged doesn't work - android

In this app, i am adding addresses to account and saving them in Realtime database (firebase).I want also to display them in recyclerview but they aren't visible.
Here visualization of my problem : https://youtu.be/OdlZNUQnA-k
The Code should work like this
Addressfragment Contains AddressesRecyclerview
AddAddressfragment for adding new Address
And it goes back to AddressFragment when new Address has been added.
Also when i tried to display all items from one array like for example postcode .It display only last added item. Even on for each loop. Like last item is deleted after adding
I understand that it need something like notifyDataSetChanged() but it doesnt work here
Here is The code:
AddressFragment:
package com.querto.fragments.address
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.FirebaseDatabase
import com.querto.R
import com.querto.adapters.AddressAdapter
import com.querto.viewmodel.MainActivityViewModel
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.fragment_address.view.*
class AddressFragment : Fragment() {
private lateinit var mMainActivityViewModel: MainActivityViewModel
private lateinit var database: DatabaseReference
private lateinit var mAuth: FirebaseAuth
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
var view = inflater.inflate(R.layout.fragment_address, container, false)
database = FirebaseDatabase.getInstance().reference
mAuth = FirebaseAuth.getInstance()
mMainActivityViewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(requireActivity().application).create(
MainActivityViewModel::class.java)
if(mAuth.currentUser==null){
Toast.makeText(requireContext(), "To add address please login",Toast.LENGTH_SHORT).show()
activity?.nav_view?.setCheckedItem(R.id.login)
activity?.supportFragmentManager?.beginTransaction()?.setCustomAnimations(R.anim.fragment_slide_in_anim, R.anim.fragment_fade_out_anim, R.anim.fragment_slide_out_anim, R.anim.fragment_fade_in_anim)?.replace(R.id.fragment_container, mMainActivityViewModel.loginFragment)?.commit()
}
view.recyclerViewAddress.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
view.recyclerViewAddress.adapter = AddressAdapter(requireContext(), mMainActivityViewModel.list_of_addresses)
view.add_address_btn.setOnClickListener {
activity?.supportFragmentManager?.beginTransaction()?.setCustomAnimations(R.anim.fragment_slide_in_anim, R.anim.fragment_fade_out_anim, R.anim.fragment_slide_out_anim, R.anim.fragment_fade_in_anim)?.replace(R.id.fragment_container, mMainActivityViewModel.addAddressFragment)?.commit()
}
return view
}
}
Adapter:
package com.querto.adapters
import android.app.Application
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.FirebaseDatabase
import com.querto.R
import com.querto.model.Address
import com.querto.viewmodel.MainActivityViewModel
import kotlinx.android.synthetic.main.my_address_row.view.*
class AddressAdapter(contextAdapter: Context, addresses: ArrayList<Address>):
RecyclerView.Adapter<AddressAdapter.MyViewHolder>() {
private var mMainActivityViewModel: MainActivityViewModel
private val context: Context = contextAdapter
private val local_addreses : ArrayList<Address> = addresses
private var database: DatabaseReference
private var mAuth: FirebaseAuth
init {
mMainActivityViewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(context.applicationContext as Application).create(
MainActivityViewModel::class.java)
database = FirebaseDatabase.getInstance().reference
mAuth = FirebaseAuth.getInstance()
}
class MyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
val currentTitle = itemView.address_title
val currentId = itemView.address_id
val currentStreet = itemView.address_street
val currentPostcode = itemView.address_postcode
val currentHouseNumber = itemView.address_number
val currentAddressCityName = itemView.address_city
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(context).inflate(R.layout.my_address_row, parent, false))
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.currentTitle.text = local_addreses[position].name
holder.currentId.text = (position + 1).toString()
holder.currentStreet.text =local_addreses[position].street
holder.currentPostcode.text =local_addreses[position].postcode
holder.currentHouseNumber.text = local_addreses[position].house_number
holder.currentAddressCityName.text = local_addreses[position].city_name
}
override fun getItemCount(): Int {
return local_addreses.size
}
fun addAddress(address: Address){
mMainActivityViewModel.list_of_addresses.add(address)
notifyDataSetChanged()
}
}
AddAddress:
package com.querto.fragments.address
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.lifecycle.ViewModelProvider
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.FirebaseDatabase
import com.querto.R
import com.querto.adapters.AddressAdapter
import com.querto.model.Address
import com.querto.viewmodel.MainActivityViewModel
import kotlinx.android.synthetic.main.fragment_add_address.view.*
class AddAddressFragment : Fragment() {
private lateinit var database: DatabaseReference
private lateinit var mAuth: FirebaseAuth
private lateinit var mMainActivityViewModel: MainActivityViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
var view = inflater.inflate(R.layout.fragment_add_address, container, false)
mMainActivityViewModel =
ViewModelProvider.AndroidViewModelFactory.getInstance(activity?.application!!)
.create(MainActivityViewModel::class.java)
view.addAddressButton.setOnClickListener {
val addressName = view.addAddressName.text.toString()
val addressStreet = view.addAddressStreet.text.toString()
val addressNumber = view.addAddressHouseNumber.text.toString()
val addressZipCode = view.addAddressCityZipCode.text.toString()
val addressCityName = view.addAddressCityName.text.toString()
if(inputCheck(addressName,addressStreet,addressNumber,addressZipCode, addressCityName)){
mAuth = FirebaseAuth.getInstance()
database = FirebaseDatabase.getInstance().reference
addAddress(addressName, addressStreet, addressNumber, addressZipCode, addressCityName)
}else{
Toast.makeText(requireContext(), "Please enter all fields", Toast.LENGTH_SHORT).show()
}
}
return view
}
private fun addAddress(addressName: String, addressStreet: String, addressNumber: String,addressZipCode: String, addressCityName: String) {
val address = Address(mAuth.currentUser?.uid, addressName, addressStreet,addressZipCode, addressNumber, addressCityName)
database.child("addresses").child(database.push().key.toString()).setValue(address).addOnCompleteListener {
if(it.isSuccessful){
val addressAdapter= AddressAdapter(requireContext(), mMainActivityViewModel.list_of_addresses)
addressAdapter.addAddress(address)
activity?.supportFragmentManager?.beginTransaction()?.setCustomAnimations(R.anim.fragment_slide_in_anim, R.anim.fragment_fade_out_anim, R.anim.fragment_slide_out_anim, R.anim.fragment_fade_in_anim)?.replace(R.id.fragment_container, mMainActivityViewModel.addressFragment)?.commit()
Toast.makeText(requireContext(), "Added address", Toast.LENGTH_SHORT).show()
}else{
Toast.makeText(requireContext(), "Fail at creating address", Toast.LENGTH_SHORT).show()
}
}
}
private fun inputCheck(addressName: String, addressStreet: String, addressNumber: String,addressZipCode: String, adressCityName: String)=
addressName.isNotEmpty() && addressStreet.isNotEmpty() && addressNumber.isNotEmpty() && addressZipCode.isNotEmpty() && adressCityName.isNotEmpty() && addressZipCode.length==5
}
MainActivityViewModel:
class MainActivityViewModel(application: Application) : AndroidViewModel(application) {
private lateinit var database: DatabaseReference
private lateinit var mAuth: FirebaseAuth
val homeFragment = HomeFragment()
val loginFragment = LoginFragment()
val registerFragment = RegisterFragment()
val detailsFragment = DetailsFragment()
val addressFragment = AddressFragment()
val addAddressFragment = AddAddressFragment()
var pizza_names: Array<String> = application.resources.getStringArray(R.array.pizza_titles)
var pizza_desc: Array<String> = application.resources.getStringArray(R.array.pizza_desc)
val pizza_small_price: IntArray = application.resources.getIntArray(R.array.pizza_small_price)
val pizza_medium_price: IntArray = application.resources.getIntArray(R.array.pizza_medium_price)
val pizza_big_price: IntArray = application.resources.getIntArray(R.array.pizza_big_price)
var pizza_img: Array<Int> = arrayOf(R.drawable.napoletana, R.drawable.margherita, R.drawable.estate, R.drawable.pepperone, R.drawable.pancetta, R.drawable.ortolana, R.drawable.marinara, R.drawable.diavola, R.drawable.messicana, R.drawable.quattro_formaggi, R.drawable.sugoza, R.drawable.semola, R.drawable.capriciossa, R.drawable.vulcano, R.drawable.romana, R.drawable.capodanno, R.drawable.primavera, R.drawable.regina, R.drawable.quattro_stagioni, R.drawable.cilento, R.drawable.tirolese, R.drawable.michele, R.drawable.pollo, R.drawable.havana, R.drawable.siciliana, R.drawable.sandra, R.drawable.bari, R.drawable.gringo, R.drawable.angelo, R.drawable.spinaci)
var focaccia_names: Array<String> = application.resources.getStringArray(R.array.foaccia_titles)
var focaccia_desc: Array<String> = application.resources.getStringArray(R.array.foaccia_desc)
val focaccia_price: IntArray = application.resources.getIntArray(R.array.foaccia_price)
var focaccia_img: Array<Int> = arrayOf(R.drawable.base, R.drawable.nutella)
var calzone_names: Array<String> = application.resources.getStringArray(R.array.calzone_titles)
var calzone_desc: Array<String> = application.resources.getStringArray(R.array.calzone_desc)
val calzone_price_normal: IntArray = application.resources.getIntArray(R.array.calzone_normal_price)
val calzone_price_big: IntArray = application.resources.getIntArray(R.array.calzone_big_price)
var calzone_img: Array<Int> = arrayOf(R.drawable.calzone)
var panuozzo_names: Array<String> = application.resources.getStringArray(R.array.panuozzo_titles)
var panuozzo_desc: Array<String> = application.resources.getStringArray(R.array.panuozzo_desc)
val panuozzo_price_normal: IntArray = application.resources.getIntArray(R.array.panuozzo_normal_price)
val panuozzo_price_big: IntArray = application.resources.getIntArray(R.array.panuozzo_big_price)
var panuozzo_img: Array<Int> = arrayOf(R.drawable.panuozzo)
val sosy_names: Array<String> = application.resources.getStringArray(R.array.sosy_titles)
val sosy_price: IntArray = application.resources.getIntArray(R.array.sosy_price)
val napoje_names: Array<String> = application.resources.getStringArray(R.array.napoje_titles)
val napoje_price: IntArray = application.resources.getIntArray(R.array.napoje_price)
val napoje_first_kind: Array<String> = application.resources.getStringArray(R.array.napoje_kinds_one)
val napoje_second_kind: Array<String> = application.resources.getStringArray(R.array.napoje_kinds_two)
val dodatki_names: Array<String> = application.resources.getStringArray(R.array.dodatki_titles)
val dodatki_small_price: IntArray = application.resources.getIntArray(R.array.dodatki_small_price)
val dodatki_medium_price: IntArray = application.resources.getIntArray(R.array.dodatki_medium_price)
val dodatki_big_price: IntArray = application.resources.getIntArray(R.array.dodatki_big_price)
var list_of_addresses = ArrayList<Address>()
private val mutableLoginStatus = MutableLiveData<Boolean>()
val loginStatus: LiveData<Boolean>
get() = mutableLoginStatus
fun checkLogin(username: String, password: String) {
viewModelScope.launch(Dispatchers.IO) {
database = FirebaseDatabase.getInstance().reference
mAuth = FirebaseAuth.getInstance()
mAuth.signInWithEmailAndPassword(username,password).addOnCompleteListener{
if(it.isSuccessful){
mutableLoginStatus.postValue(true)
}else{
mutableLoginStatus.postValue(false)
}
}
}
}
fun shareApp(context: Context) {
val openURL = Intent(android.content.Intent.ACTION_VIEW)
openURL.data = Uri.parse("https://www.facebook.com/1488596184507308/")
context.startActivity(openURL)
}
fun sendMail(context: Context) {
val sendEmail = Intent(Intent.ACTION_SEND)
val email: Array<String> = arrayOf("kontakt#cilento.pl")
sendEmail.setData(Uri.parse("mailto: kontakt#cilento.pl "))
sendEmail.putExtra(Intent.EXTRA_SUBJECT, "Problem z Usługą")
sendEmail.putExtra(Intent.EXTRA_TEXT, "Pizza którą zamówiłem nie przyszła na czas.\n\n\nMoje Dane Kontaktowe: \n\nImie: \nNazwisko: \nAdres: ")
sendEmail.setType("message/rfc822")
sendEmail.putExtra(Intent.EXTRA_EMAIL, email)
val chooser = Intent.createChooser(sendEmail, "Send mail using")
context.startActivity(chooser)
}
}
Address Class:
package com.querto.model
data class Address(
val userId: String?,
val name: String?,
val street: String?,
val postcode: String?,
val house_number: String?,
val city_name: String?
)

After Checking The MainActivityViewModel ,I See that you are not fetching data from the firebase database.
You should add this to AddressFragment class
also Add Variable called addressAdapter in the top of the class
fun getAddresses(){
val ref = FirebaseDatabase.getInstance().reference.child("addresses")
ref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (dataSnapshot.exists()) {
val address = dataSnapshot.getValue<Address>()
mMainActivityViewModel.addresses_list.add(address)
addressAdapter.notifyDataChanged()
}
}
override fun onCancelled(databaseError: DatabaseError) {
}
})
}
Also Implementing Address adapter here does not do a thing . just remove it.
private fun addAddress(addressName: String, addressStreet: String, addressNumber: String,addressZipCode: String, addressCityName: String) {
val address = Address(mAuth.currentUser?.uid, addressName, addressStreet,addressZipCode, addressNumber, addressCityName)
database.child("addresses").child(database.push().key.toString()).setValue(address).addOnCompleteListener {
if(it.isSuccessful){
val addressAdapter= AddressAdapter(requireContext(), mMainActivityViewModel.address_title, mMainActivityViewModel.address_street,mMainActivityViewModel.address_post_code, mMainActivityViewModel.address_house_number, mMainActivityViewModel.address_city_name)
addressAdapter.addAddress(addressName, addressStreet,addressZipCode, addressNumber, addressCityName)
activity?.supportFragmentManager?.beginTransaction()?.setCustomAnimations(R.anim.fragment_slide_in_anim, R.anim.fragment_fade_out_anim, R.anim.fragment_slide_out_anim, R.anim.fragment_fade_in_anim)?.replace(R.id.fragment_container, mMainActivityViewModel.addressFragment)?.commit()
Toast.makeText(requireContext(), "Added address", Toast.LENGTH_SHORT).show()
}else{
Toast.makeText(requireContext(), "Fail at creating address", Toast.LENGTH_SHORT).show()
}
}

I will try to explain it here.
When you create a custom RecyclerView adapter usually you suppose to pass data you want to be displayed in the list. For me it is better to pass array Of Class You Made To Pass Data For Single Recylcer View itemArrayList<ClassOfSingleItem>, but it is not nessesary of course.
So when you call notifyDataSetCahnged you notify your adapter that data in this ArrayList was changed. But this call will not work if you create new Adapter every time you add or remove something from the RecyclerView list.
EDIT:
Let me explain what i see: you have button with click listener, when you click it you replace current fragmen with the one where you add data.
view.add_address_btn.setOnClickListener {
activity?.supportFragmentManager?.beginTransaction()?.setCustomAnimations(R.anim.fragment_slide_in_anim, R.anim.fragment_fade_out_anim, R.anim.fragment_slide_out_anim, R.anim.fragment_fade_in_anim)?.replace(R.id.fragment_container, mMainActivityViewModel.addAddressFragment)?.commit()
}
then, when you complete editing all fields what you do? replace your addAdressFragment with addressFragment:
val addressAdapter= AddressAdapter(requireContext(), mMainActivityViewModel.list_of_addresses)
addressAdapter.addAddress(address)
activity?.supportFragmentManager?.beginTransaction()?.setCustomAnimations(R.anim.fragment_slide_in_anim, R.anim.fragment_fade_out_anim, R.anim.fragment_slide_out_anim, R.anim.fragment_fade_in_anim)?.replace(R.id.fragment_container, mMainActivityViewModel.addressFragment)?.commit()
inside this method you CREATE new AdressAdapter to call method addAdrees which has notifyDataSetChanged call inside. But recyclerView in your addressFragment has no idea about this new AddressAdapter. This is the main problem. As i mentioned in comment below my answer there are only two ways to update RecyclerView so implement one of them.
Below I show some java code (you mentioned you know java) which can give you an idea:
public class PointActivity extends BaseActivity
implements SearchView.OnQueryTextListener{
private RecyclerView mRecyclerView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_point);
mRecyclerView = findViewById(R.id.point_list);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
List<PointItem> pointItems = getFilteredAndSortedList();
mRecyclerView.setAdapter(new PointAdapter(this, pointItems));
}
//here we need to update recyclerView
#Override
public boolean onQueryTextSubmit(String query) {
searchResult(query);
return false;
}
public void searchResult(String query) {
if (query.isEmpty()) {
//just full list if query is empty
mRecyclerView.setAdapter(new PointAdapter(this, getFilteredAndSortedList()));
} else {
PointSearchManager pointSearchManager = new PointSearchManager();
List<PointItem> list;
list = Arrays.asList(pointSearchManager.toFilters(getFilteredAndSortedList().toArray(new PointItem[0]), query));
//list filtered with query result
mRecyclerView.setAdapter(new PointAdapter(this, list));
}
}

Related

Process: com.example.whatsappclone java.lang.IllegalArgumentException

i am getting this error
java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkNotNullParameter, parameter it
i don't know which variable is null i have used everything
need help , i am a beginner in android development , pls don't judge me
i know it's a simple mistake but unable to find it
Following is the entire code.
enter image description here
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.whatsappclone.Adapters.ChatAdapter
import com.example.whatsappclone.Models.MessageModel
import com.example.whatsappclone.databinding.ActivityChatDetailBinding
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import com.squareup.picasso.Picasso
import java.util.*
import kotlin.collections.ArrayList
class ChatDetailActivity : AppCompatActivity() {
private lateinit var binding: ActivityChatDetailBinding//view binding
private lateinit var mDbRef: DatabaseReference
private lateinit var auth: FirebaseAuth
private lateinit var messageList: ArrayList<MessageModel>
private lateinit var chatAdapter: ChatAdapter
private var senderRoom: String? = null
private var receiverRoom: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
//view binding
super.onCreate(savedInstanceState)
binding = ActivityChatDetailBinding.inflate(layoutInflater)
setContentView(binding.root)
//removing action bar
supportActionBar?.hide()
//getting instance of auth
auth = FirebaseAuth.getInstance()
//getting database reference
mDbRef = FirebaseDatabase.getInstance().reference
messageList = ArrayList()
val senderId = auth.currentUser?.uid//sender Id
val receiverId = intent.getStringExtra("userId")//receiver Id
senderRoom = senderId + receiverId
receiverRoom = receiverId + senderId
//getting intent extra
val userName = intent.getStringExtra("userName")
val profilePic = intent.getStringExtra("profilePic")
//putting intent extra values in views
binding.username.text = userName
if (!profilePic.equals("")) {
Picasso.get().load(profilePic).placeholder(R.drawable.defaultprofile)
.into(binding.IVProfileImage)
}
//on click listener on back button
binding.btnBack.setOnClickListener {
val intent = Intent(this#ChatDetailActivity, MainActivity::class.java)
startActivity(intent)
this.finish()
}
//chat recycler view adapter
chatAdapter = ChatAdapter(messageList, this)
binding.chatRecyclerView.adapter = chatAdapter
binding.chatRecyclerView.layoutManager = LinearLayoutManager(this)
mDbRef.child("chats")
.child(senderRoom!!).addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
messageList.clear()
for (postSnapshot in snapshot.children) {
val model = postSnapshot.getValue(MessageModel::class.java)
messageList.add(model!!)
}
chatAdapter.notifyDataSetChanged()
}
override fun onCancelled(error: DatabaseError) {
}
})
//on click on send button
binding.send.setOnClickListener {
// Toast.makeText(this, "sid:- " + senderId.toString(), Toast.LENGTH_SHORT).show()
// Toast.makeText(this, "rid:- " + receiverId.toString(), Toast.LENGTH_SHORT).show()
val message = binding.etMessage.text.toString()
val model = MessageModel(senderId!!, message)
// Toast.makeText(this, "mess- ${messageList.size}", Toast.LENGTH_SHORT).show()
// Toast.makeText(this, "id- ${senderId}", Toast.LENGTH_SHORT).show()
model.timeStamp = Date().time
binding.etMessage.setText("")
mDbRef.child("chats").child(senderRoom!!).push()
.setValue(model).addOnSuccessListener {
mDbRef.child("chats").child(receiverRoom!!).push()
.setValue(model)
}
}
}
}

(KOTLIN) Expanding and Collapsing in Expandable recyclerview

Objective
I want to expand new items in a RecyclerView at the same time, and the old selected items will be automatically collapsed.
What I done, it can be like this >>
The items expand and collapse on click but do not automatically collapse if another item is expanded
image1
Actually, what I want to make it like this >>
Any expanded item should be automatically collapse when another item is expanded.
image2
What I had researched
From this stack overflow had done what I want, but I don't how to convert into Kotlin, basically as I know it store the previous position then compare to the current position, through the If-Else Statement to determine and perform the action.
There are one more stack overflow, it also from java, slightly understand, briefly know the whole concept, but cannot go deeply explain for myself line-by-line.
This Github Sample is pretty matched my needs, but code styling quite complicated, and not fexible enough for me to add other feature and design.
Question
Why the previousPosition need to be -1?
How should separate currentPosition and previousPosition, and store the previousPosition to different object and value?
If the previousPosition is workable, how should I implement into my project?
If available, can share any related resources to me?
 like: screen shot the part of sample code, or other resources
Code
product_list_item.kt
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley
import com.google.android.material.floatingactionbutton.FloatingActionButton
import org.json.JSONArray
import org.json.JSONObject
class ViewPartActivity : AppCompatActivity() {
private lateinit var newRecylerview : RecyclerView
private lateinit var newArrayList : ArrayList<Product>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_view_part)
val btnInsertView: FloatingActionButton = findViewById(R.id.btnInsertView)
btnInsertView.setOnClickListener {
val insertViewIntent = Intent(this, AddPartActivity::class.java)
startActivity(insertViewIntent)
}
getData()
}
private fun getData() {
val url = "WEBAPI"
val requestQueue: RequestQueue = Volley.newRequestQueue(this)
val jsonObjectRequest: JsonObjectRequest = JsonObjectRequest(Request.Method.GET, url, null,
{ response ->
val jsonArray: JSONArray = response.getJSONArray("tbl_product")
val namelist = ArrayList<String>()
val categorylist = ArrayList<String>()
val quantitylist = ArrayList<String>()
val pricelist = ArrayList<String>()
for (x in 0 until jsonArray.length()) {
val jsonObject: JSONObject = jsonArray.getJSONObject(x)
val name: String = jsonObject.getString("NAME")
val category: String = jsonObject.getString("CATOGORYID")
val quantity: String = jsonObject.getString("QUANTITY")
val price: String = jsonObject.getString("PRICE")
namelist.add(name)
categorylist.add(category)
quantitylist.add(quantity)
pricelist.add(price)
}
newRecylerview =findViewById(R.id.recyclerView)
newRecylerview.layoutManager = LinearLayoutManager(this)
newRecylerview.setHasFixedSize(true)
newArrayList = arrayListOf<Product>()
for(i in namelist.indices){
val product = Product(namelist[i],categorylist[i],quantitylist[i],pricelist[i])
newArrayList.add(product)
}
val adapter = ProductAdapter(newArrayList)
newRecylerview.adapter = adapter
}, { error ->
Toast.makeText(this, error.message, Toast.LENGTH_LONG).show()
})
requestQueue.add(jsonObjectRequest)
}
}
ProductAdapter.kt
class ProductAdapter(private val productList : ArrayList<Product>) : RecyclerView.Adapter<ProductAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.product_list_item, parent,false)
return MyViewHolder(itemView)
}
#SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = productList[position]
holder.tvProductName.text = currentItem.name
holder.tvProductCategory.text= currentItem.category
holder.tvProductQuantity.text=currentItem.quantity
holder.tvProductPrice.text= "RM "+currentItem.price
val isVisible : Boolean = currentItem.visibility
holder.constraintLayout.visibility = if (isVisible) View.VISIBLE else View.GONE
holder.tvProductName.setOnClickListener{
currentItem.visibility =!currentItem.visibility
notifyItemChanged(position)
}
}
override fun getItemCount(): Int {
return productList.size
}
class MyViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
val tvProductName: TextView = itemView.findViewById(R.id.productName)
val tvProductCategory : TextView = itemView.findViewById(R.id.productCategory)
val tvProductQuantity : TextView = itemView.findViewById(R.id.productQuantity)
val tvProductPrice : TextView = itemView.findViewById(R.id.productPrice)
val constraintLayout : ConstraintLayout = itemView.findViewById(R.id.expandedLayout)
}
}
Product.kt
data class Product(
var name: String, var category: String, var quantity: String, var price: String, var visibility: Boolean = false
)
Promise
Once I get the solution, I would try my best to explain the code more deeply and update at here.

Recycler view data not loading on screen

I'm trying to show the recycler view's data on my app. The thing is, even though the NetworkStatus is successful (I can tell because I don't get the toast's message and the loader disappears and I can also see the data in the logcat), the info is not displayed. I am not sure if the error is in the way I'm calling the recycler view on my MainActivity or in the RecyclerAdapter but any idea as to where the problem is would be very helpful.
This is the RecyclerAdapter:
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.app.mortyapp.databinding.ItemDetailBinding
class RecyclerAdapter(private var characterList: List<Character>): RecyclerView.Adapter<RecyclerAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerAdapter.ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = ItemDetailBinding.inflate(
layoutInflater,
parent,
false
)
return ViewHolder(binding)
}
override fun getItemCount(): Int = characterList.size
override fun onBindViewHolder(holder: RecyclerAdapter.ViewHolder, position: Int) {
holder.bind(characterList[position])
}
fun setCharacterList(characterList: List<Character>){
this.characterList = characterList
notifyDataSetChanged()
}
inner class ViewHolder(
private val binding: ItemDetailBinding
) : RecyclerView.ViewHolder(binding.root){
fun bind(character: Character) {
with(binding){
val itemName: TextView = binding.tvName
val itemGender: TextView = binding.tvGender
itemName.text = character.name
itemGender.text = character.gender
}
}
}
}
This is the MainActivity:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.ProgressBar
import android.widget.Toast
import androidx.activity.viewModels
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import com.app.mortyapp.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val characters = mutableListOf<Character>()
private lateinit var progressBar: ProgressBar
private lateinit var recyclerAdapter: RecyclerAdapter
private val viewModel: MainViewModel by viewModels(
factoryProducer = {MainViewModelFactory()}
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
progressBar = binding.ProgressBar
progressBar.visibility = View.INVISIBLE
setObservers()
initRecyclerView()
}
private fun initRecyclerView() {
with(binding.rvCharacters){
layoutManager = LinearLayoutManager(context)
recyclerAdapter = RecyclerAdapter(characters).apply {
setCharacterList(characters)
}
}
}
private fun setObservers(){
viewModel.characterList.observe(this, Observer {
when(it.status){
NetworkStatus.LOADING ->{
//show loading state
progressBar.visibility = View.VISIBLE
}
NetworkStatus.SUCCESS -> {
//hide loading state
progressBar.visibility = View.INVISIBLE
//render character list
recyclerAdapter.setCharacterList(characters)
}
NetworkStatus.ERROR -> {
//show error message
Toast.makeText(this,"Error loading content", Toast.LENGTH_SHORT).show()
//hide loading state
progressBar.visibility = View.INVISIBLE
}
}
})
}
}
API response:
import com.google.gson.annotations.SerializedName
data class Character (
#SerializedName("id") val id: Int,
#SerializedName("name") val name: String,
#SerializedName("gender") val gender: String
)
data class CharacterListResponse(
#SerializedName("results") val results: List<Character>
)
Remote data source:
package com.app.mortyapp
import com.app.mortyapp.Model.CharacterService
import com.app.mortyapp.Model.RetrofitServices
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class CharacterRemoteDataSource {
fun getCharacterList(networkResponse: NetworkResponse<List<Character>>) {
val service = RetrofitServices.instance
.create(CharacterService::class.java)
.getCharacterList()
service.enqueue(object : Callback<CharacterListResponse> {
override fun onResponse(
call: Call<CharacterListResponse>,
response: Response<CharacterListResponse>
) {
val resource = response.body()?.run {
if (results.isNotEmpty())
Resource(NetworkStatus.SUCCESS, results)
else
Resource(NetworkStatus.ERROR)
} ?: run {
Resource(NetworkStatus.ERROR)
}
networkResponse.onResponse(resource)
}
override fun onFailure(call: Call<CharacterListResponse>, t: Throwable) {
networkResponse.onResponse(Resource(NetworkStatus.ERROR, message = t.message))
}
})
}
}
interface NetworkResponse<T> {
fun onResponse(value: Resource<T>)
}
Set adapter for Recyclerview in
setupRecylerview ()
adapter = recyclerAdapter
NetworkStatus.SUCCESS -> {
//hide loading state
progressBar.visibility = View.INVISIBLE
//render character list
recyclerAdapter.setCharacterList(characters)
recyclerAdapter.notifydatasetchanged()//add this line
}
I think most problems found with recyclerView isn't linked to it, but with some adjourning codes. For example, a very similar problem was solved by finding out that the adapter POJO class was retrieving 0 rather than the actual size of the array list.
See the solved problem here:
Android Recycler View not loading Data (Peculiar problem, Not a Duplicate)

intent.putExtra: None of the following functions can be called with the arguments supplied

I'm trying to pass data from one activity to another through an intent with putExtra. The thing is, I get the error that says: None of the following functions can be called with the arguments supplied.
I'm not sure why it's not working, since the variable that I'm referencing is in the viewholder. Any clue as to what's going on and how to fix it would help a lot.
This is my recycler adapter:
package com.example.newsapp
import android.content.Intent
import android.icu.text.CaseMap
import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.RecyclerView
import com.example.newsapp.databinding.NewsItemBinding
import com.squareup.picasso.Picasso
class RecyclerAdapter (
private var Titles: List<String>,
private var Images: List<String>,
private var Authors: List<String>,
private var Descriptions: List<String>
) : RecyclerView.Adapter<RecyclerAdapter.ViewHolder>(){
inner class ViewHolder(
view: View
): RecyclerView.ViewHolder(view){
private val binding = NewsItemBinding.bind(view)
val itemTitle: TextView = binding.tvTitle
val itemImage: ImageView = binding.ivNewsImage
fun bind(urlToImage:String){
Picasso.get().load(urlToImage).into(binding.ivNewsImage)
}
init {
itemImage.setOnClickListener{
val intent = Intent(view.context, PostActivity::class.java)
intent.putExtra("title",itemTitle)
view.context.startActivity(intent)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.news_item, parent, false)
return ViewHolder(v)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemTitle.text = Titles[position]
val itemImage = Images[position]
holder.bind(itemImage)
}
override fun getItemCount(): Int {
return Titles.size
}
}
The part with the issue is this one:
init {
itemImage.setOnClickListener{
val intent = Intent(view.context, PostActivity::class.java)
intent.putExtra("title",itemTitle) view.context.startActivity(intent)
}
}
This is my main activity:
package com.example.newsapp
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.newsapp.databinding.ActivityMainBinding
import kotlinx.coroutines.*
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.lang.Exception
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var adapter: RecyclerAdapter
private val newsTitles = mutableListOf<String>()
private val newsImages = mutableListOf<String>()
private val newsAuthors = mutableListOf<String>()
private val newsDescriptions = mutableListOf<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
makeAPIRequest()
}
private fun initRecyclerView() {
adapter = RecyclerAdapter( newsTitles, newsImages)
binding.rvNews.layoutManager = LinearLayoutManager(this)
binding.rvNews.adapter = adapter
}
private fun addToList(title:String, image:String, author:String, description:String){
newsTitles.add(title)
newsImages.add(image)
newsAuthors.add(author)
newsDescriptions.add(description)
}
private fun makeAPIRequest() {
val api = Retrofit.Builder()
.baseUrl("https://newsapi.org/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(APIService::class.java)
GlobalScope.launch(Dispatchers.IO){
val response = api.getNews()
val posts = response.body()
try{
if (posts != null) {
for(art in posts.Articles){
Log.i("Main Activity", "Result = $art")
addToList(art.Title,art.urlToImage, art.Author, art.Description)
}
}
withContext(Dispatchers.Main){
initRecyclerView()
}
} catch (e:Exception){
Log.e("Main Activity", e.toString())
}
}
}
}
intent.putExtra("title",itemTitle)
Here, itemTitle is a TextView. You cannot pass a TextView between activities. You could switch to:
intent.putExtra("title",itemTitle.text)
...to put the text from the TextView into the extra.
Also, you might want to consider whether these should be separate activities or just two fragments (or composables) in a single activity.

I am making a project where User API call and fetch the data and display in recycler view

This is the code in which api is call and fetch the data and display in recyler view data and data1 are the deatils of api data but when I am launching the app it is showing blank screen. I want to make a network call using Retrofit, and fetch the list. (URL to fetch the user list https://reqres.in/api/users?page=2)
and then In a RecyclerView in the user list will be shown
Please help and tell what is wrong in the code.
User Adapter
package com.example.userlisttest.Adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.example.userlisttest.Model.Data
import com.example.userlisttest.R
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.item_view.view.*
class UserAdapter(private val context: Context): RecyclerView.Adapter<UserAdapter.MyViewHolder>() {
private val dataList = ArrayList<Data>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
var itemView = LayoutInflater.from(context).inflate(R.layout.item_view, parent, false)
return MyViewHolder(itemView)
}
override fun getItemCount(): Int {
return dataList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
// holder.image = dataList.get(position)
Picasso.get().load(dataList[position].avatar)
val data = dataList[position]
val userfullname = holder.itemView.full_name
val image = holder.itemView.avatar
val fullname = "$(data.firstname) $(data.lastname)"
userfullname.text = (fullname as TextView).toString()
Picasso.get().load(data.avatar).into(image)
holder.itemView.setOnClickListener() {
Toast.makeText(context, fullname, Toast.LENGTH_SHORT).show()
}
}
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var image: ImageView? = null
var text: TextView? = null
init {
image = itemView.findViewById(R.id.avatar)
text = itemView.findViewById(R.id.full_name)
}
}
}
Retrofit
package com.example.userlisttest.Retrofit.RetrofitClass
import com.example.userlisttest.Model.Data1
import com.google.gson.GsonBuilder
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object RetrofitClient{
private val BASE_URL = "https://reqres.in/api/users?page=2"
private var retrofit:Retrofit?=null
fun getApiClient(baseUrl:String): Retrofit {
val gson = GsonBuilder()
.setLenient()
.create()
if (retrofit == null) {
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
}
return retrofit!!
}
}
Interface
package com.example.userlisttest.Retrofit.RetrofitClass
import com.example.userlisttest.Model.Data
import com.example.userlisttest.Model.Data1
import retrofit2.http.GET
interface RetrofitService {
#GET("users")
fun getUserList(): List<Data>
fun UserList(): List<Data1>
}
Data
package com.example.userlisttest.Model
import com.google.gson.annotations.SerializedName
data class Data1 (
#SerializedName("data")
val data: List<Data>? = null,
#SerializedName("page")
val page:Int = 0,
#SerializedName("perpage")
val perpage:Int = 0,
#SerializedName("total")
val total:Int = 0,
#SerializedName("totalpage")
val totalPage:Int = 0
)
Data
package com.example.userlisttest.Model
import com.google.gson.annotations.SerializedName
data class Data (
#SerializedName("id")
val id:Int,
#SerializedName("email")
val email:String,
#SerializedName("firstname")
val firstname : String,
#SerializedName("lastname")
val lastname: String,
#SerializedName("avatar")
val avatar: String,
)
MainActivity
class MainActivity : AppCompatActivity() {
private val dataList = ArrayList<Data>()
// private lateinit var adapter: UserAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
val adapter = UserAdapter(this)
val recyclerView: RecyclerView = findViewById(R.id.userList)
// adapter = UserAdapter(context)
val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
recyclerView.adapter = adapter
}
}
you should call the users api and then pass the data to the adapter
You are not making the request to fetch the data from the source (https://reqres.in/api/users?page=2).
You need to fetch the data using retrofit and pass it to the UserAdapter otherwise the arrayList used in the Adapter will be always empty.

Categories

Resources