Error adding to mutable list (NPE) Kotlin Android - android

---Data Class---
trying to add object to meals MutableList-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
data class YelpRestaurant(
val name: String,
val rating: Double,
val price: String,
#SerializedName("review_count") val numReviews: Int,
#SerializedName("image_url") val imageUrl: String,
val categories: List<YelpCategory>,
val location: YelpLocation,
val meals: MutableList<UserMeals>
)
----EDITED ACTIVITY----
class ThoughtsActivity : AppCompatActivity() {
lateinit var mealName: String
lateinit var mealPrice: String
lateinit var mealThought: String
lateinit var selected_Restaurant : YelpRestaurant
val meals = mutableListOf<UserMeals>()
#Subscribe(sticky = true)
fun getRest(selectedRestaurant : YelpRestaurant) {
selected_Restaurant = selectedRestaurant
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_thoughts)
thoughtBtn.setOnClickListener() {
mealName = m_name.text.toString()
mealPrice = m_price.text.toString()
mealThought = m_thought.text.toString()
var addedMeal = UserMeals(mealName, mealPrice.toDouble(), mealThought)
if (mealName.isNotEmpty()) {
selected_Restaurant.meals.add(addedMeal)
}
}
}
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
}
override fun onStop() {
super.onStop()
EventBus.getDefault().unregister(this)
}
}

You have null pointer exception when accessing selected_Restaurant.meals to prevent NPE change meals to val and instantiate it when you declare it like this in selected_Restaurant:
val meals = mutableListOf<UserMeals>()

Related

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

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

extras.getString() returns null in Kotlin Android

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

Retfrofit on response gets java.lang.NullPointerException [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 1 year ago.
Good day, I'm using Retrofit for the first time and I can't seem to get it to work. working on an app that get crypto currency rates in local currencies, here is the api [link], JSON format
Here are my models for News
data class News(
#field:SerializedName("totalResults")
val totalResults: Int,
#field:SerializedName("articles")
val articles: List<NewsArticle>?=null,
#field:SerializedName("status")
val status: String)
My model calss for NewsArticles:
data class NewsArticle(
#field:SerializedName("urlToImage")
val urlToImage: String? = null,
#field:SerializedName("description")
val description: String? = null,
#field:SerializedName("title")
val title: String? = null,
#field:SerializedName("url")
val url: String? = null,)
My interface:
const val BASE_URL = "https://saurav.tech/NewsAPI/"
interface NewsApiService {
#GET("top-headlines.json")
fun getNews(
#Query("category") category: String,
#Query("country_code") country_code: String
): Call<News>}
object NewsApi{
val newsInstance:NewsApiService
init {
val retrofit=Retrofit.Builder()
.baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create())
.build()
newsInstance=retrofit.create(NewsApiService::class.java)
}
}
My MainActivity class
class MainActivity : AppCompatActivity() {
private lateinit var adapter: NewsAdapter
//var totalResult=1
private var article = mutableListOf<NewsArticle>()
lateinit var refreshLayout: SwipeRefreshLayout
private lateinit var recyclerView: RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerView = findViewById(R.id.recyclerViewNews)
refreshLayout = findViewById(R.id.refreshLayout)
adapter = NewsAdapter(this#MainActivity, article)
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this#MainActivity)
fetchNews()
}
private fun fetchNews() {
val news = NewsApi.newsInstance.getNews("technology", "in")
news.enqueue(object : Callback<News> {
override fun onResponse(call: Call<News>, response: Response<News>) {
val news = response.body()
article.addAll(news!!.articles)
}
override fun onFailure(call: Call<News>, t: Throwable) {
Toast.makeText(applicationContext, t.message, Toast.LENGTH_SHORT).show()
}
})
}
}
My AdapterClass:
class NewsAdapter(val context: Context, val newsArticles: MutableList<NewsArticle>) :
RecyclerView.Adapter<NewsAdapter.NewsViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewsViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.news_items, parent, false)
return NewsViewHolder(view)
}
override fun onBindViewHolder(holder: NewsViewHolder, position: Int) {
val article = newsArticles[position]
holder.title.text = article.title
holder.description.text = article.description
Glide.with(holder.itemView.context).load(article.urlToImage).into(holder.image)
}
override fun getItemCount() = newsArticles.size
class NewsViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val title = view.findViewById<TextView>(R.id.titleText)!!
val description = view.findViewById<TextView>(R.id.descriptionText)!!
val image = view.findViewById<ImageView>(R.id.NewsImage)!!
}
}
When I run the code and check my log I get this error:
java.lang.NullPointerException
at com.ashish.technews.uis.MainActivity$fetchNews$1.onResponse(MainActivity.kt:44)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.lambda$onResponse$0$DefaultCallAdapterFactory$ExecutorCallbackCall$1(DefaultCallAdapterFactory.java:89)
at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCall$1$hVGjmafRi6VitDIrPNdoFizVAdk.run(lambda)
at android.os.Handler.handleCallback(Handler.java:754)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:165)
at android.app.ActivityThread.main(ActivityThread.java:6375)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802)
What's Happening?
Article List in the response is not coming and it is not being handled properly.
Solution
Replace this: article.addAll(news!!.articles)
With this: news?.let { article.addAll(it.articles) }

