Kotlin retrofit recyclerview intent to new activity - kotlin

so, i have a little problem here. in my Main Activity (CovidActivity) i want to show only "key" on my Adapter and then in my Second Activity (DetailCovidActivity) i want to show "kasus","sembuh","meninggal",and "dirawat". how to do that?
this is my CovidActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityCovidBinding.inflate(layoutInflater)
setContentView(binding.root)
adapterCovid = CovidAdapter(
listener = object: CovidAdapter.EventListener{
override fun onClick(itemList: CovidProvinceResponse.ListData) {
startActivity(
Intent(this#CovidActivity, DetailCovidActivity::class.java)
.putExtra("key",itemList.key)
.putExtra("kasus",itemList.jumlahKasus)
.putExtra("sembuh",itemList.jumlahSembuh)
.putExtra("meninggal",itemList.jumlahMeninggal)
.putExtra("dirawat",itemList.jumlahDirawat)
)
}
},listCovid = emptyList()
)
binding.rvShowCovid.adapter = adapterCovid
bindViewModel()
viewModel.getCovidProvince()
}
this is the onBindViewHolder in my Adapter
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val itemList = listCovid[position]
holder.binding.tvDaerah.text = itemList.key
holder.binding.tvJumlahKasus.text = itemList.jumlahKasus.toString()
holder.binding.tvJumlahSembuh.text = itemList.jumlahSembuh.toString()
holder.binding.tvJumlahMeninggal.text = itemList.jumlahMeninggal.toString()
holder.binding.tvJumlahDirawat.text = itemList.jumlahDirawat.toString()
holder.itemView.setOnClickListener {
listener.onClick(itemList)
}
}
and then this is the Second Activity (DetailCovidActivity)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDetailCovidBinding.inflate(layoutInflater)
setContentView(binding.root)
val province = intent.getStringExtra("key")
val kasus = intent.getIntExtra("kasus",0)
val sembuh = intent.getIntExtra("sembuh",0)
val meninggal = intent.getIntExtra("meninggal",0)
val dirawat = intent.getIntExtra("dirawat",0)
binding.tvDetailDaerah.text = province
binding.tvDetailKasus.text = kasus.toString()
binding.tvDetailSembuh.text = sembuh.toString()
binding.tvDetailMeninggal.text = meninggal.toString()
binding.tvDetailDirawat.text = dirawat.toString()
}

Related

E/RecyclerView: No adapter attached; skipping layout while getting the data from Google Spreadsheet

I am trying to get the data from the Google Spreadsheet and display it in a recyclerView in Kotlin. But I am getting the error as in the title.
I know there are many questions about the error 'E/RecyclerView: No adapter attached'. I spent hours going through all the posts and made changes to my code. But I couldn't fix the issue as I am not an expert coder.
Following is SalesData.kt
class SalesData : AppCompatActivity() {
private lateinit var binding: ActivitySalesDataBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySalesDataBinding.inflate(layoutInflater)
setContentView(binding.root)
val salesList = arrayListOf<SalesDataModel>()
binding.rvSalesData.layoutManager = LinearLayoutManager(applicationContext)
binding.rvSalesData.setHasFixedSize(true)
val adapter = SalesDataRecyclerAdapter(applicationContext,salesList)
binding.rvSalesData.adapter = adapter
val queue = Volley.newRequestQueue(this)
val url = "https://script.google.com/macros/s/fssfsdffdfhfhPPEWVM2FeIH3gZY5kAnb6JVeWpg2Xedfgt443534tdfg43t/exec"
val jsonObjectRequest = object: JsonObjectRequest(Request.Method.GET,url,null,Response.Listener {
val data = it.getJSONArray("items")
for(i in 0 until data.length()){
val salesJasonObject = data.getJSONObject(i)
val salesObject = SalesDataModel(
salesJasonObject.getString("Date"),
salesJasonObject.getString("Branch"),
salesJasonObject.getDouble("NetSale"),
salesJasonObject.getDouble("Profit"),
)
salesList.add(salesObject)
adapter.notifyDataSetChanged()
}
},Response.ErrorListener { }
){
override fun getHeaders(): MutableMap<String, String> {
return super.getHeaders()
}
}
}
}
and this is the adapter class SalesDataRecyclerAdapter.kt
class SalesDataRecyclerAdapter(val context: Context, private val saleDataList:ArrayList<SalesDataModel>)
:RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return MyViewHolder(
SalesDataLayoutBinding.inflate(
LayoutInflater.from(
parent.context
), parent, false
)
)
}
override fun getItemCount(): Int {
return saleDataList.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val model = saleDataList[position]
if (holder is MyViewHolder){
holder.binding.tvSales.text = model.salesAmount.toString()
holder.binding.tvBranch.text = model.branch
holder.binding.tvDate.text = model.date
holder.binding.tvProfit.text = model.profit.toString()
}
}
private class MyViewHolder(val binding: SalesDataLayoutBinding) : RecyclerView.ViewHolder(binding.root)
}

