I am making an app where each user can add to his Todo List, I have a problem with folder paths.
this is the part of reading data code was adding "child(auth.currentUser?.uid!!)" makes everything crash. without it though it works but shows information of all users with dictionary form.
db.child(auth.currentUser?.uid!!).addValueEventListener(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
println("The read failed")
}
override fun onDataChange(p0: DataSnapshot) {
for (i in p0.children) {
val notToDo: String = i.value.toString()
notToDos.add(notToDo)
}
listView = findViewById(R.id.listview)
listView.adapter = ArrayAdapter<String>(
this#ToDoActivity,
R.layout.listview,
notToDos
)
}
})
This is the whole code, but neither the adding part works
package ge.msda.firebaseauth
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.ListView
import android.widget.Toast
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import kotlinx.android.synthetic.main.activity_to_do.*
class ToDoActivity : AppCompatActivity() {
private lateinit var db: DatabaseReference
lateinit var listView: ListView
private lateinit var auth: FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_to_do)
db = FirebaseDatabase.getInstance().getReference("UserInfo")
val notToDos = arrayListOf<String>()
TodoSubmit.setOnClickListener {
val text = TodoText.text.toString()
db.child(auth.currentUser?.uid!!).child("ToDos").push().setValue(text).addOnCompleteListener {
if(it.isSuccessful()){
Toast.makeText(this, "Success", Toast.LENGTH_LONG).show()
}
else {
Toast.makeText(this, it.exception.toString(), Toast.LENGTH_LONG).show() }
}
TodoText.setText("")
notToDos.clear()
}
db.child(auth.currentUser?.uid!!).addValueEventListener(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
println("The read failed")
}
override fun onDataChange(p0: DataSnapshot) {
for (i in p0.children) {
val notToDo: String = i.value.toString()
notToDos.add(notToDo)
}
listView = findViewById(R.id.listview)
listView.adapter = ArrayAdapter<String>(
this#ToDoActivity,
R.layout.listview,
notToDos
)
}
})
}
}
error tracktrace
E/AndroidRuntime: FATAL EXCEPTION: main
Process: ge.msda.firebaseauth, PID: 11939
java.lang.RuntimeException: Unable to start activity ComponentInfo{ge.msda.firebaseauth/ge.msda.firebaseauth.ToDoActivity}: kotlin.UninitializedPropertyAccessException: lateinit property auth has not been initialized
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property auth has not been initialized
at ge.msda.firebaseauth.ToDoActivity.onCreate(ToDoActivity.kt:41)
at android.app.Activity.performCreate(Activity.java:7802)
at android.app.Activity.performCreate(Activity.java:7791)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
This is the way the database looks like and I want to add a new folder in each user named "ToDos" where I can add other items.
You are getting that error because you forgot to initialize your auth object. To solve this, simply add the following line of code:
auth = FirebaseAuth.getInstance()
Right after the following line of code:
db = FirebaseDatabase.getInstance().getReference("UserInfo")
Related
I have a BaseFragment class that is extended by all fragments in my app. And i have a HomeActivity class is a starting activity and also has some generic functionality in it.
Here is my HomeActivity code:
class HomeActivity : HomeActivityContract.View {
private val presenter: HomeActivityContract.Presenter by inject {
parametersOf(Schedulers.computation())
}
override val selectedWatchList: WatchlistItem
get() = homeActivityBinding.watchlistSpinner.selectedWatchList
override val watchlistItems: MutableList<WatchlistItem>
get() = homeActivityBinding.watchlistSpinner.watchlistItems
val bag = CompositeDisposable()
lateinit var homeActivityBinding: ActivityHomeBinding
override
fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (presenter.hasAccount) {
homeActivityBinding = ActivityHomeBinding.inflate(layoutInflater)
setContentView(homeActivityBinding.root)
Observables.combineLatest(
realtimeDatabaseService.enableMaintenancePageForPhone,
realtimeDatabaseService.maintenanceDate
) { isEnabled, _mMsg ->
if (isEnabled) {
homeActivityBinding.homeMaintenanceView.root.visibility = View.VISIBLE
homeActivityBinding.homeParentView.visibility = View.GONE
homeActivityBinding.homeMaintenanceView.maintenanceTV.text = getString(R.string.maintenance_msg, _mMsg)
} else {
homeActivityBinding.homeMaintenanceView.root.visibility = View.GONE
homeActivityBinding.homeParentView.visibility = View.VISIBLE
presenter.attachView(this)
presenter.dataProvider.getAccountUpdate()
.subscribeBy(onError = { it.printStackTrace() }, onNext = {
presenter.sendDeviceIdForCurrentAccount(isNotificationsEnabledInSettings)
}).disposeBy(lifecycle.disposers.onDestroy)
setSupportActionBar(homeActivityBinding.homeToolbar)
presenter.start()
}
}
.subscribe()
.disposeBy(lifecycle.disposers.onDestroy)
} else {
val intent = Intent(this, LoginActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
}
startActivity(intent)
finish()
}
}
fun hideNavigationMenu() {
homeActivityBinding.homeNavigationView.visibility = View.GONE /// This is where it says that homeActivityBinding is uninitialised.
}
BaseFragment code:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (isAdded)
parentFragmentManager.let { fragmentManager ->
takeIf { fragmentManager.backStackEntryCount >= 1 }?.let {
(activity as? HomeActivity)?.hideNavigationMenu()
}
}
}
So BaseFragment is calling hideNavigationMenu in HomeActivity.
Here is the crash report:
Caused by kotlin.UninitializedPropertyAccessException: lateinit property homeActivityBinding has not been initialized
at com.app.android.traderpro.etx.activities.homeActivity.HomeActivity.G5(HomeActivity.kt:7)
at com.app.android.traderpro.etx.activities.homeActivity.HomeActivity.hideNavigationMenu(HomeActivity.kt:404)
at com.app.android.traderpro.etx.fragments.BaseFragment.hideNavigationMenu(BaseFragment.kt:138)
at com.app.android.traderpro.etx.fragments.BaseFragment.onCreate(BaseFragment.kt:153)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:3090)
at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:475)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:257)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1424)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2968)
at androidx.fragment.app.FragmentManager.dispatchCreate(FragmentManager.java:2875)
at androidx.fragment.app.FragmentController.dispatchCreate(FragmentController.java:252)
at androidx.fragment.app.FragmentActivity.onCreate(FragmentActivity.java:220)
at com.app.android.traderpro.etx.activities.BaseActivity.onCreate(BaseActivity.kt:61)
at com.app.android.traderpro.etx.activities.homeActivity.HomeActivity.onCreate(HomeActivity.kt:134)
at android.app.Activity.performCreate(Activity.java:8207)
at android.app.Activity.performCreate(Activity.java:8191)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3819)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4022)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2336)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8653)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
The first thing is I cannot replicate this crash and there are around 200 crashes reported in Firebase Crashlytics.
And
HomeActivity is the first activity that launches all other fragments. This crash is not happening as soon as this activity is started, it is happening after some time. So I don't understand how homeActivityBinding can be uninitialized.
I'd appreciate it if anyone can tell me how a lateinit property that is initialised can be uninitialized again
Fragment.onCreate() is too early to be trying to access members of the Activity, even though it is already attached. From the onCreate() documentation:
Note that this can be called while the fragment's activity is still in the process of being created. As such, you can not rely on things like the activity's content view hierarchy being initialized at this point.
You should move your code from onCreate to onViewCreated.
I am trying to fetch data from Firestore. But the error occurs:
java.lang.RuntimeException: Could not deserialize object. Can't convert object of type java.lang.String to type com.example.quiz.models.Question (found in field 'questions.title')
The error is found in setUpFirestore() and because of the line: Log.d("DATA", value.toObjects(Quiz::class.java).toString()) {as per logcat error}
My MainActivity:
package com.example.quiz.activities
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.recyclerview.widget.GridLayoutManager
import com.example.quiz.R
import com.example.quiz.adapters.QuizAdapter
import com.example.quiz.databinding.ActivityMainBinding
import com.example.quiz.models.Quiz
import com.google.android.material.datepicker.MaterialDatePicker
import com.google.firebase.firestore.DocumentSnapshot
import com.google.firebase.firestore.FirebaseFirestore
import java.text.SimpleDateFormat
import java.util.*
class MainActivity() : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
lateinit var actionBarDrawerToggle: ActionBarDrawerToggle
lateinit var adapter: QuizAdapter
private var quizList = mutableListOf<Quiz>()
lateinit var firestore : FirebaseFirestore
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setUpViews()
}
fun setUpViews(){
setUpFirestore()
setUpDrawerLayout()
setUpRecyclerView()
setUpDatePicker()
}
private fun setUpDatePicker() {
val btnDatePicker = binding.btnDatePicker
btnDatePicker.setOnClickListener{
val datePicker = MaterialDatePicker.Builder.datePicker().build()
datePicker.show(supportFragmentManager,"DatePicker")
datePicker.addOnPositiveButtonClickListener {
Log.d("DATEPICKER",datePicker.headerText)
val dateFormatter = SimpleDateFormat("dd-mm-yyyy")
val date = dateFormatter.format(Date(it))
val intent = Intent(this,QuestionActivity::class.java)
intent.putExtra("DATE",date)
startActivity(intent)
}
datePicker.addOnNegativeButtonClickListener {
Log.d("DATEPICKER",datePicker.headerText)
}
datePicker.addOnCancelListener {
Log.d("DATEPICKER","Date Picker was cancelled")
}
}
}
private fun setUpFirestore() {
firestore = FirebaseFirestore.getInstance()
val collectionReference = firestore.collection("quizzes")
collectionReference.addSnapshotListener{ value,error ->
if(value == null || error != null){
Toast.makeText(this,"Error fetching data",Toast.LENGTH_SHORT).show()
return#addSnapshotListener
}
Log.d("DATA", value.toObjects(Quiz::class.java).toString())
quizList.clear()
quizList.addAll(value.toObjects(Quiz::class.java))
adapter.notifyDataSetChanged()
}
}
private fun setUpRecyclerView(){
val quizRecyclerView = binding.quizRecyclerView
adapter = QuizAdapter(this,quizList)
quizRecyclerView.layoutManager = GridLayoutManager(this,2)
quizRecyclerView.adapter = adapter
}
fun setUpDrawerLayout(){
val appBar = binding.appBar
val mainDrawer = binding.mainDrawer
val navigationView = binding.navigationView
setSupportActionBar(appBar)
actionBarDrawerToggle = ActionBarDrawerToggle(this,mainDrawer,
R.string.app_name,
R.string.app_name
)
actionBarDrawerToggle.syncState()
navigationView.setNavigationItemSelectedListener {
val intent = Intent(this,ProfileActivity::class.java)
startActivity(intent)
mainDrawer.closeDrawers()
true
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (actionBarDrawerToggle.onOptionsItemSelected(item)){
return true
}
return super.onOptionsItemSelected(item)
}
}
my Question model is mentioned below:
package com.example.quiz.models
data class Question(
var description: String = "",
var option1: String = "",
var option2: String = "",
var option3: String = "",
var option4: String = "",
var answer: String = "",
var userAnswer:String=""
)
my quiz model is -
package com.example.quiz.models
import com.google.firebase.auth.FirebaseAuth
data class Quiz(
var id: String = "",
var title: String = "",
var questions: MutableMap<String, Question> = mutableMapOf()
)
database image:
database image
logcat error is -
2022-04-24 17:19:04.678 12341-12341/com.example.quiz E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.quiz, PID: 12341
java.lang.RuntimeException: Could not deserialize object. Can't convert object of type java.lang.String to type com.example.quiz.models.Question (found in field 'questions.title')
at com.google.firebase.firestore.util.CustomClassMapper.deserializeError(CustomClassMapper.java:568)
at com.google.firebase.firestore.util.CustomClassMapper.convertBean(CustomClassMapper.java:549)
at com.google.firebase.firestore.util.CustomClassMapper.deserializeToClass(CustomClassMapper.java:258)
at com.google.firebase.firestore.util.CustomClassMapper.deserializeToType(CustomClassMapper.java:194)
at com.google.firebase.firestore.util.CustomClassMapper.deserializeToParameterizedType(CustomClassMapper.java:296)
at com.google.firebase.firestore.util.CustomClassMapper.deserializeToType(CustomClassMapper.java:192)
at com.google.firebase.firestore.util.CustomClassMapper.access$300(CustomClassMapper.java:57)
at com.google.firebase.firestore.util.CustomClassMapper$BeanMapper.deserialize(CustomClassMapper.java:775)
at com.google.firebase.firestore.util.CustomClassMapper$BeanMapper.deserialize(CustomClassMapper.java:746)
at com.google.firebase.firestore.util.CustomClassMapper.convertBean(CustomClassMapper.java:547)
at com.google.firebase.firestore.util.CustomClassMapper.deserializeToClass(CustomClassMapper.java:258)
at com.google.firebase.firestore.util.CustomClassMapper.convertToCustomClass(CustomClassMapper.java:103)
at com.google.firebase.firestore.DocumentSnapshot.toObject(DocumentSnapshot.java:183)
at com.google.firebase.firestore.QueryDocumentSnapshot.toObject(QueryDocumentSnapshot.java:116)
at com.google.firebase.firestore.QuerySnapshot.toObjects(QuerySnapshot.java:184)
at com.google.firebase.firestore.QuerySnapshot.toObjects(QuerySnapshot.java:166)
at com.example.quiz.activities.MainActivity.setUpFirestore$lambda-4(MainActivity.kt:95)
at com.example.quiz.activities.MainActivity.$r8$lambda$ALF8Ugv5XcVyBlrGHEr70w5PaxM(Unknown Source:0)
at com.example.quiz.activities.MainActivity$$ExternalSyntheticLambda5.onEvent(Unknown Source:4)
at com.google.firebase.firestore.Query.lambda$addSnapshotListenerInternal$2$com-google-firebase-firestore-Query(Query.java:1205)
at com.google.firebase.firestore.Query$$ExternalSyntheticLambda2.onEvent(Unknown Source:6)
at com.google.firebase.firestore.core.AsyncEventListener.lambda$onEvent$0$com-google-firebase-firestore-core-AsyncEventListener(AsyncEventListener.java:42)
at com.google.firebase.firestore.core.AsyncEventListener$$ExternalSyntheticLambda0.run(Unknown Source:6)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
You're getting the following error:
Could not deserialize object.Can't convert object of type java.lang.String to type com.example.quiz.models.Question (found in field 'questions.title')
Because when using this line of code:
Log.d("DATA", value.toObjects(Quiz::class.java).toString())
It means that you're trying to convert each document into an object of type Quiz, which is actually not possible. Why? Because each document should contain a questions array which should be composed of only Question objects. But this is not happening since that array contains also a String called title. As I see in your Quiz class, the title field should be a field directly within the document and should not be present inside the array. To solve this, you have to remove the title from the array and add it as a field inside the document.
I am making a news app in android but I am getting error when I call a API(http) from my app. I don't know why the error is coming I implemented all the class, memebers, function.
Pleas help me.
Here is the error description
2021-01-21 09:21:25.896 18052-18052/com.arne.khabriapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.arne.khabriapp, PID: 18052
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.arne.khabriapp/com.arne.khabriapp.MainActivity}: kotlin.UninitializedPropertyAccessException: lateinit property mAdapter has not been initialized
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property mAdapter has not been initialized
at com.arne.khabriapp.MainActivity.onCreate(MainActivity.kt:25)
at android.app.Activity.performCreate(Activity.java:7802)
at android.app.Activity.performCreate(Activity.java:7791)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
2021-01-21 09:21:25.912 18052-18090/com.arne.khabriapp D/NetworkSecurityConfig:
No Network Security Config specified, using platform default
Here is my MainActivity.kt
package com.arne.khabriapp
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.toolbox.JsonObjectRequest
class MainActivity : AppCompatActivity(), NewsItemClicked {
private lateinit var mAdapter: NewsListAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView = findViewById<RecyclerView>(R.id.rView)
recyclerView.layoutManager = LinearLayoutManager(this)
// recyclerView.layoutManager = GridLayoutManager(this,12)
// recyclerView.layoutManager = StaggeredGridLayoutManager(15,12)
fetchData()
recyclerView.adapter = mAdapter
}
private fun fetchData() {
// val list = ArrayList<String>()
// for(i in 0 until 100){
// list.add("item $i")
// }
// return list
val url = "https://newsapi.org/v2/top-headlines?country=in&apiKey=9bb7bf6152d147ad8ba14cd0e7452f2f"
val jsonObjectRequest = JsonObjectRequest(
Request.Method.GET,
url,
null,
{
val newsJsonArray = it.getJSONArray("articles")
val newsArray = ArrayList<NewsClass>()
for (i in 0 until newsJsonArray.length()){
val newsJsonObject = newsJsonArray.getJSONObject(i)
val news =NewsClass(
newsJsonObject.getString("title"),
newsJsonObject.getString("author"),
newsJsonObject.getString("url"),
newsJsonObject.getString("urlToImage")
)
newsArray.add(news)
}
mAdapter.updateNews(newsArray)
},
{
}
)
MySingletonClass.getInstance(this).addRequestQueue(jsonObjectRequest)
}
override fun OnItemClick(item: NewsClass) {
}
}
Here is my NewsAdapter.kt
package com.arne.khabriapp
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
//class Name: extendItForRecyclerView.Adapter<ViewHolderClass>
class NewsListAdapter( private val listener: NewsItemClicked): RecyclerView.Adapter<NewsViewHolder>()
{
private val items: ArrayList<NewsClass> = ArrayList()
// call me when each time one viewholder is created
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewsViewHolder {
//Layout Inflater - Converts XML into View
val view = LayoutInflater.from(parent.context).inflate(R.layout.itemnews, parent, false)
val viewHolder = NewsViewHolder(view)
view.setOnClickListener{
//this is a call back to main activity so the main activity knows that any item is clicked and then the mainn activity behave according to this.
listener.OnItemClick(items[viewHolder.adapterPosition])
}
return viewHolder
}
// I will bind the item with viewholder
override fun onBindViewHolder(holder: NewsViewHolder, position: Int) {
val currentItem = items[position]
holder.titleView.text = currentItem.title
}
// call me only one time i will give you how many item will be here in list
override fun getItemCount(): Int {
return items.size
}
fun updateNews(updatedNews: ArrayList<NewsClass>){
items.clear()
items.addAll(updatedNews)
notifyDataSetChanged()
}
}
class NewsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val titleView: TextView = itemView.findViewById(R.id.title)
}
interface NewsItemClicked{
fun OnItemClick(item: NewsClass)
}
Please Give Some Answer
Thank you very much in advanced
You can do it like this.
private lateinit var mAdapter: NewsListAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView = findViewById<RecyclerView>(R.id.rView)
recyclerView.layoutManager = LinearLayoutManager(this)
// recyclerView.layoutManager = GridLayoutManager(this,12)
// recyclerView.layoutManager = StaggeredGridLayoutManager(15,12)
mAdapter = NewsListAdapter(this)//should be inited before use.
fetchData()
recyclerView.adapter = mAdapter
}
Or you can do it this way
private val mAdapter: NewsListAdapter by lazy{
NewsListAdapter(this)
}
Mostly the exact code works fine in another type of code structure yet doesn't work here although the structure of DB is perfectly aligned like it should be
Favourites:
+-UID:
+---id: restaurant_id
+---name: "name"
+---rating: rating
+image_url:"image_url"
FavrouiteFragment code:
package com.reazon.foodrunner.fragment
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import com.reazon.foodrunner.R
import com.reazon.foodrunner.adapter.FavouriteRecyclerAdapter
import com.reazon.foodrunner.model.Favourite
class FavouriteFragment : Fragment() {
private var recyclerAdapter: FavouriteRecyclerAdapter? = null
private var recyclerFavourite: RecyclerView? = null
internal var favouritesList: MutableList<Favourite> = ArrayList()
private var layoutManager: RecyclerView.LayoutManager? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_favourite, container, false)
recyclerFavourite = view.findViewById(R.id.recyclerFavouriteAll)
layoutManager = LinearLayoutManager(activity)
recyclerFavourite!!.layoutManager = layoutManager
retrieveAllFavouriteRestaurants()
return view
}
private fun retrieveAllFavouriteRestaurants() {
favouritesList.clear()
val firebaseUser = FirebaseAuth.getInstance().currentUser!!.uid
val mDatabaseReference = FirebaseDatabase.getInstance().reference.child("Favourites/$firebaseUser")//.child()
mDatabaseReference.addValueEventListener(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
Log.d("ERROR ", "" + error.message)
}
override fun onDataChange(p0: DataSnapshot) {
for (snapshot in p0.children) {
val favorite = snapshot.getValue(Favourite::class.java)
recyclerAdapter = FavouriteRecyclerAdapter(context!! , favouritesList)
recyclerFavourite?.adapter = recyclerAdapter
if (favorite != null) {
favouritesList.add(favorite)
}
}
}
})
}
}
Model Class:
package com.reazon.foodrunner.model
data class Favourite (
var id:Int? = null,
var name:String? = null,
var rating:Double? = null,
var cost_for_one:Int? = null,
var image_url:String? = null
)
LogCat Window Error identification:
2020-09-05 09:22:07.520 5208-5208/com.reazon.foodrunner E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.reazon.foodrunner, PID: 5208
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.reazon.foodrunner.model.Favourite
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertBean(CustomClassMapper.java:435)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(CustomClassMapper.java:231)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(CustomClassMapper.java:79)
at com.google.firebase.database.DataSnapshot.getValue(DataSnapshot.java:203)
at com.reazon.foodrunner.fragment.FavouriteFragment$retrieveAllFavouriteRestaurants$1.onDataChange(FavouriteFragment.kt:50)
at com.google.firebase.database.core.ValueEventRegistration.fireEvent(ValueEventRegistration.java:75)
at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(EventRaiser.java:55)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Since you have the following db:
Favorites
Uid
id : id
name : name
Therefore you have to use the following code:
override fun onDataChange(p0: DataSnapshot) {
val favorite = p0.getValue(Favourite::class.java)
Remove the for loop because when you iterate you will get the data as String instead of your custom object.
I'm in front of this error since yesterday. I implement a chat app whit Kotlin and I have an issue when I run my code. I got a Firebase DatabaseException:
Can't convert object of type java.lang.String to type com.example.noalumni.model.Users
Doesn't anybody know how to fix it? Here is my code.
NewMessageActivity.kt
package com.example.noalumni.activities
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.example.noalumni.R
import com.example.noalumni.fragments.ChatFragment
import com.example.noalumni.model.Users
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.ValueEventListener
import com.google.firebase.firestore.auth.User
import com.squareup.picasso.Picasso
import com.xwray.groupie.GroupAdapter
import com.xwray.groupie.GroupieViewHolder
import com.xwray.groupie.Item
import kotlinx.android.synthetic.main.activity_new_message.*
import kotlinx.android.synthetic.main.user_row_new_message.view.*
class NewMessageActivity : AppCompatActivity() {
companion object {
val USER_KEY = "USER_KEY"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_new_message)
supportActionBar?.title = "Selectionner un contact"
fetchUsers()
}
private fun fetchUsers() {
val ref = FirebaseDatabase.getInstance().getReference("/users")
ref.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
val adapter = GroupAdapter<GroupieViewHolder>()
p0.children.forEach {
Log.d("NewMessage", it.toString())
val user : Users = it.getValue(Users::class.java) as Users
adapter.add(UserItem(user))
}
adapter.setOnItemClickListener { item, view ->
val userItem = item as UserItem
val intent = Intent(view.context, ChatFragment::class.java)
//intent.putExtra(USER_KEY, userItem.user.username)
intent.putExtra(USER_KEY, userItem.user)
startActivity(intent)
finish()
}
recyclerview_newmessage.adapter = adapter
}
override fun onCancelled(p0: DatabaseError) {
}
})
}
}
class UserItem(val user: Users) : Item<GroupieViewHolder>() {
override fun bind(viewHolder: GroupieViewHolder, position: Int) {
viewHolder.itemView.username_textview_newmessage.text = user.username
Picasso.get().load(user.profileImageUrl).into(viewHolder.itemView.imageview_new_message)
}
override fun getLayout(): Int {
return R.layout.user_row_new_message
}
}
My data class
Users
Users.kt
package com.example.noalumni.model
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
#Parcelize
data class Users (val username: String, val email: String, val password: String, val profileImageUrl: String): Parcelable {
constructor() : this("", "", "", "")
}
The logcat output
2020-06-04 11:09:39.649 5093-5093/com.example.test2 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.test2, PID: 5093
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.example.noalumni.model.Users
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertBean(com.google.firebase:firebase-database##19.3.0:435)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(com.google.firebase:firebase-database##19.3.0:231)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(com.google.firebase:firebase-database##19.3.0:79)
at com.google.firebase.database.DataSnapshot.getValue(com.google.firebase:firebase-database##19.3.0:203)
at com.example.noalumni.activities.NewMessageActivity$fetchUsers$1.onDataChange(NewMessageActivity.kt:46)
at com.google.firebase.database.Query$1.onDataChange(com.google.firebase:firebase-database##19.3.0:179)
at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database##19.3.0:75)
at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database##19.3.0:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database##19.3.0:55)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
You are getting the following error:
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.example.noalumni.model.Users
Because you are trying to get all children within the users node as User objects while all objects are actually Strings. To be able to get User objects, you need to make a little change in your database structure, so I can look like this:
Firebase-root
|
--- users
|
--- uid
|
--- email: "badarouyazid98#gmail.com"
|
--- password: "azerty"
|
--- profileImageUrl: ""
|
--- username: "Maria"
See there is an extra uid node under users node? To be able to have such a schema, when you add a User object to the database, use the following lines of code:
val uid = FirebaseAuth.getInstance().currentUser!!.uid
val rootRef = FirebaseDatabase.getInstance().reference
val uidRef = rootRef.child("users").child(uid)
uidRef.setValue(yourUserObject)
Then your actual code will work fine.