How to send data From One RecyclerView Item to load another RecyclerView using Nested JSON using Kotlin

I have two activity and each activity has recyclerview, I have nested json.I want when user tap first activity recyclerview then they goes to next activity and show the recyclerview.Better understanding please follow the json link and code.
Json Link
: https://run.mocky.io/v3/8c3f6be2-a53f-47da-838c-72e603af844d
CropData.kt
data class CropData(
#SerializedName("cropImage")
val cropImage: String,
#SerializedName("cropName")
val cropName: String,
#SerializedName("cropTime")
val cropTime: String,
#SerializedName("cropDetails")
val cropDetails: String,
#SerializedName("cropProcess")
val cropProcess: String,
#SerializedName("cropType")
val cropType: String,
#SerializedName("cropFertilizer")
val cropFertilizer: List<CropFertilizer>
)
CropFertilizer.kt
data class CropFertilizer(
#SerializedName("fertilizerName")
val fertilizerName: String,
#SerializedName("fertilizerFirst")
val fertilizerFirst: String,
#SerializedName("fertilizerSecond")
val fertilizerSecond: String,
#SerializedName("fertilizerThird")
val fertilizerThird: String
)
CropActivity.kt
class CropActivity : AppCompatActivity(), CropOnItemClickListener {
private lateinit var viewModel: CropActivityViewModel
private val cropAdapter by lazy { CropAdapter(this) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_crop)
val repository = Repository()
val viewModelFactory = CropActivityViewModelFactory(repository)
viewModel = ViewModelProvider(this, viewModelFactory).get(CropActivityViewModel::class.java)
viewModel.getCropData()
viewModel.cropResponse.observe(this, Observer { response ->
cropAdapter.setData(response)
Log.d("dCrop", response.toString())
})
setUpCrops()
}
private fun setUpCrops() {
crop_recyclerview.layoutManager = LinearLayoutManager(
this,
LinearLayoutManager.VERTICAL, false
)
crop_recyclerview.setHasFixedSize(true)
crop_recyclerview.adapter = cropAdapter
}
override fun onClick(item: CropData, position: Int) {
val intent = Intent(this, CropDetailsActivity::class.java)
intent.putExtra("name", item.cropName)
intent.putExtra("image", item.cropImage)
intent.putExtra("intro", item.cropDetails)
intent.putExtra("process", item.cropProcess)
intent.putExtra("type", item.cropType)
intent.putExtra("time", item.cropTime)
startActivity(intent)
}
}
CropAdapter.kt
class CropAdapter(private val cropOnItemClickListener: CropOnItemClickListener) :
RecyclerView.Adapter<CropAdapter.ViewHolder>() {
private var cropList = emptyList<CropData>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.crop_row,parent,false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemView.crop_name.text = cropList[position].cropName
holder.itemView.crop_details.text = cropList[position].cropDetails
holder.itemView.crop_time.text = cropList[position].cropTime
holder.itemView.setOnClickListener{
cropOnItemClickListener.onClick(cropList[position],position)
}
}
override fun getItemCount(): Int {
return cropList.size
}
fun setData(newList: List<CropData>){
notifyDataSetChanged()
cropList = newList
notifyDataSetChanged()
}
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)
}
CropDetailsActivity.kt
class CropDetailsActivity : AppCompatActivity() {
private lateinit var viewModel: CropDetailsActivityViewModel
private val fertlizerAdapter by lazy { FertilizerAdapter() }
private val cropFertilizerAdapter by lazy { FertilizerAdapter() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_crop_details)
val bundle:Bundle? = intent.extras
crop_details_name.text = bundle!!.getString("name")
val i: String = bundle!!.getString("intro")
crop_details_intro.text = i
Glide.with(this).load(bundle.getString("image")).into(crop_details_image);
val j: String = bundle!!.getString("process")
crop_details_process.text = j
crop_details_time.text = bundle!!.getString("time")
crop_details_type.text = bundle!!.getString("type")
val repository = Repository()
val viewModelFactory = CropDetailsActivityViewModelFactory(repository)
viewModel = ViewModelProvider(this, viewModelFactory).get(CropDetailsActivityViewModel::class.java)
viewModel.getFertilizer()
viewModel.fResponse.observe(this, Observer {
cropFertilizerAdapter.setData(it)
})
crop_details_recyclerview.layoutManager = LinearLayoutManager(
this,
LinearLayoutManager.VERTICAL, false
)
crop_details_recyclerview.setHasFixedSize(true)
crop_details_recyclerview.adapter = cropFertilizerAdapter
}
}
Better understanding see the image
[1]: https://i.stack.imgur.com/BtPqe.jpg
I want to show CropFertilizer list in CropDetailsActivity.How can i do this?

How do I change the viewmodel observable data in android?

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

Categories

Resources