Update firestore data from populated recycler View

I want to update firestore data which I have got in a Recycler view.
Recycler View Activity Code
class AdminActivity : AppCompatActivity() {
private val dB = Firebase.firestore
private lateinit var userRecyclerView: RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.title = "Admin Panel"
userRecyclerView = findViewById(R.id.user_list)
userRecyclerView.layoutManager = LinearLayoutManager(this)
userRecyclerView.setHasFixedSize(true)
val query = dB.collection("users")
val options = FirestoreRecyclerOptions.Builder<User>().setQuery(query, User::class.java)
.setLifecycleOwner(this).build()
//adapter
val adapter = object : FirestoreRecyclerAdapter<User, UserViewHolder>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val view = LayoutInflater.from(this#AdminActivity)
.inflate(R.layout.user_item, parent, false)
return UserViewHolder(view)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int, model: User) {
val nameTv: TextView = holder.itemView.findViewById(R.id.name_textview)
val idTv: TextView = holder.itemView.findViewById(R.id.id_textview)
val phoneTv: TextView = holder.itemView.findViewById(R.id.phone_textview)
nameTv.text = model.name
idTv.text = model.id
phoneTv.text = model.phone
holder.itemView.setOnClickListener {
val intent = Intent(baseContext, AdminViewActivity::class.java)
startActivity(intent)
}
}
}
userRecyclerView.adapter = adapter
}
}
I want to update the data when i click on the holder.
Only update the data of the user whose recycler view I clicked.
Firestore Database Image

how can i get a function to finish retrieving data before the rest of my code is executed [duplicate]

This question already has answers here:
getContactsFromFirebase() method return an empty list
(1 answer)
Setting Singleton property value in Firebase Listener
(3 answers)
Closed 2 years ago.
Im trying to get a method that gets data from firebase to finish executing before the rest of my code is run so that it can add the data to a spinner.
at the moment i'm using a call back but it seems that this only prints the data when all the data is fetched
this is my code and i've added some println()s to see the order of how the code is running:
class FollowingFragment: Fragment() {
private val database = FirebaseDatabase.getInstance()
private val mAuth = FirebaseAuth.getInstance()
private var currentUid = mAuth.currentUser?.uid
val sharedPreferences = activity?.getSharedPreferences("savedCategories", Context.MODE_PRIVATE)
val categories: ArrayList<String> = ArrayList()
val test: ArrayList<String> = ArrayList()
lateinit var spinner : Spinner
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
) =
inflater.inflate(R.layout.fragment_following, container, false)!!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
println("Order 1")
fetchUserFollowings(object:FollowingCallback {
override fun onCallback(value: ArrayList<String>) {
println("Order 2")
test.addAll(categories)
println(test)
println("Order 3")
}
})
println("Order 4")
//Bind views
val list = view.findViewById<RecyclerView>(R.id.followingRecyclerView)
//create layout manager
val layoutManager = LinearLayoutManager(context)
list.layoutManager = layoutManager
spinner = view.findViewById(R.id.sp_option) as Spinner
//Set Dropdown list
println("Order 5")
val adapter = ArrayAdapter<String>(view.context, android.R.layout.simple_list_item_1, test)
println("Order 6")
spinner.adapter = adapter
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
//fetchNews(categories[position])
//Log.e("CATEGORY", "${categories[position]}")
}
override fun onNothingSelected(parent: AdapterView<*>?) {
TODO("Not yet implemented")
}
}
}
private fun fetchNews(category: String) {
val c = Calendar.getInstance()
val year = c.get(Calendar.YEAR)
val month = c.get(Calendar.MONTH)
val day = c.get(Calendar.DAY_OF_MONTH)
val date = "$year-${month+1}-$day"
val dateBefore = "$year-${month+1}-${day-1}"
val url = "http://newsapi.org/v2/everything?q=$category&from=$dateBefore&to=$date&sortBy=popularity&apiKey=${Constants.API_KEY}"
val request = Request.Builder().url(url).build()
val client = OkHttpClient()
client.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
val body = response?.body?.string()
val gson = GsonBuilder().create()
val homeFeed = gson.fromJson(body, HomeFeed::class.java)
activity?.runOnUiThread {
followingRecyclerView.adapter = MyAdapter(homeFeed)
}
}
override fun onFailure(call: Call, e: IOException) {
println("Failed to execute request")
}
})
}
interface FollowingCallback {
fun onCallback(value:ArrayList<String>)
}
private fun fetchUserFollowings(myCallback:FollowingCallback) {
val myRef = database.getReference("User-following").child(currentUid!!)
myRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
categories.clear()
for (childSnapshot in dataSnapshot.children) {
if (childSnapshot.hasChildren()) {
var test = childSnapshot.child("category").value
categories.add(test as String)
}
}
myCallback.onCallback(categories)
}
override fun onCancelled(error: DatabaseError) {
Log.e("Database Error", error.toString())
}
})
}
}
this is how it prints out:
Order 1
Order 4
Order 5
Order 6
Order 2
["List of from firebase"]
Order 3
but i need the "list from firebase" before order 4,5,6 are run as i need to use this list to populate the spinner
how can i fix this?

Receive data from Adapter to DetailsActivity?

I want to know how I can receive the data from adapter (recyclerview) to DetailsActivity. I tried many times but the images from recyclerview doesn't show in DetailsActivity.
this is my code.
ImageAdapter
class ImageAdapter (private var items:List<Item>, private val context:Context):
RecyclerView.Adapter<ImageAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):ViewHolder {
return ViewHolder(
LayoutInflater.from(context).inflate(R.layout.item, parent, false)
)
}
override fun getItemCount(): Int {
return items.size
}
override fun onBindViewHolder(holder: ImageAdapter.ViewHolder, position: Int) {
val item = items[position]
Picasso.get().load(item.imageUrl).into(holder.imageView)
holder.imageView.setOnClickListener {
val intent = Intent(context, DetailsActivity::class.java)
intent.putExtra("iImages", item.imageUrl)
context.startActivity(intent)
}
}
class ViewHolder(view:View):RecyclerView.ViewHolder(view) {
val imageView : ImageView = view.findViewById(R.id.imageView)
}
}
DetailsActivity
class DetailsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_details)
val aImageView = intent.getIntExtra("iImages", 0)
details_image.setImageResource(aImageView)
}
}
RecyclerActivity
class RecyclerActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recycler)
val storage = FirebaseStorage.getInstance()
val storageRef = storage.reference.child("wallpapers")
val imageList : ArrayList<Item> = ArrayList()
//progressBar.visibility = View.VISIBLE
val listAllTask : Task<ListResult> = storageRef.listAll()
listAllTask.addOnCompleteListener { result ->
val items: List<StorageReference> = result.result!!.items
//add cycle for add image url to list
items.forEachIndexed { index,item ->
item.downloadUrl.addOnSuccessListener {
Log.d("item", "$it")
imageList.add(Item(it.toString()))
}.addOnCompleteListener {
recyclerview.adapter = ImageAdapter(imageList, this)
recyclerview.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
//progressBar.visibility = View.GONE
}
}
}
}
}
Item
data class Item(
var imageUrl: String
)
The problem is this line:
details_image.setImageResource(aImageView)
You are setting a resource int but what you pass seems to be a url, so instead load the "iImages" value with Picasso for that view
Edit: Replace this:
val aImageView = intent.getIntExtra("iImages", 0)
details_image.setImageResource(aImageView)
with this
val retrievedImageUrl = intent.getIntExtra("iImages", 0)
Picasso.get().load(retrievedImageUrl).into(details_image)
The Answer
val imageView : ImageView = findViewById(R.id.details_image)
Glide.with(this).load(intent.getStringExtra("iImages")).into(imageView)

How to add ViewModel to a project which uses ViewPager and Tablayout?

Hello i am new in Android Development so maybe this question can be weird for you.
I have a class named IdentityCardInfo which has variables. And I am getting this variables in InfoFragment.
From InfoFragment I want to show these variables in a ResultsFragment wihch has 3 tabs with tablayout.
I want to use ViewModel to pass data to tablayouts but I don't know how to use I've searched but get stuck.
Here is code for IdentityCardInfo class:
class IdentityCardInfo {
companion object AppConstant{
const val serieNo ="67G74444"
const val validDate = "01/01/2022"
const val dateOfBirth = "10/08/1998"
const val fullName = "Muhittin KAYA"
const val identityNo: Long = 11111111111
const val gender = "MALE"
const val nationality = "TUR"
}
}
Here is code for InfoFragment:
class InfoFragment : BaseFragment() {
lateinit var navController: NavController
companion object {
private const val TAG = "Info Fragment"
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_info, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
navController = Navigation.findNavController(view)
button_info_idcard.setOnClickListener {
//start OcrActivity
val intent = Intent(activity, OcrActivity::class.java)
startActivityForResult(intent, 101)
}
imagebutton_info_settings.setOnClickListener {
navController.navigate(R.id.action_infoFragment_to_settingsFragment)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Log.i("Muhittin", "onActivityResult()")
if (requestCode == 101) {
val message = data?.getStringExtra("TEST_TEXT")
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
val serieNo = IdentityCardInfo.serieNo
val validDate = IdentityCardInfo.validDate
val dateOfBirth = IdentityCardInfo.dateOfBirth
val fullname = IdentityCardInfo.fullName
val gender = IdentityCardInfo.gender
val identityNo = IdentityCardInfo.identityNo
val nationality = IdentityCardInfo.nationality
val bundle = bundleOf(
"TEST_TEXT" to message,
"SERIE_NO" to serieNo,
"VALID_DATE" to validDate,
"DOB" to dateOfBirth,
"FULL_NAME" to fullname,
"GENDER" to gender,
"IDENTITY_NO" to identityNo,
"NATIONALITY" to nationality
)
navController.navigate(
R.id.action_infoFragment_to_detailFragment,
bundle
)
}
}
}
This is for ResultsFragment: (I don't add tablayout code and viewpager code)
class ResultsFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
retainInstance = true
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_results, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val tabLayout: TabLayout = requireView().findViewById(R.id.tabLayout_results)
tabLayout.tabGravity = TabLayout.GRAVITY_FILL
val tabTitles = arrayOf(
resources.getString(R.string.result_tab1_name),
resources.getString(R.string.result_tab2_name),
resources.getString(R.string.result_tab3_name)
)
val viewPager: ViewPager = requireView().findViewById(R.id.viewpager_results)
viewPager.offscreenPageLimit = 3
val adapter = PagerAdapter(fragmentManager, tabTitles)
viewPager.adapter = adapter
tabLayout.setupWithViewPager(viewPager)
}
}
If you want to use ViewModels to pass data between fragments in the same activity, here's the Android documentation about it. It lets the fragments access a shared object without needing to know about each other, or communicate through the activity (with a bunch of code just to enable that communication)
You'd basically do something like this:
// create a ViewModel that holds the data you want to share
class IdentityCardViewModel : ViewModel() {
val identityInfo = MutableLiveData<IdentityCardInfo>()
fun setInfo(info: IdentityCardInfo) {
identityInfo.value = info
}
}
Then each fragment would grab a copy of the same ViewModel instance by doing:
// Get a reference to the IdentityCardViewModel created and held by the activity
private val model: IdentityCardViewModel by activityViewModels()
and then InfoFragment can set the data with model.setInfo(yourIdentityCardInfo). ResultsFragmentcan observe this data and do something whenever it sees a new value:
model.identityInfo.observe(viewLifecycleOwner, Observer<IdentityCardInfo> { info ->
// Do whatever you need with the updated info, like displaying it
})
#muhittin kaya Refer below code to resolve your issue
InfoFragment
class InfoFragment : BaseFragment() {
lateinit var navController: NavController
// Initialize your variable
lateinit var infoFragmentInterface: InfoFragmentDataInterface
// If you get initialization exception then uncomment below line and comment above line
//private var infoFragmentInterface: InfoFragmentDataInterface? = null
companion object {
private const val TAG = "Info Fragment"
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_info, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
navController = Navigation.findNavController(view)
button_info_idcard.setOnClickListener {
//start OcrActivity
val intent = Intent(activity, OcrActivity::class.java)
startActivityForResult(intent, 101)
}
imagebutton_info_settings.setOnClickListener {
navController.navigate(R.id.action_infoFragment_to_settingsFragment)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Log.i("Muhittin", "onActivityResult()")
if (requestCode == 101) {
val message = data?.getStringExtra("TEST_TEXT")
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
val serieNo = IdentityCardInfo.serieNo
val validDate = IdentityCardInfo.validDate
val dateOfBirth = IdentityCardInfo.dateOfBirth
val fullname = IdentityCardInfo.fullName
val gender = IdentityCardInfo.gender
val identityNo = IdentityCardInfo.identityNo
val nationality = IdentityCardInfo.nationality
val bundle = bundleOf(
"TEST_TEXT" to message,
"SERIE_NO" to serieNo,
"VALID_DATE" to validDate,
"DOB" to dateOfBirth,
"FULL_NAME" to fullname,
"GENDER" to gender,
"IDENTITY_NO" to identityNo,
"NATIONALITY" to nationality
)
//Add This line for passing your data
//You can also pass string data here
infoFragmentInterface.getInfoFragmentData(bundle)
navController.navigate(
R.id.action_infoFragment_to_detailFragment,
bundle
)
}
}
}
// Create this interface to pass your data
interface InfoFragmentDataInterface {
fun getInfoFragmentData(bundle: Any)
}
ResultsFragment
class ResultsFragment : Fragment(), InfoFragmentDataInterface {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
retainInstance = true
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_results, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val tabLayout: TabLayout = requireView().findViewById(R.id.tabLayout_results)
tabLayout.tabGravity = TabLayout.GRAVITY_FILL
val tabTitles = arrayOf(
resources.getString(R.string.result_tab1_name),
resources.getString(R.string.result_tab2_name),
resources.getString(R.string.result_tab3_name)
)
val viewPager: ViewPager = requireView().findViewById(R.id.viewpager_results)
viewPager.offscreenPageLimit = 3
val adapter = PagerAdapter(fragmentManager, tabTitles)
viewPager.adapter = adapter
tabLayout.setupWithViewPager(viewPager)
}
override fun getInfoFragmentData(bundle: Any) {
// You'll get your Bundle data here.
}
}